【发布时间】:2018-08-22 04:07:05
【问题描述】:
给定一个名为“studentRecords.txt”的文件,示例输入如下所示,一旦读取字符串 endOfFileMarker“***”,我无法弄清楚如何让我的程序停止读取文件:
23456770,Mina,Porter,3,ENEE,114,CMSC,412,ENME,515
23456790,Alex,Simpson,1,CMSC,412
***
我正在使用 while 循环读取文件,表明只要文件不等于文件末尾,并且我读取的第一个输入不等于 endOfFileMarker。现在,输出不会在 endOfFileMarker 处停止读取,并将其作为结构中的新记录,并具有显示函数的给定输出(我意识到第二条记录的错误,但这似乎是显示函数的问题而不是我存储它的方式):
23456770 Mina Porter 3 ENEE 114 CMSC 412 ENME 515
23456Alex Alex Simpson 1 CMSC 412
*** Alex Simpson 1 CMSC 412
我之前尝试过使用 fgets 并创建一个输入缓冲区来读取每一行。但是由于每个学生的课程名称和课程代码的数量都是可变的,我发现 fscanf 并使用带有 !feof 控制条件的 while 循环来更好地工作。一旦我点击 endOfFileMarker,现在有点不知如何停止存储到结构中。如果有人可以帮助我解决这个问题,那将非常感激。我的完整代码写在下面。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define filename "studentRecords.txt"
typedef struct courseInfo
{//structure defining courseInfo elements
int courseID;
char courseName[30];
}crsInfo;
typedef struct studentInfo
{//structure defining studentInfo elements
char studentID[9];
char firstName[20];
char lastName[25];
int coursesAttended;
crsInfo cInfo[10];
struct studentInfo * next;
}stdInfo;
stdInfo * firstStdNodePointer = NULL;
stdInfo * currentStdNodePointer = NULL;
void addStudentInfo(stdInfo newStd)
{
if (firstStdNodePointer == NULL) //Create the first course node
{
firstStdNodePointer = (stdInfo *) malloc(sizeof(stdInfo));
strcpy(firstStdNodePointer->studentID, newStd.studentID);
strcpy(firstStdNodePointer->firstName, newStd.firstName);
strcpy(firstStdNodePointer->lastName, newStd.lastName);
firstStdNodePointer->coursesAttended = newStd.coursesAttended;
for(int i = 0; i < newStd.coursesAttended; i++)
{
firstStdNodePointer->cInfo[i].courseID = newStd.cInfo[i].courseID;
strcpy(firstStdNodePointer->cInfo[i].courseName, newStd.cInfo[i].courseName);
}
firstStdNodePointer->next = NULL;
currentStdNodePointer = firstStdNodePointer;
}
else // add next course to the end of the course linked list.
{
// Go to the last Course in the list to get the course ID
stdInfo * newStdNodePointer = (stdInfo *) malloc(sizeof(stdInfo));
strcpy(newStdNodePointer->studentID, newStd.studentID);
strcpy(newStdNodePointer->firstName, newStd.firstName);
strcpy(newStdNodePointer->lastName, newStd.lastName);
newStdNodePointer->coursesAttended = newStd.coursesAttended;
for(int j = 0; j < newStd.coursesAttended; j++)
{
newStdNodePointer->cInfo[j].courseID = newStd.cInfo[j].courseID;
strcpy(newStdNodePointer->cInfo[j].courseName, newStd.cInfo[j].courseName);
}
newStdNodePointer->next = NULL;
currentStdNodePointer->next = newStdNodePointer; // Link previous node with newNode
currentStdNodePointer = currentStdNodePointer->next; // Make current node as previous node
}
}
void loadStudentInfo()
{
FILE * fptr = NULL;
fptr = fopen(filename, "r+");
const char endOfFileMarker[] = "***"; //marks the end of the student record list
if(fptr == NULL)
{
printf("File can not be opened\n");
}
stdInfo newStd;//defining a new struct studentInfo variable so I can pass to the addStudent function
//char line[100] = "";
//char * strPtr;
while (!feof(fptr) && strcmp(newStd.studentID, endOfFileMarker) != 0 )
{
fscanf(fptr, "%[^,],", newStd.studentID);
printf("%s\n", newStd.studentID);
fscanf(fptr, "%[^,],", newStd.firstName);
printf("%s\n", newStd.firstName);
fscanf(fptr, "%[^,],", newStd.lastName);
fscanf(fptr, "%i,", &newStd.coursesAttended);
for(int j = 0; j < newStd.coursesAttended; j++)
{//To read each courseName and ID, you need to go according to how many courses they entered
//because the amount of records in cInfo should correspond with how many pairs of courseName
//are entered into the file
fscanf(fptr, "%[^,],", newStd.cInfo[j].courseName);
fscanf(fptr, "%i,", &newStd.cInfo[j].courseID);
}
addStudentInfo(newStd);
}
fclose(fptr);
}
void displayCourseInfo()
{
printf("------------------------------------------------\n");
stdInfo * stdListPointer = firstStdNodePointer;
//start from the beginning
while(stdListPointer != NULL) {
printf("%s %s %s\t%i\t", stdListPointer->studentID, stdListPointer->firstName, stdListPointer->lastName, stdListPointer->coursesAttended);
for(int i = 0; i < stdListPointer->coursesAttended; i++)
{
printf(" %s %i ", stdListPointer->cInfo[i].courseName, stdListPointer->cInfo[i].courseID);
}
printf("\n");
stdListPointer = stdListPointer->next;
}
printf("------------------------------------------------\n");
}
void switchCaseMenu()
{
int selection;
int menuActive = 1;
while(menuActive)
{
printf("60-141 Bonus Assignment - Ben John\n");
printf("------------\n");
printf("1. Add a new student\n");
printf("2. Delete a student\n");
printf("3. Search for a student\n");
printf("4. Display current students\n");
printf("5. Save student information to file\n");
printf("6. Exit\n");
printf("Please enter a selection: ");
scanf("%i", &selection);
switch(selection)
{
case 1:
printf("~Selected - Add a new student~\n");
break;
case 2:
printf("~Selected - Delete a student~\n");
break;
case 3:
printf("~Selected - Search for s student~\n");
break;
case 4:
printf("~Selected - Display current students~\n");
displayCourseInfo();
break;
case 5:
printf("~Selected - Save student information to file~\n");
break;
case 6:
printf("~Selected - Exit~\n");
menuActive = 0;
break;
default:
printf("Invalid Input!\n");
}
}
printf("Goodbye!\n");
}
int main(void)
{
loadStudentInfo();
switchCaseMenu();
return 0;
}
【问题讨论】:
-
考虑使用 fgets() + sscanf() 而不是 fscanf() 的循环。它有助于逐行解析,不再需要 fot feof()。
-
strcmp(newStd.studentID, endOfFileMarker)处的未定义行为;newStd.studentID未初始化。 -
您使用
feof错误;见stackoverflow.com/questions/5431941/…。
标签: c linked-list structure