5

这个程序在我的 UNIX 机器上导致了一个段错误。我将原因缩小到第二次调用 memset()。

为什么会出现这种行为?第一个“块”代码与第二个几乎相同,不是吗?如果第二个调用 memset segfault,为什么第一次调用没有呢?

我查看了有关 segfaulting memset 调用的其他线程,但没有一个与此类似。

如果您想知道我为什么要编写这样一个微不足道的程序,它改编自我一直在编写的另一个程序,我用它来教自己如何将 memcpy() 应用于结构。

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

typedef struct{
    int x;
    char text;
} FilesStruct;

int
main(int argc, char** argv)
{
    FilesStruct *old_dir;
    memset(old_dir,0,sizeof(FilesStruct));
    old_dir->x = 3;
    old_dir->text = 'c';
    printf("old dir: %d,%c\n",old_dir->x,old_dir->text);

    FilesStruct *new_dir;
    memset(new_dir,0,sizeof(FilesStruct));
    new_dir->x = 7;
    new_dir->text = 'g';
    printf("new dir: %d,%c\n",new_dir->x,new_dir->text);

    return 0;
}
4

3 回答 3

11
FilesStruct *old_dir;
memset(old_dir,0,sizeof(FilesStruct));

尝试写入未初始化的指针。这会导致未定义的行为,包括可能的崩溃。这种行为的第一个实例没有崩溃只是运气(好或坏,取决于你如何看待它)。

您需要为old_dir. 最简单的方法是在堆栈上声明它

FilesStruct old_dir;
memset(&old_dir,0,sizeof(old_dir));

或者您可以在堆上动态分配(确保在free不再需要该对象时调用)

FilesStruct *old_dir = calloc(1, sizeof(*old_dir);
/* use old_dir */
free(old_dir);

这同样适用于new_dir您的代码。

于 2013-05-28T13:43:29.763 回答
3
FilesStruct *old_dir;

这定义了一个 FilesStruct 指针。它未初始化,因此它实际上并不指向 FilesStruct 的任何存储。

memset(old_dir,0,sizeof(FilesStruct));

将告诉 memset 将 old_dir 指向的任何内容归零,但由于指针未初始化,您会得到未定义的行为。

您需要为指针提供存储空间,例如

FilesStruct *old_dir = malloc(sizeof(FilesStruct));

在您的情况下,您实际上并不需要指针或动态分配的内存,您可能会这样做

FilesStruct old_dir;
memset(&old_dir,0,sizeof(FilesStruct));
old_dir.x = 3;
old_dir.text = 'c';
printf("old dir: %d,%c\n",old_dir.x,old_dir.text);
于 2013-05-28T13:49:26.920 回答
3

既没有old_dir也没有new_dir初始化,所以这是未定义的行为。一种解决方案是在堆栈上分配两个变量:

FilesStruct old_dir;
//...
FilesStruct new_dir;

&在调用时使用运算符获取地址memset

memset(&old_dir,0,sizeof(FilesStruct));
于 2013-05-28T13:43:52.777 回答