结构上的指定初始化程序导致 strcpy 和 realloc 中出现段错误
我正在使用 WSL Ubuntu-20.04 LTS
并使用 gcc
进行编译。
我正在准备一些示例来向 CS 学生教授 C 的基础知识,当我阅读有关指定初始化程序的内容时,以下代码引发了错误,
typedef enum {male, female} sexe;
struct human_t {
char * name;
char * title;
sexe gender;
};
struct human_t steve = {.name = "Steve",
.title = "Mr.",
.gender = male
};
strcpy(steve.name, "AA");
并阅读了关于 strcpy
的手册,目标缓冲区为比 "AA"
更大的尺寸我只是不知道为什么这不起作用。
我还观察到以下情况:
struct human_t steve = {.name = "Steve",
.title = "Mr.",
.gender = male
};
char * new_name = "Gobeldydukeryboo";
realloc(steve.name, strlen(new_name));
strcpy(steve.name, new_name);
这会返回错误realloc():无效指针
。
阅读关于realloc的手册,指针必须由malloc
调用返回才能工作。 我有一种感觉,指定初始化不会调用 malloc
,这可以解释为什么 realloc
失败,但是,它不能解释为什么 strcpy 失败。
这是怎么回事?
I'm using WSL Ubuntu-20.04 LTS
and compiling with gcc
.
I'm preparing some examples to teach the basics of C to CS Students and as I was reading about designated Initialisers, the following bit of code caused errors,
typedef enum {male, female} sexe;
struct human_t {
char * name;
char * title;
sexe gender;
};
struct human_t steve = {.name = "Steve",
.title = "Mr.",
.gender = male
};
strcpy(steve.name, "AA");
And reading the manual on strcpy
the destination buffer being of larger size than "AA"
I'm simply at a loss as to why this doesn't work.
I also observed the following :
struct human_t steve = {.name = "Steve",
.title = "Mr.",
.gender = male
};
char * new_name = "Gobeldydukeryboo";
realloc(steve.name, strlen(new_name));
strcpy(steve.name, new_name);
And this returns the error realloc(): invalid pointer
.
Reading the manual on realloc
the pointer must have been returned by a malloc
call for it to work.
I'm having a feeling that designated initialisation does not call malloc
, which would explain why realloc
fails, it doesn't, however, explain why strcpy
fails.
What's going on here ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这里的
name
(和title
)是用字符串文字的地址初始化的。字符串文字不是从堆中分配的,实际上它们(通常)是只读的。因此,如果您想编写更健壮的代码,则应始终将字符串文字分配给 const char* 。因此,在第一个片段中,
strcpy(steve.name, "AA");
将尝试写入只读内存并崩溃。如果您将 steve.name 设置为 const char,它会产生编译器错误,并且您会安全。然后第二个片段,
realloc(steve.name, strlen(new_name));
将尝试调整未使用malloc
分配的内存块的大小。所以你会崩溃。另外,这根本不是您使用realloc的方式。您需要这样做:
要修复,存储字符串的副本:
这里
strdup
是一个 POSIX 函数,但不是标准 C 函数,因此您可能需要自己定义它:Here
name
(andtitle
) is initialized with the address of a string literal. String literals are not allocated from heap and in fact they are (usually) read-only. So string literals should always be assigned toconst char*
if you want to write more robust code.So in the first snippet,
strcpy(steve.name, "AA");
will try to write to read-only memory and crashes. If you had madesteve.name
a const char, it would have produced a compiler error and you would have been safe.Then 2nd snippet,
realloc(steve.name, strlen(new_name));
will try to resize a memory block which was not allocated withmalloc
. So you get a crash.Also, this is not how you use
realloc
at all. You need to do it like this:To fix, store copy of the string:
Here
strdup
is a POSIX function, but not standard C function, so you may need to define it yourself:在此声明中,
您使用字符串文字
"Steve"
的第一个字符的地址初始化了指针name
。然后在这个语句中
你试图改变字符串文字。
任何更改字符串文字的尝试都会导致未定义的行为。
相反,您可以只写
After ,指针
name
将指向字符串文字"AA"
。在此语句中,
您尝试重新分配具有静态存储持续时间的字符串文字占用的内存。但您只能重新分配先前动态分配的内存。此外,通常您需要将 realloc 调用的返回地址分配给指针。否则,重新分配的内存的地址将会丢失,并且会出现内存泄漏。
要么将数据成员名称声明为字符数组,例如
,要么总是动态分配内存来存储字符串,例如
另一个数据成员
title
也存在同样的问题。In this declaration
you initialized the pointer
name
with the address of the first character of the string literal"Steve"
.Then in this statement
you was trying to change the string literal.
Any attempt to change a string literal results in undefined behavior.
Instead you could just write
After that the pointer
name
will point to the string literal"AA"
.In this statement
you are trying to reallocate the memory occupied by a string literal that has static storage duration. But you may reallocate only memory that was previously allocated dynamically. Moreover in general you need to assign to a pointer the returned address of a call of
realloc
. Otherwise the address of the reallocated memory will be lost and you will have a memory leak.Either declare the data member name as a character array as for example
Or always allocate dynamically a memory to store there a string as for example
The same problem exists with another data member
title
.