将数据写入动态数组时出现分段错误

Segmentation fault when writing data to a dynamic array

我的任务是编写一个文件,显示用户输入的未知数量的记录。每条记录都有以下字段:名字、姓氏、地址、城市、州、邮政编码和 Phone 号码。

我假设最好的方法是用上面的字段定义一个结构 Record,然后声明一个 Record 数组,其中包含与用户输入的记录一样多的记录。为了实现这一点,我将使用一个循环来获取每条记录的每个字段的输入,然后如果用户想继续在 Record 数组中动态分配一个额外的 space 并继续直到用户输入 no。我在行遇到访问冲突写入位置错误:

scanf("%s", records[i]->fname);

我的代码有什么问题?

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
struct Record;

struct Record
    {
        char fname[51];
        char lname[51];
        char address[51];
        char city[51];
        char state[51];
        int zipcode;
        int phoneNumber;
    };

int main()
{
    FILE *fileWriter;
    const char filename[] = "data.txt";
    char answer = 'y';
    int size = 1;
    int i = 0;
    struct Record **records;
    records = malloc(sizeof(*records)*(size));

    while(answer == 'y' || answer == 'Y')
    {
        printf("First Name: \n");
        scanf("%s", records[i]->fname);

        printf("Last Name: \n");
        scanf("%s", records[i]->lname);

        printf("Address: \n");
        scanf("%s", records[i]->address);

        printf("City: \n");
        scanf("%s", records[i]->city);

        printf("State: \n");
        scanf("%s", records[i]->state);

        printf("Zipcode: \n");
        scanf("%d", records[i]->zipcode);

        printf("Phone Number: \n");
        scanf("%d", records[i]->phoneNumber);
        //stores all record info

        printf("Are there anymore records? [y/n] ");
        answer = getchar();
        if(answer == 'y' || answer == 'Y')
        {
            size++;
            records[i++];
            printf("\n");
        }
        records = realloc(records,sizeof(*records)*(size));
    }

    //open file
    fileWriter = fopen(filename,"wb");

    if(fileWriter != NULL)
    {
        if(fwrite(records,sizeof(*records),size,fileWriter) != 1)
        {
            fprintf(stderr, "Failed to write to %s\n", filename);
            exit(1);
        }
        fclose(fileWriter);
    }
    else
    {
        printf("Error opening file.");
    }
}

编辑版本

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

struct Record
    {
        char fname[51];
        char lname[51];
        char address[51];
        char city[51];
        char state[51];
        int zipcode;
        int phoneNumber;
    };




int main()
{
    FILE *fileWriter;
    const char filename[] = "data.txt";
    char answer = 'y';
    int size = 1;
    int i = 0;
    struct Record *records = NULL;
    struct Record *records_temp;




    while(answer == 'y' || answer == 'Y')
    {
        struct Record *records_temp = realloc(records,(size)*sizeof(*records));

        if(records_temp == NULL)  
        {
            free(records); 

        }
        records = records_temp;
        printf("First Name: \n");
        scanf("%s", records[i].fname);
        printf("Last Name: \n");
        scanf("%s", records[i].lname);

        printf("Address: \n");
        scanf(" %[^\n]", records[i].address);

        printf("City: \n");
        scanf("%s", records[i].city);

        printf("State: \n");
        scanf("%s", records[i].state);

        printf("Zipcode: \n");
        scanf("%d", &records[i].zipcode);

        printf("Phone Number: \n");
        scanf("%d", &records[i].phoneNumber);
        //stores all record info

        printf("Are there anymore records? [y/n] ");
        answer = getchar();
        if(answer == 'y' || answer == 'Y')
        {
            size++;
            records[i++];
            printf("\n");
        }

        //open file

    fileWriter = fopen(filename,"wb");

    if(fileWriter != NULL)
    {
        if(fwrite(records,sizeof(*records),size,fileWriter) != 1)
        {
            fprintf(stderr, "Failed to write to %s\n", filename);
            exit(1);
        }
        fclose(fileWriter);
    }
    else
    {
        printf("Error opening file.");
    }
}
}

嗯,你会遇到段错误,因为你还没有为 records 中的第一个实体分配内存。

所以要解决这个问题,您需要

records[size-1] = malloc(sizeof(Records));

换句话说: 你有 records 是指向 Records 的指针。 你什么时候做的

records = malloc(sizeof(*records)*(size));

您实际上要求 size 指向 Records 的指针。 但这还不够,你需要分配另一块内存来存储实际的 Records 所以这就是为什么我们必须

records[size - 1] = malloc(sizeof(Records));

注意:如果size > 1 那么你应该这样做:

int i = 0;
for(;i < size; i++) {
    records[i] = malloc(sizeof(Records));
}

除此之外,你为什么要用Records **,正如Arjun已经解释的那样,你应该使用Records *并修复realloc的部分- ing 新内存,因为如果 realloc 失败,它会 returns NULL 并且在最坏的情况下你最终会出现内存泄漏或另一个段错误,无论哪种方式 - 这对你的程序都不利.

请看

当您想为 Record 的列表动态分配 space 时,您应该这样做:

struct Record *records;
records = malloc(size * sizeof(*records));

这为 sizeRecord 分配了 space。

要增加分配的大小,您应该:

struct Record *records_temp = realloc(records, newsize * sizeof(*records));

if (records_temp == NULL) {
    free(records);
    /* die with error -ENOMEM */
}

records = records_temp;

不要realloc指向同一个指针。它可能会导致您在失败时泄漏内存。

,您可以避免malloc()并在循环中仅使用realloc(),方法是最初为其提供NULL指针。

C 89 标准说:

4.10.3.4 The realloc function

If ptr is a null pointer, the realloc function behaves like the malloc function for the specified size.

struct Record *records = NULL;
struct Record *records_temp;
size = INITIAL_SIZE;

while (/* your condition */) {
    records_temp = realloc(records, size * sizeof(*records));

    if (records_temp == NULL) {
        free(records);
        /* die with error -ENOMEM */
    }

    records = records_temp;

    /* do stuff */

    size += SIZE_INCREMENT;
}

作为 Jonathan Leffler , but 根据他的评论做出回答:

Note that the line records[i++]; increments i and does nothing else useful.

Also note that the struct Record; line really isn't necessary. The only time it might make a difference is if you are defining mutually recursive structures in a function scope rather than at file scope (and this use is at file scope). As it is, the line says "there is a type struct Record", and the next block of code says "there is a type struct Record and this is how it is defined".

by Cool Guy to illustrate what was meant by that, Jonathan :

struct A { … };
struct B { … };
void f(void)
{
    struct A;
    struct B
    {
         …;
        struct A *a_ref;
        …
    };
    struct A
    {
        …;
        struct B *b_ref;
        …
    };
    …
}

Without the struct A; line, the a_ref element would point at a structure of the externally defined type struct A, not the mutually recursive pair of structure types. The error messages could be quite confusing too! However, reusing type names like this is a bad idea.