struct-> char_member =“”和strcat(struct-> char_member,“string”)之间有什么区别?

时间:2016-09-03 23:20:22

标签: c

我有以下代码:

#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-&gt; str =“hello world”不需要分配内存但strcat(p-&gt; str,“hello world”)需要在使用前分配内存?

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

4 个答案:

答案 0 :(得分:1)

要明确指出,分配给p->str并不需要分配。 p->str只是一个内存地址,您可以放入任何内存地址,无论是否有效。当您想要操作内存地址的内容时,需要进行分配。

p->str = "hello world"的情况下,编译器提前预留一个内存区域并放置&#34; hello world&#34;字符串,并使用该地址。

注意strcat的第二个参数如何也是字符串文字,并且不需要分配。

答案 1 :(得分:1)

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

在第二个示例中,您未能使用p->strmalloc分配空间。由于p未初始化,因此您正在读取您不拥有的内存中的某个随机位置。

尝试:

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

这里我们有malloc'足够的空间用于“hello world”(加上'\ 0'字符)。 strcpy将字符串“hello”复制到已分配的内存中。现在strcat成功,因为你“拥有”p-&gt; str所指向的记忆。

另外不要忘记你已经使用malloc的free()内存!

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

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

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

答案 2 :(得分:1)

"hello, world""hello"" world"都是字符串文字;它们都存储为char的数组,以便程序一开始就可用,并且在程序的生命周期内可见。

声明

p->str = "hello, world";

将字符串文字的地址复制到p->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->str设置为指向您在别处声明的数组

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

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

struct test
{
  char str[SOME_SIZE];
};

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

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

您仍然可以将字符串文字的地址指定给p->str,但请注意,您无法将该地址传递给strcpystrcatstrtok或尝试修改输入字符串内容的任何其他函数。

答案 3 :(得分:0)

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

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