在主函数中访问动态数组中的记录时发生段错误,但在包含函数中没有

Segmentation fault occurs when accessing records in a dynamic array in the main function, but not in the included function

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

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: %d\n", 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 = %d\n", 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,段错误发生在 main,所以我很困惑为什么动态数组可以在 included 函数中访问,但在 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: %d\n", my_s[3].one, my_s[3].two);
}

段错误仍然存​​在:

$ ./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
...

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

您的代码也没有真正起作用 - realloc 在您的 for 循环中,等等。

然后尝试 运行 valgrind - 它会发现这个问题。

这是我在评论中暗示的内容。这假设 *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: %d\n", (*my_s)[0].one, (*my_s)[0].two);
}

你可以这样调用它。

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

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

这里是在 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: %d\n", i, my_structs[i].one, my_structs[i].two);
        return 0;
    }