结构上的指定初始化程序导致 strcpy 和 realloc 中出现段错误

发布于 2025-01-09 07:43:56 字数 1213 浏览 1 评论 0原文

我正在使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

柏林苍穹下 2025-01-16 07:43:56
struct human_t steve = {.name = "Steve", 
                          .title = "Mr.", 
                          .gender = male
                         };

这里的name(和title)是用字符串文字的地址初始化的。字符串文字不是从堆中分配的,实际上它们(通常)是只读的。因此,如果您想编写更健壮的代码,则应始终将字符串文字分配给 const char* 。


因此,在第一个片段中,strcpy(steve.name, "AA"); 将尝试写入只读内存并崩溃。如果您将 steve.name 设置为 const char,它会产生编译器错误,并且您会安全。


然后第二个片段,realloc(steve.name, strlen(new_name));将尝试调整未使用malloc分配的内存块的大小。所以你会崩溃。

另外,这根本不是您使用realloc的方式。您需要这样做:

char *tmp = realloc(steve.name, strlen(new_name)+1);
if (!tmp) { perror("realloc error"); exit(1); }
strcpy(tmp, new_name);
steve.name = tmp;

要修复,存储字符串的副本:

struct human_t steve = {.name = strdup("Steve"), 
                          .title = strdup("Mr."), 
                          .gender = male
                         };

这里 strdup 是一个 POSIX 函数,但不是标准 C 函数,因此您可能需要自己定义它:

char *strdup(const char *src)
{
    char *dst = src ? malloc(strlen(src)+1) : NULL;
    if (dst) strcpy(dst, src);
    return dst;
}
struct human_t steve = {.name = "Steve", 
                          .title = "Mr.", 
                          .gender = male
                         };

Here name (and title) 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 to const 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 made steve.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 with malloc. So you get a crash.

Also, this is not how you use realloc at all. You need to do it like this:

char *tmp = realloc(steve.name, strlen(new_name)+1);
if (!tmp) { perror("realloc error"); exit(1); }
strcpy(tmp, new_name);
steve.name = tmp;

To fix, store copy of the string:

struct human_t steve = {.name = strdup("Steve"), 
                          .title = strdup("Mr."), 
                          .gender = male
                         };

Here strdup is a POSIX function, but not standard C function, so you may need to define it yourself:

char *strdup(const char *src)
{
    char *dst = src ? malloc(strlen(src)+1) : NULL;
    if (dst) strcpy(dst, src);
    return dst;
}
鸵鸟症 2025-01-16 07:43:56

在此声明中,

struct human_t steve = {.name = "Steve", 
                          .title = "Mr.", 
                          .gender = male
                         };

您使用字符串文字 "Steve" 的第一个字符的地址初始化了指针 name

然后在这个语句中

strcpy(steve.name, "AA");

你试图改变字符串文字。

任何更改字符串文字的尝试都会导致未定义的行为。

相反,您可以只写

steve.name = "AA";

After ,指针 name 将指向字符串文字 "AA"

在此语句中,

realloc(steve.name, strlen(new_name));

您尝试重新分配具有静态存储持续时间的字符串文字占用的内存。但您只能重新分配先前动态分配的内存。此外,通常您需要将 realloc 调用的返回地址分配给指针。否则,重新分配的内存的地址将会丢失,并且会出现内存泄漏。

要么将数据成员名称声明为字符数组,例如

struct human_t {
    char name[10[;
    char * title;
    sexe gender;
};

,要么总是动态分配内存来存储字符串,例如

struct human_t steve = {.name = malloc( 10 ), 
                          .title = "Mr.", 
                          .gender = male
                         };

strcpy( steve.name, "Steve" );

另一个数据成员 title 也存在同样的问题。

In this declaration

struct human_t steve = {.name = "Steve", 
                          .title = "Mr.", 
                          .gender = male
                         };

you initialized the pointer name with the address of the first character of the string literal "Steve".

Then in this statement

strcpy(steve.name, "AA");

you was trying to change the string literal.

Any attempt to change a string literal results in undefined behavior.

Instead you could just write

steve.name = "AA";

After that the pointer name will point to the string literal "AA".

In this statement

realloc(steve.name, strlen(new_name));

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

struct human_t {
    char name[10[;
    char * title;
    sexe gender;
};

Or always allocate dynamically a memory to store there a string as for example

struct human_t steve = {.name = malloc( 10 ), 
                          .title = "Mr.", 
                          .gender = male
                         };

strcpy( steve.name, "Steve" );

The same problem exists with another data member title.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文