0

Noob programmer here...so please bear with me. I'm trying to pass an existing text file into an array however once my main Menu loads the information that once existed in that file goes away, even if I don't make any changes. it is just not keeping the information. The Program is supposed to allow the user to either create a new file or update and/or load an existing file. Any ideas on how to fix this issue? Thank you all!

char fileName[20] = "";

void loadEmployee()
{
    FILE* fPtr;
    char singleLine[150];

    if (strcmp(fileName, "") == 0)
    {
        printf("\nWhat's the name of the file? ");
        scanf_s("%s", fileName, 20);
    }

    fopen_s(&fPtr, fileName, "r");

    while (!feof(fPtr))
    {
        fgets(singleLine, 150, fPtr);
        puts(singleLine);
    }
    fclose(fPtr);
}

void saveEmployee()
{
    FILE* fPtr;

    if (strcmp(fileName, "") == 0)
    {
        printf("\nWhat's the name of the file? ");
        scanf_s("%s", fileName, 20);
    }

    fopen_s(&fPtr, fileName, "w");

        for (int i = 0; i < numEmps; i++)
        {
            fprintf(fPtr, "%s %f %f\n", emps[i].emps.name, 
                        emps[i].emps.rate, emps[i].emps.hours);
        }
        fclose(fPtr);
}


void loadMenu()
{
    int i = 0;

    printf("1. Load from a file  \n");
    printf("2. Keyboard \n");
    scanf_s("%d", &choice);

    switch (choice)
    {
    case 1: loadEmployee();
        break;

    default:
        break;
    }

        do
        {
            printf("\nMAIN MENU\n");
            printf("1.Add Employee\n");
            printf("2.Edit Employee\n");
            printf("3.Print Employee\n");
            printf("4.Print ALL employees\n");
            printf("5.Exit\n");
            scanf_s("%d", &choice);

            switch (choice)
            {
            case 1: NameInput();
                break;
            case 2: printf("Choose employee: \n");
                for (int i = 0; i < numEmps; i++)
               {
                printf("%d. %s \n", i + 1, 
                                    emps[i].emps.name);
               }
                scanf_s("%d", &choice);

                empUpdate(choice - 1);

                break;

            case 3: printf("Choose employee: \n\n");
                for (int i = 0; i < numEmps; i++)
                {
                printf("%d) %s \n", i + 1, 
                                    emps[i].emps.name);
                }

                scanf_s("%d", &choice);
                printf("%s \n", emps[choice - 
                                1].emps.name);
                printf("%.2f \n", emps[choice - 
                                1].emps.hours);
                printf("%.2f \n", emps[choice - 
                                1].emps.rate);

                break;

            case 4: PayOutput();
                break;

            case 5: printf("Quitting program!");
                saveEmployee();
                return;

            default: printf("Invalid choice try again \n\n");
                break;
            }
        } while (choice != 5);
}  

int main()
{
    struct information empsi[20];
    loadMenu();
}

2 Answers2

1

Your function loadEmployee only writes to a char[] that is local to the function (which means it’s discarded at the end).

When the program exits, you « save » the employee by reopening your file in write mode, which clears it, and what follows probably doesn’t do much, so the file remains empty.

Try actually returning or storing the data from the file outside your function so it can be reused later.

hugo
  • 3,067
  • 2
  • 12
  • 22
0

As @hugo said, the program reads the file but doesn't store the contents. This means emps will be empty. When you quit you open the file for writing deleting its contents. Beause emps is empty, nothing is written.

This can be solved by reading similar to how you're writing. I don't know exactly what emps looks like, but something like this.

for( numEmps = 1; fgets(singleLine, 150, fPtr); numEmps++ ) {
    // I'm assuming emps is preallocated.
    struct Employee emp = emps[numEmps-1];
    sscanf(singleLine, "%80s %f %f",
        emp.emps.name,
        &emp.emps.rate,
        &emp.emps.hours
    );
}

Notice rather than using feof I'm looking at the return value of fgets. As Edward Karak mentioned, when reading lines don't check for eof.


Other issues in the code...

You're not checking whether your files actually opened.

    fopen_s(&fPtr, fileName, "r");
    if( !fPtr ) {
        perror(fileName);
        exit(1);
    }

The code uses a lot of global variables. This leads to hard to understand code as anything can change those globals at any time. Instead, take advantage of function arguments and return values. Then you can completely understand a function just by looking at it.

For example, loadEmployee should take the struct to populate and the filename to read from, then return how many it read. saveEmployee is similar.

int loadEmployee(struct Employee *emps, char *fileName) {
    ...
    return numEmps;
}

void saveEmployee(struct Employee *emps, char *fileName) {
    ...
}

Neither should be in charge of asking the user for the filename. This should be handled by the caller. Functions should do one thing; it makes them simpler and more flexible.

We can move the logic to get the filename into a function. Rather than using a global, we use a static variable. This variable is still local to the function, but does not get reset. getFileName remembers the filename.

char *getFileName() {
    static char fileName[80] = "";

    if (strcmp(fileName, "") == 0)
    {
        printf("\nWhat's the name of the file? ");
        scanf("%20s", fileName);
    }

    return fileName;
}

...
switch(choice) {
    case 1:
        numEmps = loadEmployee(emps, getFileName());
        break;
    ...
    case 5:
        printf("Quitting program!");
        saveEmployee(emps, getFileName());
        return;
}
...

These are not the source of your problem, but they will help structure your code so it's easier to understand and debug.

Schwern
  • 153,029
  • 25
  • 195
  • 336
  • Thank you for all the feedback. I'll definitely implement this. Now, I tried to add your piece of code but the `emp` is not working, it throws this error **incomplete type is not allowed**. shouldn't I add this to the index? like I used with `saveEmployee`? `fprintf(fPtr, "%s %f %f\n", emps[i].emps.name, emps[i].emps.rate, emps[i].emps.hours);` however, when I tried adding this now it has 2 errors and one of the is that **i** is undefined. so ....a bit frustrating. lol – chessnotcheckers Aug 05 '19 at 04:56
  • `incomplete type is not allowed` is a C++ error. Possibly because `struct Employee` is just a guess at the type of `emps`; you'll have to fill in the correct type. `struct Employee emp = emps[numEmps-1];` is there to avoid repeating `emps[numEmps-1]` like you're repeating `emps[i]`. There is no `i` in the loop I wrote, I used `numEmps` instead to count up the number of emps read in. You won't be able to just cut & paste the code in, your question left out too many details. You'll have to adapt what I've written. – Schwern Aug 05 '19 at 05:14