链接列表和 fscanf
Linked Lists and fscanf
我正在尝试创建一个链表来存储来自文本文件的输入。
我可以获得第一组信息,但是当我获得后续信息时,出现段错误。
请告诉我我做错了什么。
这是我的全部代码
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int CourseID;
char CourseName[30];
} courseInfo;
struct StudentInfo{
char StudentID[9];
char FirstName[20];
char LastName[25];
int Courses;
courseInfo CourseInfo[10];
struct StudentInfo *next;
};
typedef struct StudentInfo studentInfo;
typedef studentInfo *ListPtr;
studentInfo LoadFile(studentInfo *RootPtr);
void PrintStruct(studentInfo *startPtr);
int main()
{
studentInfo studentList[100];
ListPtr HeadPtr = NULL;
printf("Loading File...\n");
LoadFile(HeadPtr);
printf("Load Success\n");
PrintStruct(studentList);
printf("AfterPrint\n");
return 0;
}
studentInfo LoadFile( studentInfo *RootPtr)
{
FILE * ptrFile;
ListPtr NodePtr = malloc(sizeof (studentInfo));
ListPtr curr;
int counter, i=0;
ptrFile = fopen("studentInfo.txt", "r");
if( ptrFile == NULL)
printf("Open Unsuccessful\n");
fscanf(ptrFile,"%s", NodePtr->StudentID);
printf("%s\n", NodePtr->StudentID);
fscanf(ptrFile,"%s", NodePtr->FirstName);
printf("%s\n", NodePtr->FirstName);
fscanf(ptrFile,"%s", NodePtr->LastName);
printf("%s\n", NodePtr->LastName);
fscanf(ptrFile,"%d", &(NodePtr->Courses));
printf("%d\n", NodePtr->Courses);
for(counter = 0; counter <= NodePtr->Courses; counter++)
{
fscanf(ptrFile,"%s", NodePtr->CourseInfo[counter].CourseName);
printf("%s ", NodePtr->CourseInfo[counter].CourseName);
fscanf(ptrFile,"%d", &(NodePtr->CourseInfo[counter].CourseID));
printf("%d\n", NodePtr->CourseInfo[counter].CourseID);
}
curr = RootPtr;
NodePtr->next = NULL;
RootPtr = NodePtr;
NodePtr = NodePtr -> next;
while( strcmp("***", NodePtr->StudentID) !=0 )
{
fscanf(ptrFile,"%s", NodePtr->StudentID);
printf("%s\n", NodePtr->StudentID);
fscanf(ptrFile,"%s", NodePtr->FirstName);
printf("%s\n", NodePtr->FirstName);
fscanf(ptrFile,"%s", NodePtr->LastName);
printf("%s\n", NodePtr->LastName);
fscanf(ptrFile,"%d", &(NodePtr->Courses));
printf("%d\n", NodePtr->Courses);
for(counter = 0; counter <= NodePtr->Courses; counter++)
{
fscanf(ptrFile,"%s", NodePtr->CourseInfo[counter].CourseName);
printf("%s ", NodePtr->CourseInfo[counter].CourseName);
fscanf(ptrFile,"%d",&(NodePtr->CourseInfo[counter].CourseID));
printf("%d\n", NodePtr->CourseInfo[counter].CourseID);
}
NodePtr = NodePtr->next;
}
fclose(ptrFile);
return *NodePtr;
}
void PrintStruct(studentInfo *startPtr)
{
int i;
ListPtr begin;
printf("In print\n");
for( begin = startPtr; begin->next != NULL; begin=begin->next)
{
printf("%s\n", begin->StudentID);
printf("%s\n", begin->FirstName);
printf("%s\n", begin->LastName);
printf("%d\n", begin->Courses);
for(i = 0; i <= begin->Courses; i++)
{
printf("%s", begin->CourseInfo[i].CourseName);
printf("%d\n", begin->CourseInfo[i].CourseID);
}
}
return;
}
`
我的文本文件是:
111111111
丽莎
搬运工
3个
电气工程 114
中国移动412
恩美 515
333333333
亚历克斯
辛普森
1个
中国移动 412
并且最多只会打印“333333333”
后跟一个“0”,然后是一个段错误。
读取文件时存在一些问题,如 valgrind 所强调:
$ valgrind ./a.out
==4662== Memcheck, a memory error detector
==4662== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==4662== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==4662== Command: ./a.out
==4662==
Loading File...
111111111
Lisa
Porter
3
ENEE 114
CMSC 412
ENME 515
==4662== Conditional jump or move depends on uninitialised value(s)
==4662== at 0x4E7BA91: vfprintf (vfprintf.c:1635)
==4662== by 0x4E855C8: printf (printf.c:33)
==4662== by 0x400A09: LoadFile (bar.c:66)
==4662== by 0x400784: main (bar.c:30)
==4662==
==4662== Use of uninitialised value of size 8
==4662== at 0x4E7B0FB: _itoa_word (_itoa.c:179)
==4662== by 0x4E7EB02: vfprintf (vfprintf.c:1635)
==4662== by 0x4E855C8: printf (printf.c:33)
==4662== by 0x400A09: LoadFile (bar.c:66)
==4662== by 0x400784: main (bar.c:30)
==4662==
==4662== Conditional jump or move depends on uninitialised value(s)
==4662== at 0x4E7B105: _itoa_word (_itoa.c:179)
==4662== by 0x4E7EB02: vfprintf (vfprintf.c:1635)
==4662== by 0x4E855C8: printf (printf.c:33)
==4662== by 0x400A09: LoadFile (bar.c:66)
==4662== by 0x400784: main (bar.c:30)
==4662==
==4662== Conditional jump or move depends on uninitialised value(s)
==4662== at 0x4E7EB4E: vfprintf (vfprintf.c:1635)
==4662== by 0x4E855C8: printf (printf.c:33)
==4662== by 0x400A09: LoadFile (bar.c:66)
==4662== by 0x400784: main (bar.c:30)
==4662==
==4662== Conditional jump or move depends on uninitialised value(s)
==4662== at 0x4E7BB5C: vfprintf (vfprintf.c:1635)
==4662== by 0x4E855C8: printf (printf.c:33)
==4662== by 0x400A09: LoadFile (bar.c:66)
==4662== by 0x400784: main (bar.c:30)
==4662==
==4662== Conditional jump or move depends on uninitialised value(s)
==4662== at 0x4E7BBDF: vfprintf (vfprintf.c:1635)
==4662== by 0x4E855C8: printf (printf.c:33)
==4662== by 0x400A09: LoadFile (bar.c:66)
==4662== by 0x400784: main (bar.c:30)
==4662==
333333333 0
==4662== Invalid read of size 1
==4662== at 0x4C2D1D3: strcmp (vg_replace_strmem.c:755)
==4662== by 0x400A5A: LoadFile (bar.c:74)
==4662== by 0x400784: main (bar.c:30)
==4662== Address 0x0 is not stack'd, malloc'd or (recently) free'd
更具体地说,我建议您使用 scanf
和 assert
来确保读取一个值(如果没有可读取的内容,scanf 可能 return 而无需设置变量) :
assert(1 == fscanf(ptrFile,"%s", NodePtr->CourseInfo[counter].CourseName));
printf("%s ", NodePtr->CourseInfo[counter].CourseName);
assert(1 == fscanf(ptrFile,"%d", &(NodePtr->CourseInfo[counter].CourseID)));
printf("%d\n", NodePtr->CourseInfo[counter].CourseID);
(另外,包括 assert.h
)
现在,如果你执行你的程序,你会得到:
$ valgrind ./a.out
==4750== Memcheck, a memory error detector
==4750== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==4750== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==4750== Command: ./a.out
==4750==
Loading File...
111111111
Lisa
Porter
3
ENEE 114
CMSC 412
ENME 515
a.out: bar.c:66: studentInfo LoadFile(studentInfo *): Assertion `1 == fscanf(ptrFile,"%d", &(NodePtr->CourseInfo[counter].CourseID))' failed.
这确实是问题所在:您的程序试图在文件结束后读取。
对扫描到不足缓冲区的字符串输入没有限制。
以下尝试将“111111111”存储到 char
数组中。第一个是 9 char
,其中 fscanf(ptrFile,"%s",...)
扫描并存储到 NodePtr->StudentID
- 一个 9 char
数组。然后 fscanf
附加一个 '[=18=]'
并在调用未定义行为 (UB) 的数组外写入。
struct StudentInfo{
char StudentID[9];
...
// My text file is : 111111111 Lisa Porter 3 ENEE 114 CMSC 4
fscanf(ptrFile,"%s", NodePtr->StudentID);
代码应该 1) 分配足够的 space 2) 使用 "%9s"
限制输入长度和 3) 检查 fscanf()
结果。更好:
struct StudentInfo{
// Enough space for 9 char and [=11=]
char StudentID[9+1];
...
// add if and ------------v
if (1 != fscanf(ptrFile,"%9s", NodePtr->StudentID))
Handle_Error();
我正在尝试创建一个链表来存储来自文本文件的输入。 我可以获得第一组信息,但是当我获得后续信息时,出现段错误。
请告诉我我做错了什么。
这是我的全部代码
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int CourseID;
char CourseName[30];
} courseInfo;
struct StudentInfo{
char StudentID[9];
char FirstName[20];
char LastName[25];
int Courses;
courseInfo CourseInfo[10];
struct StudentInfo *next;
};
typedef struct StudentInfo studentInfo;
typedef studentInfo *ListPtr;
studentInfo LoadFile(studentInfo *RootPtr);
void PrintStruct(studentInfo *startPtr);
int main()
{
studentInfo studentList[100];
ListPtr HeadPtr = NULL;
printf("Loading File...\n");
LoadFile(HeadPtr);
printf("Load Success\n");
PrintStruct(studentList);
printf("AfterPrint\n");
return 0;
}
studentInfo LoadFile( studentInfo *RootPtr)
{
FILE * ptrFile;
ListPtr NodePtr = malloc(sizeof (studentInfo));
ListPtr curr;
int counter, i=0;
ptrFile = fopen("studentInfo.txt", "r");
if( ptrFile == NULL)
printf("Open Unsuccessful\n");
fscanf(ptrFile,"%s", NodePtr->StudentID);
printf("%s\n", NodePtr->StudentID);
fscanf(ptrFile,"%s", NodePtr->FirstName);
printf("%s\n", NodePtr->FirstName);
fscanf(ptrFile,"%s", NodePtr->LastName);
printf("%s\n", NodePtr->LastName);
fscanf(ptrFile,"%d", &(NodePtr->Courses));
printf("%d\n", NodePtr->Courses);
for(counter = 0; counter <= NodePtr->Courses; counter++)
{
fscanf(ptrFile,"%s", NodePtr->CourseInfo[counter].CourseName);
printf("%s ", NodePtr->CourseInfo[counter].CourseName);
fscanf(ptrFile,"%d", &(NodePtr->CourseInfo[counter].CourseID));
printf("%d\n", NodePtr->CourseInfo[counter].CourseID);
}
curr = RootPtr;
NodePtr->next = NULL;
RootPtr = NodePtr;
NodePtr = NodePtr -> next;
while( strcmp("***", NodePtr->StudentID) !=0 )
{
fscanf(ptrFile,"%s", NodePtr->StudentID);
printf("%s\n", NodePtr->StudentID);
fscanf(ptrFile,"%s", NodePtr->FirstName);
printf("%s\n", NodePtr->FirstName);
fscanf(ptrFile,"%s", NodePtr->LastName);
printf("%s\n", NodePtr->LastName);
fscanf(ptrFile,"%d", &(NodePtr->Courses));
printf("%d\n", NodePtr->Courses);
for(counter = 0; counter <= NodePtr->Courses; counter++)
{
fscanf(ptrFile,"%s", NodePtr->CourseInfo[counter].CourseName);
printf("%s ", NodePtr->CourseInfo[counter].CourseName);
fscanf(ptrFile,"%d",&(NodePtr->CourseInfo[counter].CourseID));
printf("%d\n", NodePtr->CourseInfo[counter].CourseID);
}
NodePtr = NodePtr->next;
}
fclose(ptrFile);
return *NodePtr;
}
void PrintStruct(studentInfo *startPtr)
{
int i;
ListPtr begin;
printf("In print\n");
for( begin = startPtr; begin->next != NULL; begin=begin->next)
{
printf("%s\n", begin->StudentID);
printf("%s\n", begin->FirstName);
printf("%s\n", begin->LastName);
printf("%d\n", begin->Courses);
for(i = 0; i <= begin->Courses; i++)
{
printf("%s", begin->CourseInfo[i].CourseName);
printf("%d\n", begin->CourseInfo[i].CourseID);
}
}
return;
}
`
我的文本文件是: 111111111 丽莎 搬运工 3个 电气工程 114 中国移动412 恩美 515 333333333 亚历克斯 辛普森 1个 中国移动 412
并且最多只会打印“333333333” 后跟一个“0”,然后是一个段错误。
读取文件时存在一些问题,如 valgrind 所强调:
$ valgrind ./a.out
==4662== Memcheck, a memory error detector
==4662== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==4662== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==4662== Command: ./a.out
==4662==
Loading File...
111111111
Lisa
Porter
3
ENEE 114
CMSC 412
ENME 515
==4662== Conditional jump or move depends on uninitialised value(s)
==4662== at 0x4E7BA91: vfprintf (vfprintf.c:1635)
==4662== by 0x4E855C8: printf (printf.c:33)
==4662== by 0x400A09: LoadFile (bar.c:66)
==4662== by 0x400784: main (bar.c:30)
==4662==
==4662== Use of uninitialised value of size 8
==4662== at 0x4E7B0FB: _itoa_word (_itoa.c:179)
==4662== by 0x4E7EB02: vfprintf (vfprintf.c:1635)
==4662== by 0x4E855C8: printf (printf.c:33)
==4662== by 0x400A09: LoadFile (bar.c:66)
==4662== by 0x400784: main (bar.c:30)
==4662==
==4662== Conditional jump or move depends on uninitialised value(s)
==4662== at 0x4E7B105: _itoa_word (_itoa.c:179)
==4662== by 0x4E7EB02: vfprintf (vfprintf.c:1635)
==4662== by 0x4E855C8: printf (printf.c:33)
==4662== by 0x400A09: LoadFile (bar.c:66)
==4662== by 0x400784: main (bar.c:30)
==4662==
==4662== Conditional jump or move depends on uninitialised value(s)
==4662== at 0x4E7EB4E: vfprintf (vfprintf.c:1635)
==4662== by 0x4E855C8: printf (printf.c:33)
==4662== by 0x400A09: LoadFile (bar.c:66)
==4662== by 0x400784: main (bar.c:30)
==4662==
==4662== Conditional jump or move depends on uninitialised value(s)
==4662== at 0x4E7BB5C: vfprintf (vfprintf.c:1635)
==4662== by 0x4E855C8: printf (printf.c:33)
==4662== by 0x400A09: LoadFile (bar.c:66)
==4662== by 0x400784: main (bar.c:30)
==4662==
==4662== Conditional jump or move depends on uninitialised value(s)
==4662== at 0x4E7BBDF: vfprintf (vfprintf.c:1635)
==4662== by 0x4E855C8: printf (printf.c:33)
==4662== by 0x400A09: LoadFile (bar.c:66)
==4662== by 0x400784: main (bar.c:30)
==4662==
333333333 0
==4662== Invalid read of size 1
==4662== at 0x4C2D1D3: strcmp (vg_replace_strmem.c:755)
==4662== by 0x400A5A: LoadFile (bar.c:74)
==4662== by 0x400784: main (bar.c:30)
==4662== Address 0x0 is not stack'd, malloc'd or (recently) free'd
更具体地说,我建议您使用 scanf
和 assert
来确保读取一个值(如果没有可读取的内容,scanf 可能 return 而无需设置变量) :
assert(1 == fscanf(ptrFile,"%s", NodePtr->CourseInfo[counter].CourseName));
printf("%s ", NodePtr->CourseInfo[counter].CourseName);
assert(1 == fscanf(ptrFile,"%d", &(NodePtr->CourseInfo[counter].CourseID)));
printf("%d\n", NodePtr->CourseInfo[counter].CourseID);
(另外,包括 assert.h
)
现在,如果你执行你的程序,你会得到:
$ valgrind ./a.out
==4750== Memcheck, a memory error detector
==4750== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==4750== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==4750== Command: ./a.out
==4750==
Loading File...
111111111
Lisa
Porter
3
ENEE 114
CMSC 412
ENME 515
a.out: bar.c:66: studentInfo LoadFile(studentInfo *): Assertion `1 == fscanf(ptrFile,"%d", &(NodePtr->CourseInfo[counter].CourseID))' failed.
这确实是问题所在:您的程序试图在文件结束后读取。
对扫描到不足缓冲区的字符串输入没有限制。
以下尝试将“111111111”存储到 char
数组中。第一个是 9 char
,其中 fscanf(ptrFile,"%s",...)
扫描并存储到 NodePtr->StudentID
- 一个 9 char
数组。然后 fscanf
附加一个 '[=18=]'
并在调用未定义行为 (UB) 的数组外写入。
struct StudentInfo{
char StudentID[9];
...
// My text file is : 111111111 Lisa Porter 3 ENEE 114 CMSC 4
fscanf(ptrFile,"%s", NodePtr->StudentID);
代码应该 1) 分配足够的 space 2) 使用 "%9s"
限制输入长度和 3) 检查 fscanf()
结果。更好:
struct StudentInfo{
// Enough space for 9 char and [=11=]
char StudentID[9+1];
...
// add if and ------------v
if (1 != fscanf(ptrFile,"%9s", NodePtr->StudentID))
Handle_Error();