c-在主函数中访问动态数组中的记录时发生分段故障,但在包含函数中不发生



我遇到了这样一个问题:结构的动态数组被正确初始化,并用包含文件中的函数中的数据填充,但试图访问数组的内容会导致主函数中的分段错误,即使指针是全局定义的。请看下面的例子:

my_struct.h

typedef struct my_struct {
int one;
int two;
} my_struct_t;
void update_my_struct(my_struct_t*, int);

my_struct.c

#include <stdlib.h>
#include <stdio.h>
#include "my_struct.h"
void
update_my_struct(my_struct_t *my_s, int num)
{
int i;
for (i = 0; i < num; i++ ) {
my_s = realloc(my_s, sizeof(my_struct_t)*(i+1));
my_s[i].one = 1*i;
my_s[i].two = 2*i;
}
printf("  my_s[0] one: %d two: %dn", my_s[0].one, my_s[0].two);
}

main.c

#include <stdlib.h>
#include <stdio.h>
#include "my_struct.h"
my_struct_t *my_structs;
void
main(void)
{
int i;
update_my_struct(my_structs, 4);
for (i = 0; i < 4; i++)
printf("  %d. one = %d, two = %dn", i, my_structs[i].one, my_structs[i].two);
free(my_structs);
}

编译并运行:

$ gcc main.c my_struct.c
$ ./a.out 
my_s[0] one: 0 two: 0
Segmentation fault (core dumped)

我用gdb检查了一下,seg错误发生在main中,所以我很困惑,为什么动态数组可以在包含的函数中访问,而在主函数中访问——尽管指针是在main.c中声明的。我将感谢对这个问题的一些有益的提示和评论。

更新

根据EML的回答,我将更新功能的代码更改为:

void
update_my_struct(my_struct_t *my_s, int num)
{
int i;
for (i = 0; i < num; i++ ) {
if (my_s == NULL)
my_s = (my_struct_t *) malloc(sizeof(my_struct_t));
else
my_s = (my_struct_t *) realloc(my_s, sizeof(my_struct_t)*(i+1));
my_s[i].one = 1*i;
my_s[i].two = 2*i;
}
printf("  my_s[3] one: %d two: %dn", my_s[3].one, my_s[3].two);
}

Seg故障仍然发生:

$ ./a.out 
my_s[3] one: 3 two: 6
Segmentation fault (core dumped)

Valgrind没有向我提供任何有见地的信息,以下是其输出的片段:

==5301== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==5301== Command: ./a.out
==5301== 
my_s[3] one: 3 two: 6
==5301== Invalid read of size 4
==5301==    at 0x40118F: main (in a.out)
==5301==  Address 0x4 is not stack'd, malloc'd or (recently) free'd
==5301== 
==5301== 
==5301== Process terminating with default action of signal 11 (SIGSEGV): dumping core
...

以下是我在评论中暗示的内容。这假设*my_s最初为NULL,因此在这种情况下realloc的行为将类似于malloc

#include <stdlib.h>
#include <stdio.h>
#include "my_struct.h"
void
update_my_struct(my_struct_t **my_s, int num)
{
int i;
*my_s = (my_struct_t *)realloc(*my_s, sizeof(my_struct_t)*num); 
for (i = 0; i < num; i++ ) {
(*my_s)[i].one = 1*i;
(*my_s)[i].two = 2*i;
}
printf("  (*my_s)[0] one: %d two: %dn", (*my_s)[0].one, (*my_s)[0].two);
}

你可以这样称呼它。

my_struct_t *my_structs = NULL;
...
update_my_struct(&my_structs, 4);

对于一次初始化来说,这将很好地工作,并且分配的结构数量由调用方保留。第二个调用将重新分配给新数量的结构,并从头开始重新初始化所有内容。为了简洁起见,我省略了realloc返回值检查。

这是在godbolt上测试的完整代码。

#include <stdlib.h>
#include <stdio.h>
typedef struct my_struct {
int one;
int two;
} my_struct_t;

void
update_my_struct(my_struct_t **my_s, int num)
{
int i;
*my_s = (my_struct_t *)realloc(*my_s, sizeof(my_struct_t)*num); 
for (i = 0; i < num; i++ ) {
(*my_s)[i].one = 1*i;
(*my_s)[i].two = 2*i;
}
}
my_struct_t *my_structs = NULL;
int main ()
{
int i;
update_my_struct(&my_structs, 4);
for (int i=0; i<4; i++)
printf("  (*my_s)[%d] one: %d two: %dn", i, my_structs[i].one, my_structs[i].two);
return 0;
}

检查您的realloc文档:内存必须先前已使用malloc/etc分配,否则结果未定义。

你的代码也不能真正工作——realloc在你的for循环中,等等。

试着运行valgrind——它会发现这个问题。

最新更新