4

I am confused about some basics in C string declaration. I tried out the following code and I noticed some difference:

char* foo(){
    char* str1="string";
    char str2[7]="string";
    char* str3=(char)malloc(sizeof(char)*7);
    return str1;
    /* OR: return str2; */
    /* OR: return str3; */
    }
void main()  {
    printf("%s",foo());
    return 0;
    }

I made foo() return str1/2/3 one at a time, and tried to print the result in the main. str2 returned something weird, but str1 and str3 returned the actual "string".

1.Now, what's the difference between the three declarations? I think the reason why str2 didn't work is because it is declared as a local variable, is that correct?

2.Then what about str1? If the result remains after the foo() ended, wouldn't that cause memory leak?

3.I'm simply trying to write a function that returns a string in C, and use the value returned by that function for other stuff, which str declaration above should I use?

Thanks in advance!

4

3 回答 3

9
char* str1="string";

这会产生str1一个指针;它指向字符串文字的第一个字符。您应该将其定义为const,因为您不允许修改字符串文字:

const char *str1 = "string";

...

char str2[7]="string";

这将创建str2一个数组char(不是指针),并将字符串文字的内容复制到其中。无需将其定义为const; 数组本身是可写的。您也可以省略大小并让它由初始化程序确定:

char str2[] = "string";

然后sizeof str2 == 7(6 字节"string"加 1 用于终止'\0')。

这个:

char* str3=(char)malloc(sizeof(char)*7);

写错了,甚至不应该编译;至少,你应该从你的编译器那里得到一个警告。您正在将结果转换malloc()为 type char。您应该将其转换为char*

char *str3 = (char*)malloc(sizeof(char) * 7);

但是强制转换是不必要的,并且在某些情况下可以掩盖错误;请参阅comp.lang.c FAQ中的问题 7.7 和以下内容:

char *str3 = malloc(sizeof(char) * 7);

但是sizeof(char)根据定义是 1,所以你可以写:

char *str3 = malloc(7);

malloc()分配内存,但不会初始化它,所以如果你尝试打印str3指向的字符串,你会得到垃圾——如果分配的空间碰巧不包含终止 null,甚至会导致运行时崩溃字符'\0'。您可以使用 初始化它strcpy(),例如:

char *str3 = malloc(7);
if (str3 == NULL) {
    fprintf(stderr, "malloc failed\n");
    exit(EXIT_FAILURE);
}
strcpy(str3, "string");

您必须非常小心,您要复制的数据不大于分配的空间。(不,`strncpy() 不是这个问题的答案。)

void main()是不正确的; 它应该是int main(void)。如果您的教科书告诉您要使用,请void main()找到更好的教科书;它的作者不太了解 C。

#include并且您需要为您正在使用的任何库函数提供适当的指令: <stdio.h>for printf()<stdlib.h>forexit()malloc()<string.h>for strcpy()。每个函数的文档都应该告诉您要包​​含哪个标头。

我知道这需要吸收很多;不要指望马上就明白。

我提到了comp.lang.c 常见问题解答;这是一个极好的资源,特别是第 6 节,它讨论了数组和指针以及它们之间经常令人困惑的关系。

至于你的问题 3,如何从 C 函数返回一个字符串,由于 C 进行内存分配的方式(基本上它留给自己管理),结果出奇地复杂。您不能安全地返回指向局部变量的指针,因为当函数返回时该变量不再存在,给调用者留下一个悬空指针,所以返回你的str2是危险的。返回字符串文字是可以的,因为它对应于在整个程序执行过程中存在的匿名数组。您可以声明一个数组static并返回一个指向它的指针,或者您可以使用malloc()(这是最灵活的方法,但这意味着调用者需要free()内存),或者您可以要求调用者传递一个指向缓冲区的指针,您的函数会将结果复制到该缓冲区中。

某些语言允许您构建一个字符串值并简单地从函数中返回它。正如您现在发现的那样,C 不是这些语言之一。

于 2013-01-22T20:34:08.013 回答
6
char* str1="string";

这将创建一个指向文本字符串的指针,该字符串将位于一个.data.text多个段上,并且始终可以访问。每当你做这样的事情时,一定要声明它const,因为如果你试图修改它,可能会发生令人讨厌的事情。

char str2[7]="string";

这会在堆栈上创建一个带有文字字符串副本的本地缓冲区。一旦函数返回,它就变得不可用。这解释了你得到的奇怪结果。

char* str3=(char)malloc(sizeof(char)*7);

这会在堆上创建一个缓冲区(未初始化),直到您释放它为止。你必须释放它,否则你会得到内存泄漏。

于 2013-01-22T20:17:03.620 回答
0

字符串文字 "string"存储为具有静态范围的 7 元素数组,char这意味着它的内存在程序启动时分配并保持到程序终止。

宣言

char *str1 = "string";

将字符串文字的地址str1分配给. 即使str1当函数退出时变量不再存在,它的(字面量的地址"string")在函数之外仍然有效。

宣言

char str2[7] = "string";

声明str2为 的数组,并将字符串文字的内容char复制到其中。当函数退出时,不再存在,其内容不再有意义。 str2

宣言

char *str3 = (char*) malloc(sizeof(char) * 7);

可以简化为

char *str3 = malloc(sizeof *str3 * 7);

分配一个未初始化的 7 字节内存块并将其地址复制到str3. 当函数退出时,变量str3不再存在,但它指向的内存仍然被分配。正如所写,这内存泄漏,因为您没有在调用代码中保留指针的值。请注意,由于您没有将任何内容复制到此块中,因此输出main将是随机的。

此外,除非您的编译器文档明确列出该函数void main()的合法签名,否则请改用。 mainint main(void)

于 2013-01-22T20:27:43.400 回答