【问题标题】:Array of pointers initialization指针数组初始化
【发布时间】:2009-10-18 15:36:15
【问题描述】:
 char **arr;
 arr = (char **)calloc(1,sizeof(char*));

 for(i = 0; i< 16; i++)
    if(arr[i] = (char *)calloc(1, 2*sizeof(char)) == NULL)
        perror("Memory cannot be allocated to arr[i]", %d);

当我尝试将内存分配给 arr[i] 时,上面的代码在 for 循环中引发错误。这个分配有什么问题。本质上,我想存储 16 个长度为 2 的字符串。我也尝试过使用指针数组(char *arr[16])。我尝试使用 malloc() 和 calloc() 查找有关双指针初始化的资源,但找不到很多 .如果您能指出一些链接,那将不胜感激。 谢谢。

【问题讨论】:

  • 代码不可编译。通常建议您发布您正在使用的真实代码。
  • @Andrey - 我没有在错误中使用 %d 。我刚刚打印了错误字符串。
  • 这还不是全部。您对if 下的arr[i] 的分配与NULL 的比较缺少大括号,这使其关联不正确。它也无法编译。

标签: c pointers


【解决方案1】:

您需要为 16 个指针分配足够的内存,而不仅仅是一个。

arr = (char **)calloc(16, sizeof(char*));

您的代码发生的情况是arr 有足够的内存仅用于一个指针,因此arr[0] = &lt;something&gt; 是正确的,但arr[1] 及更高版本正在触及不属于程序的内存。

此外,分配字符串指针的方式是错误的。您正在分配 0 或 1 值,具体取决于 calloc 的结果是否为 NULL。您需要在此处添加括号:

if ((arr[i] = (char *)calloc(1, 2*sizeof(char))) == NULL)
    perror("Memory cannot be allocated to arr[%d]", i);

呃更好:

for(i = 0; i < 16; i++) {
    arr[i] = (char *)calloc(1, 2*sizeof(char));
    if (arr[i] == NULL) {
        perror("Memory cannot be allocated to arr[%d]", i);
    }
}

【讨论】:

  • 这不是我在 for 循环中所做的吗?我在这里错过了什么吗?
  • 不,您正在为一个指针分配内存,然后(错误地)覆盖不属于您的程序的内存。
  • 不,您正在分配数组中的各个字符串。您必须首先确保您有空间容纳 16 个指向字符串的指针。试试 Lukas 的建议,你会发现它有效。另请记住,您需要通过 16 次对 free() 的单独调用来释放每个字符串 + 整个数组
  • 我试过上面的代码。代码编译正常,但是内存没有分配给 arr[i],perror 说内存不能分配。
  • 那是因为赋值错误,a = b == c 被评估为a = (b == c),而不是(a = b) == c。您需要在此处添加括号。
【解决方案2】:

当你使用calloc时,习惯上使用第一个参数传递数组中的元素个数,第二个参数传递一个元素的大小。因此,要分配一个包含 16 个指针的数组,通常会使用 calloc(16, &lt;pointer size&gt;),而不是 calloc(1, 16 * &lt;pointer size&gt;),尽管两者都做同样的事情。在您的代码中,您显然完全忘记了 16 并且只分配了 1 个指针。

不要转换 'calloc' 的结果。

在计算内存分配函数的大小时避免使用sizeof(&lt;type&gt;)。更喜欢使用sizeof *&lt;pointer&gt;

如果要存储长度为 2 的字符串,则需要一个至少 3 个字符长的缓冲区(零终止符的额外字符)。

内存分配失败通常不会设置errno,因此perror 不适合在这里使用。

if 条件下对arr[i] 的分配缺少大括号。操作关联不正确。它不会按原样编译。

char **arr; 
arr = calloc(16, sizeof *arr); 
for(i = 0; i < 16; i++)
    if((arr[i] = calloc(3, sizeof *arr[i]) == NULL)
        fprintf(stderr, "Memory cannot be allocated");

最后,一个未命名的“魔常数”(16 和 3)在大多数情况下不是一个好主意。

【讨论】:

  • 不要转换 'calloc' 的结果。为什么?
  • 首先,没有必要。其次,它相当危险(请参阅常见问题解答 c-faq.com/malloc/mallocnocast.html)。第三,类型名称用于声明,它们不应该在“常规”代码中提及。
  • 但是,重点是它们完全没有必要,所以这里的主要问题是你到底为什么要在那里放一个演员表 ?
  • 习惯 C++ 的人通常会这样做,因为如果没有强制转换,这将是一个错误,或者至少是一个警告。
  • 除了自定义之外,还有一个很好的理由更喜欢calloc(number, size) 而不是calloc(1, number * size) - 在前者中,calloc 应该检查乘法是否溢出size_t 的大小并进行换行,而在后者你需要自己做。
【解决方案3】:
arr = (char **)calloc(1,sizeof(char*));

分配一个指向char的指针。

本质上,我想存储 16 个长度为 2 的字符串

char **arr = calloc(16, sizeof *arr);

if (!arr) exit(-1); /* bail out somehow */

for(i = 0; i < 16; i++)
  if((arr[i] = calloc(2, sizeof *arr[ i ])) == NULL)
    printf("Memory cannot be allocated to arr[ %d ]", i + 1);

还要检查if 条件和printf 语句中的括号。你的代码还能编译吗?

【讨论】:

  • 是的,我的代码可以编译,但在运行时会引发分段错误。
  • @Deepak Konidena:请不要发明任何东西。您在原始问题中发布的代码不会(也没有)无法编译。要么您发布了错误的代码,要么发生了其他事情,但 OP 中的代码再次不可编译。
  • @dirkgently:在这两种情况下你都忘记了sizeof。此外,perror 并没有按照您的想法行事。为什么 16 和 2(3?)突然互换位置?
  • @Andrey - 是的,你是对的。我只是打印了错误字符串,没有使用 %d。
  • 仍然无法编译。请参阅我对原始帖子的评论。
【解决方案4】:

直接存储两个字符比存储指针要便宜,所以我建议放弃一级间接并使用连续的内存块:

char (*arr)[2] = calloc(16, sizeof *arr); 

另外请记住,您的字符序列不能是字符串,因为您没有为终止 0 提供内存。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-28
    • 1970-01-01
    • 2016-12-09
    • 1970-01-01
    相关资源
    最近更新 更多