我有以下代码:
#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”。我的英语非常基础,请不要介意:)
答案 0 :(得分:1)
要明确指出,分配给p->str
并不需要分配。 p->str
只是一个内存地址,您可以放入任何内存地址,无论是否有效。当您想要操作内存地址的内容时,需要进行分配。
在p->str = "hello world"
的情况下,编译器提前预留一个内存区域并放置&#34; hello world&#34;字符串,并使用该地址。
注意strcat
的第二个参数如何也是字符串文字,并且不需要分配。
答案 1 :(得分:1)
在第一个示例中,您将一个不可变字符串分配给p->str
(它存储在只读存储器中)。因此,尝试更改内存会导致seg-fault。
在第二个示例中,您未能使用p->str
为malloc
分配空间。由于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
。
显然,malloc
或calloc
的动态分配更灵活;您可以根据需要分配尽可能多的内存,并且可以根据需要使用realloc
增大或缩小动态缓冲区。只需记住在完成后释放p->str
。
您仍然可以将字符串文字的地址指定给p->str
,但请注意,您无法将该地址传递给strcpy
或strcat
或strtok
或尝试修改输入字符串内容的任何其他函数。
答案 3 :(得分:0)
你是对的。但是你应该在这里使用strcpy
而不是strcat
,因为strcat
会将一个字符串附加到p->str
,这是未初始化的。
实际上p->str = "hello world";
会使p->str
指向(匿名)字符串。它的内存通常在程序执行开始时自动分配。