如何使用sprintf/snprintf与双指针字符数组

3
以下代码“应该”将字符串数组存储在struct data下的变量name中。假设数组元素的数量在运行时确定,在下面的示例代码中,它们使用DYNAMIC_ELEMENTS定义。字符串使用sprintf格式化。
#define DYNAMIC_ELEMENTS 10

struct data {
    char **name;
};

int main()
{
 struct data *data = calloc(1, sizeof(*data));
 data->name = calloc(DYNAMIC_ELEMENTS, sizeof(data->name[0]));

 for (int i = 0; i <= DYNAMIC_ELEMENTS; i++) {
     sprintf(data->name[i], "Name %u", i + 1);
     printf("%s\n", data->name[i]);
 }
  return 0;
}

当我运行这段代码时,出现了段错误。错误来自于以下代码行:
sprintf(data->name[i], "Name %u", i + 1);
有什么想法是哪里出错了吗?
更新:如果我采取以下方法,代码就能编译通过(但我想避免这种情况):
//...
char buf[127];
sprintf(buf, "Name %u", i + 1);     
data->name[i] = strdup(buf);
//...
2个回答

1

你需要:

 struct data *data = calloc(1, sizeof(*data)); 
 data->name = calloc(DYNAMIC_ELEMENTS, sizeof(data->name[0]));

 for (int i = 0; i < DYNAMIC_ELEMENTS; i++) { /* correctly count till 10 */
     data->name[i] = calloc(256, sizeof(data->name[0][0])); /* allocate memory before copying to it */
     ...

calloc(256, sizeof(data->name[0][0])); 限制字符串大小为255字节。如果这是书的页数或极大的数字呢? - S.S. Anne
1
@JL2210,“%u” 表示无符号整数的十进制表示(https://en.cppreference.com/w/cpp/io/c/fprintf)。它很可能是 4 字节(https://en.cppreference.com/w/cpp/language/types),而不超过 8 字节,因此适合于 256 个字符。当然,这只是一个玩具示例,在分配之前最好进行测量。 - Renat
“Which is most probably 4 bytes ... and not more than 8 bytes” 这句话不太清楚。作为一个32位的unsigned,十进制表示需要11个字节来存储“4294967295”,这也适合256个字节 - 是的,相当过度了。 - chux - Reinstate Monica

1

这个:

i <= DYNAMIC_ELEMENTS

访问超出您分配的内存边界。您应该使用:
i < DYNAMIC_ELEMENTS

你还需要为每个单独的字符串分配内存:
data->name[i] = calloc(1, snprintf(NULL, 0, "Name %u", i + 1));

完整示例:

for (int i = 0; i < DYNAMIC_ELEMENTS; i++) {
    data->name[i] = calloc(1, snprintf(NULL, 0, "Name %u", i + 1));
    sprintf(data->name[i], "Name %u", i + 1);
    printf("%s\n", data->name[i]);
}

这个的原因是:
//...
char buf[127];
sprintf(buf, "Name %u", i + 1);     
data->name[i] = strdup(buf);
//...

这是因为你正在使用strdup分配内存,并将其赋值给data->name[i]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接