一旦读取字符串 endOfFileMarker "***",我无法弄清楚如何让我的程序停止读取文件,给定一个名为"studentRecords.txt"的文件,示例输入如下所示:
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 循环来更好地工作。现在有点不知所措,一旦我点击 end FileMarker,如何停止存储到结构中。如果有人能帮我解决这个问题,那将不胜感激。我的完整代码写在下面。
#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 openedn");
}
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("%sn", newStd.studentID);
fscanf(fptr, "%[^,],", newStd.firstName);
printf("%sn", 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 %st%it", 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 Johnn");
printf("------------n");
printf("1. Add a new studentn");
printf("2. Delete a studentn");
printf("3. Search for a studentn");
printf("4. Display current studentsn");
printf("5. Save student information to filen");
printf("6. Exitn");
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
进行扫描。然后,您可以使用strcmp
来打破循环。像这样:
while(fgets(buffer, SIZE_OF_BUFFER, fileptr))
{
size_t len = strlen(buffer);
if (len > 0 && buffer[len-1] == 'n') buffer[len - 1] = ' '; // Strip n if present
if (strcmp(buffer, "***") == 0) break; // Stop reading
// use sscanf on buffer to find the individual fields in the line
}
请注意,fgets
还将n
字符(也称为换行符(存储到buffer
中,因此在执行字符串比较之前,n
被剥离(如果存在(。
对于您的用例,您实际上不需要测试字符串中的最后一个字符是否实际上是n
。只需使缓冲区足够大,并始终去除最后一个字符即可。通过这种方式,代码可以简化为:
while(fgets(buffer, SIZE_OF_BUFFER, fileptr))
{
size_t len = strlen(buffer);
if (len) buffer[len - 1] = ' '; // Strip last character
if (strcmp(buffer, "***") == 0) break; // Stop reading
// use sscanf on buffer to find the individual fields in the line
}
或者更紧凑的方式(感谢@melpomene(:
while(fgets(buffer, SIZE_OF_BUFFER, fileptr))
{
buffer[strcspn(buffer, "n")] = ' '; // Strip n character if present
if (strcmp(buffer, "***") == 0) break; // Stop reading
// use sscanf on buffer to find the individual fields in the line
}