我有一些代码在使用 sprintf 复制指向字符串的指针时会进行堆栈转储。我正在尝试将动物的内容复制到一个名为 output 的新指针数组中。但是,我得到了堆栈转储。
输出中应包含以下内容: 新动物兔子 新动物马 新动物驴
我以正确的方式解决这个问题吗?
非常感谢
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void p_init(const char **animals, char **output);
int main(int argc, char **argv)
{
char *animals[] = {"rabbit", "horse", "donkey", '\0'};
char **prt_animals = animals;
char *output[sizeof(*animals)];
/* print the contents here */
while(*prt_animals)
{
printf("Animal: %s\n", *prt_animals++);
}
/* copy and update in the output buffer */
p_init(*&animals, *&output);
getchar();
return 0;
void p_init(const char **animals, char **output)
{
while(*animals)
{
sprintf(*output, "new animal %s", *animals);
*output++;
}
}
最佳答案
数组animals
是一个指针数组。它不是某种大小的缓冲区数组。因此,如果你这样做了
sizeof(*animals)
您将获得该数组第一个元素的大小。相当于
sizeof(char*)
因为你的数组存储指针。因此,在读取的行中
char *output[sizeof(*animals)];
您在一个数组中分配了 4 个或 8 个指针(取决于您平台上指针的宽度。通常是 4 个或 8 个)。但这当然没有意义!您想要做的是创建一个与 animals
大小相同的指针数组。你必须先得到动物数组的总大小,然后除以一个元素的大小
char *output[sizeof(animals)/sizeof(*animals)];
现在,这就是您想要的。但是指针仍将具有不确定的值...接下来您使用 *&animals
传递数组(另一个相同)。为什么?您可以直接传递 animals
。获取它的地址然后取消引用与一开始什么都不做是一样的。
然后在您调用的函数中,您将 animal
中的元素指向的字符串复制到某个不确定的目的地(记住 output
数组的元素 - 指针 -还有不确定的值。我们还没有分配它们!)。您首先必须分配适量的内存并使元素指向该内存。
while(*animals) {
// now after this line, the pointer points to something sensible
*output = malloc(sizeof("new animal ") + strlen(*animals));
sprintf(*output, "new animal %s", *animals);
output++; // no need to dereference the result
animals++; // don't forget to increment animals too!
}
加法,关于上面的sizeof
您必须确定一件重要的事情。这是我们计算尺寸的方式。无论您做什么,请确保您始终有足够的空间放置琴弦! C 字符串由字符和一个终止空字符组成,它标志着字符串的结尾。因此,*output
应该指向一个缓冲区,该缓冲区至少要包含用于“new animal”
和*animals
的空间。第一个包含 11 个字符。第二个取决于我们实际复制的内容 - 它的长度是 strlen
返回的内容。所以,我们总共需要
12 + strlen(*animals)
所有字符的空格,包括终止空值。现在,将该数字硬编码到您的代码中并不是一种好的风格。前缀可能会更改,您可能会忘记更新数字或误数一两个字符。这就是我们使用 sizeof
的原因,我们将其与我们想要添加的字符串文字一起提供。回想一下,sizeof
表达式的计算结果为其操作数的大小。您之前在 main
中使用它来获取数组的总大小。现在您将它用于字符串文字。所有字符串文字都是字符数组。字符串文字由您键入的字符组成,除 空字符外。因此,以下条件成立,因为 strlen
计算 C 字符串的长度,并且不包括终止空字符到它的长度
// "abc" would have the type char[4] (array of 4 characters)
sizeof "..." == strlen("...") + 1
我们不必除以一个元素的大小,因为 sizeof char 无论如何都是一个,所以不会有什么区别。为什么我们使用 sizeof
而不是 strlen?因为它已经考虑了终止空字符,并且它在编译时进行评估。编译器可以逐字替换 sizeof 表达式返回的大小。
关于将字符串复制到缓冲区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/663064/