【问题标题】:How to stop reading a file once a certain string appears in c一旦某个字符串出现在c中,如何停止读取文件
【发布时间】: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


【解决方案1】:

我建议您使用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] = '\0'; // 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] = '\0';         // 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")] = '\0';    // Strip \n character if present
    if (strcmp(buffer, "***") == 0) break;   // Stop reading

    // use sscanf on buffer to find the individual fields in the line
}

【讨论】:

  • 您也可以使用buffer[strcspn(buffer, "\n")] = '\0';,这总是安全的。
  • 所以我尝试使用您使用的 while(fgets) 的第二种变体。我想我不了解 sscanf 工作原理的本质,因为我首先使用一个 sscanf 行来读取每一行,直到 courseAttended 行,因为我需要一种方法来读取可变数量的 courseNames 和 courseID,所以我使用值of courseAttended 读取每行的 courseNames 和 courseIDs。该文件被正确读取,但仅限于并包括 courseAttended 变量。它开始在 courseName 和 coursed 变量中重复读取 studentID。我需要 fseek 吗?
猜你喜欢
  • 2014-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-26
  • 1970-01-01
  • 2015-08-07
相关资源
最近更新 更多