我的任务是写一个文件,显示用户输入的未知数量的记录。每条记录都有以下字段:名字,姓氏,地址,城市,州,邮政编码和电话号码。
我认为最好的方法是使用上面的字段定义一个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.");
}
}
}
答案 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));
这为size
个Record
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;。
当asked按Cool 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
的结构,而不是相互递归的结构类型对。错误消息也可能很混乱!但是,重复使用这样的类型名称是一个坏主意。