【问题标题】:C string declarationC 字符串声明
【发布时间】:2013-01-22 20:14:02
【问题描述】:

我对 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,并尝试在 main 中打印结果。 str2 返回了一些奇怪的东西,但 str1 和 str3 返回了实际的“字符串”。

1.现在,这三个声明有什么区别?我认为 str2 不起作用的原因是因为它被声明为局部变量,对吗?

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

3.我只是想用 C 语言编写一个返回字符串的函数,并将该函数返回的值用于其他内容,我应该使用上面的哪个 str 声明?

提前致谢!

【问题讨论】:

    标签: c string


    【解决方案1】:
    char* str1="string";
    

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

    const char *str1 = "string";
    

    ...

    char str2[7]="string";
    

    这使str2 成为char 的数组(不是指针),并将字符串文字的内容复制到其中。无需将其定义为const;数组本身是可写的。你也可以省略大小,让它由初始化器决定:

    char str2[] = "string";
    

    然后是sizeof str2 == 7"string" 为 6 个字节,终止 '\0' 为 1)。

    这个:

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

    写错了,它甚至不应该编译;至少,你应该从你的编译器那里得到一个警告。您将malloc() 的结果转换为类型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 指向的字符串,你会得到垃圾——如果分配的空间甚至会导致运行时崩溃碰巧不包含终止空字符'\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 不是其中一种语言。

    【讨论】:

    • 感谢您的澄清。在这种情况下,如果我的函数必须返回一个任意长度的字符串,我在函数中使用了一个 char[someLength] 缓冲区,如何将这个缓冲区作为输出返回?
    • @user1926344:首先,请注意您的“任意长度”字符串不能超过someLength 字节。其次,您只需将其复制到调用者能够访问的某个内存区域——这意味着您不妨跳过char[someLength] 变量并直接将其复制到那里。该区域可以是static(有一些缺点),也可以是malloc()ed,也可以由调用者来分配它并向你的函数传递一个指针。
    【解决方案2】:
    char* str1="string";
    

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

    char str2[7]="string";
    

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

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

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

    【讨论】:

      【解决方案3】:

      字符串字面量 "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)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-01-03
        • 2010-12-31
        • 1970-01-01
        • 1970-01-01
        • 2013-05-25
        • 2018-02-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多