2013-01-22 112 views
4

我对C字符串声明中的一些基本知识感到困惑。我尝试了下面的代码,我注意到一些差异:C字符串声明

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; 
    } 

我提出FOO()的返回STR1/2/3一次一个,并试图打印结果在主。 str2返回了一些奇怪的东西,但str1和str3返回了实际的“字符串”。

1.现在这三个声明有什么区别?我认为str2之所以不起作用是因为它被声明为局部变量,这是否正确?

2.那么str1呢?如果结果在foo()结束后仍然存在,是不是会导致内存泄漏?

3.我只是试图编写一个函数,它返回C中的一个字符串,并将该函数返回的值用于其他的东西,我应该使用哪个str声明?

在此先感谢!

回答

8
char* str1="string"; 

这使得str1是一个指针;它指向字符串文字的第一个字符。你应该把它定义为const,因为你不允许修改字符串文字:

const char *str1 = "string"; 

...

char str2[7]="string"; 

这使得str2char数组(不是指针),和将字符串文字的内容复制到其中。没有必要将其定义为const;该阵列本身是可写的。还可以省略尺寸,让它通过初始化来确定:

char str2[] = "string"; 

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

此:

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

编写不当,它甚至不应该编译;至少,你应该从你的编译器得到警告。您正在将malloc()的结果转换为char。你应该将其转换为char*

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

但投是不必要的,可以掩盖在某些情况下的错误;参见问题7.7和在comp.lang.c FAQ如下:

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

sizeof(char)是1的定义,所以你可以这样写:

char *str3 = malloc(7); 

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

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

你必须要非常小心,你复制的数据是不超过所分配的空间更大。 (否,`strncpy() is not the answer to this problem。)

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

而你需要为你使用任何库函数适当#include指令:<stdio.h>printf()<stdlib.h>exit()malloc(),并<string.h>strcpy()。每个函数的文档都应该告诉你要包含哪个头文件。

我知道这是很多吸收;不要指望马上理解它。

我提到了comp.lang.c FAQ;这是一个很好的资源,特别是第6节,讨论数组和指针以及它们之间经常令人困惑的关系。如果你的问题3,如何从C函数返回一个字符串,事实证明,由于C内存分配的方式(基本上它自己管理它),结果会非常复杂。你不能安全地返回一个指向局部变量的指针,因为当函数返回时该变量不再存在,使得调用者留下一个悬挂指针,因此返回str2是危险的。返回一个字符串文字是可以的,因为它对应于整个执行程序时存在的匿名数组。你可以用static声明一个数组并返回一个指针,或者你可以使用malloc()(这是最灵活的方法,但它意味着调用者需要free()内存),或者你可以要求调用者传入一个指针到你的函数将复制结果的缓冲区。

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

+0

感谢您的澄清。在这种情况下,如果我的函数必须返回一个任意长度的字符串,我在函数中使用了一个char [someLength]缓冲区,我怎样才能返回这个缓冲区作为输出? – turtlesoup

+0

@ user1926344:首先,请注意您的“任意长度”字符串不能长于“someLength”字节。其次,你只需将它复制到调用者可以访问的某个内存区域 - 这意味着你可以直接跳过'char [someLength]'变量并将其复制到那里。该区域可以是'静态'(有一些缺点),或者它可以是'malloc()',也可以由调用者来分配它并将函数传递给指针。 –

6
char* str1="string"; 

这将创建一个指向将位于任.data.text段和在任何时候都可以访问的文本字符串。每当你做这样的事情时,一定要声明它const,因为如果你尝试修改它,可能会发生讨厌的事情。

char str2[7]="string"; 

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

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

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

0

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

声明

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()作为main功能的合法签名,使用int main(void)代替。