【问题标题】:Dynamically growing array of strings in CC中动态增长的字符串数组
【发布时间】:2021-12-29 18:13:33
【问题描述】:

我想创建一个可变大小的数组来存储最大长度为 40 的字符串。我进行了研究并找到了以下代码,它创建了一个动态整数数组。

typedef struct {
  int *array;
  size_t used;
  size_t size;
} Array;

void initArray(Array *a, size_t initialSize) {
  a->array = malloc(initialSize * sizeof(int));
  a->used = 0;
  a->size = initialSize;
}

void insertArray(Array *a, int element) {
  // a->used is the number of used entries, because a->array[a->used++] updates a->used only *after* the array has been accessed.
  // Therefore a->used can go up to a->size 
  if (a->used == a->size) {
    a->size *= 2;
    a->array = realloc(a->array, a->size * sizeof(int));
  }
  a->array[a->used++] = element;
}

void freeArray(Array *a) {
  free(a->array);
  a->array = NULL;
  a->used = a->size = 0;
} 

我目前正在尝试修改代码,使其能够解决我的问题。到目前为止,我想出了这个

typedef struct {
  
  size_t used;
  size_t size;
  char *array[][40];
} Array;

void initArray(Array *a, size_t initialSize) {
  a->array = malloc(initialSize * sizeof(char));
  a->used = 0;
  a->size = initialSize;
}

void insertArray(Array *a, char element) {
  // a->used is the number of used entries, because a->array[a->used++] updates a->used only *after* the array has been accessed.
  // Therefore a->used can go up to a->size 
  if (a->used == a->size) {
    a->size *= 2;
    a->array = realloc(a->array, a->size * sizeof(char));
  }
  strcpy(a->array[a->used++], element);
} 

终于

Array a;
char srcname[40];
initArray(&a, 100); 
insertArray(&a, srcname); 

这会产生分段错误。 尽管我进行了研究,但我还没有设法制作一个有效的动态字符串数组。 任何指导将不胜感激

【问题讨论】:

  • char *array[][40] 没有声明你认为它做了什么。这段代码不应该编译,更不用说在运行时产生分段错误了。
  • 你可能应该有一个指向字符串的指针数组。代码可能会更简单一些,而且您可以存储任意长度的字符串。

标签: c multidimensional-array dynamic-memory-allocation c-strings function-definition


【解决方案1】:

如果要存储最大长度为 40 个字符的字符串,包括终止符 null,可以使用灵活的数组成员。您不需要特殊函数来初始化数组,字符串加一也会进行初始化(您只需将 NULL 作为参数传递,表明数组尚未初始化)。 该函数按照STEP宏定义中定义的步骤自动改变字符串数组的大小。

typedef struct {
  size_t used;
  size_t size;
  char array[][40];
} Array;

#define STEP    64

Array *addString(Array *arr, const char *str)
{
    size_t newsize;
    if(!arr || arr -> size == arr -> used)
    {
        newsize = arr ? arr -> size + STEP : STEP;
        arr = realloc(arr, sizeof(*arr) + newsize * sizeof(arr -> array[0]));
        arr -> size = newsize;
        arr -> used = newsize == STEP ? 0 : arr -> used;
    }
    if(arr)
    {
        strncpy(arr -> array[arr -> used], str, sizeof(arr -> array[0]));
        arr -> array[arr -> used][sizeof(arr -> array[0]) - 1] = 0;
        arr -> used++;
    } 
    return arr;
}

int main(void)
{
    Array *arr = NULL, *tmp;

    // function wrks same as realloc so you need to assign the temp variable to
    // avoid memory leak in case of error. I will skip it for the simplicity of the example

    for(size_t i = 0; i < 256; i++)
    {
        char str[40];
        sprintf(str,"String no: %zu", i);
        arr = addString(arr, str);
        printf("Array: size: %3zu used: %3zu\n", arr -> size, arr -> used);
    }

    for(size_t i = 0; i < 256; i++)
    {
        printf("Array sting no %zu: `%s`\n", i, arr -> array[i]);
    }
}

https://godbolt.org/z/8E7EbeaW7

【讨论】:

    【解决方案2】:

    结构体中数据成员数组的声明

    typedef struct {
      
      size_t used;
      size_t size;
      char *array[][40];
    } Array;
    

    不正确。

    如果你想声明一个指针那么你需要写

    typedef struct {
      
      size_t used;
      size_t size;
      char ( *array )[40];
    } Array;
    

    函数initArray也不正确。

    void initArray(Array *a, size_t initialSize) {
      a->array = malloc(initialSize * sizeof(char));
      a->used = 0;
      a->size = initialSize;
    }
    

    因为分配了不正确的数组。

    函数可以如下所示

    int initArray( Array *a, size_t initialSize) 
    {
        a->used = 0;
    
        a->array = malloc( initialSize * sizeof( char[40] ) );
        int success = a->array != NULL;
        
        if ( success )
        {  
            a->size = initialSize;
        }
        else
        {
            a->size = 0;
        }
    
        return success;
    }
    

    相应地,函数insertArray(第二个参数的类型不正确,因为你要传递一个字符串而不是一个字符,不是吗?)应该像这样声明和定义

    int insertArray( Array *a, const char *element ) 
    {
        int success = 1;
    
        if ( a->used == a->size ) 
        {
            char ( *tmp )[40] = realloc( a->array, 2 * a->size * sizeof( char[40] ) );
            if ( ( success = tmp != NULL ) )
            {
                a->array = tmp;
                a->size *= 2;
            }
        }
    
        if ( success )
        { 
            strcpy( a->array[a->used++], element );
        }
    
        return success;
    } 
    

    最后是数组srcname

    char srcname[40];
    

    在将数组传递给函数insertArray之前必须包含一个字符串。

    【讨论】:

    • a-&gt;size *= 2; 几步之后就有了巨大的增长。
    • @0___________ 我使用了问题代码中显示的方法。您可以使用任何值来增加分配的数组。
    • 相传,国际象棋是由大维齐尔西萨·本·达希尔发明的,并作为礼物送给了印度国王希勒姆。国王非常高兴,只要听起来合理,他就给他任何他所要求的报酬。大维齐尔要求如下:“在棋盘的第一个方格上放一粒小麦。然后在第二个方格上放两粒,下一个放四粒,然后再放八粒,然后继续,每个连续的格子上的谷物数量加倍,直到到达棋盘上的每一个方格。”
    • 直觉上,希勒姆国王——就像几乎其他人一样——低估了谷物的数量,并嘲笑西萨,因为他要了这么小的礼物。当他有人计算谷物的总数时,他花了一个多星期才得出解决方案。希勒姆国王在得到答案时,无疑变得非常苍白:棋盘所有方格上的谷物总数量将是 18.446.744.073.709.551.615 这是几十年来世界上所有小麦的收成。跨度>
    • 如果我们假设一粒小麦有 5 毫米长,那么当我们将所有谷物一个接一个地放在棋盘上时,我们得到的总距离(以千米为单位)是多少。半人马座阿尔法星是离我们太阳系最近的恒星,距离地球 4.36 光年。麦粒的总长度足以覆盖从地球到这颗恒星的距离。
    猜你喜欢
    • 2015-06-08
    • 2015-02-16
    • 1970-01-01
    • 1970-01-01
    • 2022-01-21
    • 1970-01-01
    • 2017-08-27
    • 1970-01-01
    • 2020-04-13
    相关资源
    最近更新 更多