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