【问题标题】:what's difference between struct->char_member = "" and strcat(struct->char_member,"string")?struct->char_member = "" 和 strcat(struct->char_member,"string") 有什么区别?
【发布时间】:2017-01-11 17:40:14
【问题描述】:

我有以下代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct test {
    char *str;
};

int main(void)
{
    struct test *p = malloc(sizeof(struct test));
    p->str = "hello world";
    printf("%s\n",p->str);
    return 0;
}

它工作正常。但是当我这样写的时候:

struct test *p = malloc(sizeof(struct test));
p->str="hello";
strcat(p->str," world");

或者这个:

struct test *p = malloc(sizeof(struct test));
strcat(p->str,"hello world");

我遇到了分段错误。

我在这里找到了一些相关的解释:

您只为结构本身分配内存。这包括指向 char 的指针,它在 32 位系统上只有 4 个字节,因为它是结构的一部分。它不包括未知长度字符串的内存,因此如果您想要一个字符串,您也必须手动为其分配内存

Allocate memory for a struct with a character pointer in C

通过解释,我知道如果我想使用strcat,正确的代码应该是这样的:

struct test *p = malloc(sizeof(struct test));
p->str = malloc(size);
strcat(p->str,"hello world");

所以我的问题是为什么 p->str = "hello world" 不需要分配内存但 strcat(p->str,"hello world") 需要在使用前分配内存?

我的编译器是“gcc (Debian 4.9.2-10) 4.9.2”。我的英语很基础,请不要介意:)

【问题讨论】:

  • 您的“正确代码”也不正确,您还需要在调用 strcat 之前初始化为空字符串
  • strcat() 只能用于将更多文本附加到已经初始化的字符串,分配内存后不能立即使用。首先使用strcpy(),或者至少确保将字符串的第一个元素设置为\0,使其成为有效的空字符串。

标签: c


【解决方案1】:

"hello, world""hello"" world" 都是 字符串字面量;它们都存储为char 的数组,以便它们在程序启动后立即可用并且在程序的生命周期内可见。

声明

p->str = "hello, world";

将字符串文字的地址复制到p-&gt;str。这适用于printf 语句和任何其他只需要读取 字符串的东西。但是,在声明中

p->str = "hello";
strcat( p->str, " world" );

您正在尝试修改字符串文字"hello",通过将字符串" world" 附加到它。字符串文字不可修改,并且尝试这样做会导致 未定义的行为,在您的情况下这是一个段错误 - 在许多流行的桌面平台上,字符串文字保存在内存的只读部分中。

因此,您需要留出一个您可以写入的内存区域。您可以使用

动态进行
p->str = malloc( SOME_SIZE);  // enough space to store your final string
strcpy( p->str, "hello" );  // copy the contents of "hello" to the memory str points to
strcat( p->str, " world" ); // append the contents of " world" to the memory str points to

或者您可以将p-&gt;str 设置为指向您在其他地方声明的数组

char buffer[SOME_SIZE];
p->str = buffer; // assigns the *address* of buffer to p->str

或者您可以在struct 定义中将str 声明为char 的数组

struct test
{
  char str[SOME_SIZE];
};

SOME_SIZE 足够大,可以容纳您要存储的任何字符串。请注意,在这种情况下,p-&gt;str = "hello" 不会工作;您不能使用= 运算符将数组的内容相互分配;在这种情况下,您必须使用 strcpy

显然,malloccalloc 的动态分配更灵活;您可以根据需要分配尽可能多的内存,并且可以根据需要使用realloc 增大或缩小动态缓冲区您只需要记住在完成后释放p-&gt;str

您仍然可以将字符串文字的地址分配给 p-&gt;str,但请注意,您不能将该地址传递给像 strcpystrcatstrtok 这样的函数或任何其他试图修改输入字符串的内容。

【讨论】:

    【解决方案2】:

    需要明确的是,分配给p-&gt;str 并不是需要分配的。 p-&gt;str 只是一个内存地址,你可以放入任何内存地址,有效与否。当你想操作内存地址的内容时,你需要一个分配。

    p-&gt;str = "hello world" 的情况下,编译器提前保留一个内存区域并将“hello world”字符串放入其中,并使用该地址。

    注意strcat 的第二个参数也是字符串字面量,不需要分配。

    【讨论】:

      【解决方案3】:

      在第一个示例中,您将一个不可变字符串分配给p-&gt;str(它存储在只读内存中)。因此尝试更改内存会导致段错误。

      在第二个示例中,您未能使用mallocp-&gt;str 分配空间。由于 p 未初始化,因此您正在从不属于您的内存中的某个随机位置读取数据。

      试试:

      struct test *p = malloc(sizeof(struct test));
      p->str=(char *)malloc(12 * sizeof(char));
      strcpy(p->str, "hello");
      strcat(p->str," world");
      

      这里我们有malloc'd 刚刚足够的空间用于“hello world”(加上 '\0' 字符)。 strcpy 将字符串“hello”复制到您分配的内存位置。现在strcat 成功了,因为您“拥有” p->str 指向的内存。

      也不要忘记free()内存你有malloc'd!

      编辑:作为旁注,我认为您可能对为结构分配内存感到困惑。在这种情况下,为结构分配内存只会为char * 提供足够的内存;但是您还没有为实际指向的指针分配内存。

      实际上没有必要为struct test 分配内存,你可以只为char * 分配内存。更好的是:

      struct test p;
      p.str=(char *)malloc(12 * sizeof(char));
      strcpy(p.str, "hello");
      strcat(p.str," world");
      

      【讨论】:

      • 我认为你不应该转换malloc() 的结果。这在网络上的几个地方都有解释。
      【解决方案4】:

      你是对的。但是你应该在这里使用strcpy 而不是strcat,因为strcat 会在p-&gt;str 后面附加一个未初始化的字符串。

      事实上p-&gt;str = "hello world"; 将使p-&gt;str 指向一个(匿名)字符串。它的内存通常在程序执行开始时自动分配。

      【讨论】:

        猜你喜欢
        • 2011-11-14
        • 1970-01-01
        • 2014-06-17
        • 1970-01-01
        • 2014-10-20
        • 1970-01-01
        • 2019-05-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多