简体   繁体   中英

How to stop reading a file once a certain string appears in c

I'm having trouble figuring out how to get my program to stop reading a file once the character string endOfFileMarker "***" is read given a file called "studentRecords.txt" with sample input as shown:

23456770,Mina,Porter,3,ENEE,114,CMSC,412,ENME,515  
23456790,Alex,Simpson,1,CMSC,412  
***

I'm reading the file using a while loop indicating that as long the file is not equal to the end of the file and if the first input from which I read is not equivalent to the endOfFileMarker. Right now the output doesn't stop reading at the endOfFileMarker and takes it as a new record in the structure with the given output of a display function (I realize the error with the 2nd record but that appears to be a problem with the display function and not the way I'm storing it):

23456770 Mina Porter    3        ENEE 114  CMSC 412  ENME 515

23456Alex Alex Simpson  1        CMSC 412

*** Alex Simpson        1        CMSC 412

I've tried using fgets earlier and creating an input buffer to read each line. But since there will be variable number of course names and course codes for each student, I found fscanf and using a while loop with control condition of !feof to work better. Kind of at a loss right now of how to stop storing into the structure once I hit the endOfFileMarker. If someone can please help me out with this, that would be very appreciated. My full code is written below.

#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;
}

I'll suggest that you read the file line by line using fgets and use sscanf to do the scanning. Then you can use strcmp to break the loop. Something like:

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
}

Note that fgets also stores the \\n character (aka newline) into the buffer so before doing the string compare, the \\n is stripped off (if present).

For your use case you don't really need to test whether the last character in the string is actually a \\n . Just make the buffer sufficiently large and always strip off the last character. In this way the code can be simplified to:

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
}

or an even more compact way (thanks to @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
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM