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

时间:2015-05-26 02:44:25

标签: c file struct segmentation-fault records

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

我认为最好的方法是使用上面的字段定义一个struct Record,然后声明一个Record的数组,它包含与用户输入的记录一样多的记录。为了实现这一点,我将使用循环来获取每个记录的每个字段的输入,然后如果用户想要继续在Record数组中继续动态分配额外空间并继续直到用户输入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.");
    }
}
}

3 个答案:

答案 0 :(得分:3)

好吧,你得到一个段错误,因为你没有为records中的第一个实体分配内存。

所以要解决你需要

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

以这种方式表达: 你有records指向Records的指针。 当你做了

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

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

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

注意:如果size&gt; 1然后你应该做:

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

除此之外,您为什么选择Records **Arjun已经解释过,您应该使用Records *并修复realloc的新部分内存,因为如果realloc失败,它将返回NULL,并且在最糟糕的情况下,无论哪种方式都会导致内存泄漏或其他段错误 - 这对您的程序不利。

请参阅Arjun's post

答案 1 :(得分:2)

如果要为Record列表动态分配空间,您应该这样做:

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

这为sizeRecord s分配空间。

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

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 realloc函数

     

如果ptr是空指针,则realloc函数的行为类似于malloc   指定大小的函数。

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;
}

答案 2 :(得分:1)

作为Jonathan Leffler commented,但是declined从他的评论中回答:

  

请注意,行records[i++];会增加i,并且不会有任何其他用处。

also

  

另请注意,struct Record;行确实没有必要。唯一可能产生影响的是,如果要在函数作用域而不是文件作用域中定义相互递归的结构(并且此用法位于文件范围)。实际上,该行表示&#34;有一个类型struct Record&#34;,下一个代码块说&#34;有一个struct Record类型,这就是它已定义&#34;。

askedCool Guy说明其含义时,Jonathan said

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

如果没有struct A;行,a_ref元素将指向外部定义的类型struct A的结构,而不是相互递归的结构类型对。错误消息也可能很混乱!但是,重复使用这样的类型名称是一个坏主意。