将数据写入动态数组时出现分段错误
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));
这为 size
个 Record
分配了 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.
我的任务是编写一个文件,显示用户输入的未知数量的记录。每条记录都有以下字段:名字、姓氏、地址、城市、州、邮政编码和 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));
这为 size
个 Record
分配了 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
Note that the line
records[i++];
incrementsi
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 typestruct Record
", and the next block of code says "there is a typestruct Record
and this is how it is defined".
当
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, thea_ref
element would point at a structure of the externally defined typestruct 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.