Maisie Farro
Maisie Farro

Reputation: 87

Problems with arrays within structures and files in C

I'm trying to store information of the name of a lesson and the day(s) I have that lesson using structures in C. Storing the name hasn't been an issue. The problem occurs when I try and store multiple days (weekdays as integers, ie. Monday = 1) in an array.

This is what I have:

#include<stdio.h>
#include<string.h>

struct lessons{

   char name[20];
   int day[3];

};

changelessons(){

    int i, k;
    struct lessons give[1], receive[1];

    FILE *fptr;

    fptr = fopen("lessons","wb");

    fflush(stdin);

    printf("\n\t ~ Change lessons ~");
    printf("\n\nWhat's the lesson called?: ");
    gets(give[0].name);

    printf("\nHow many days do you have it?\n");
    scanf("%d", &k);

    for(i = 0; i < k; i++); {  // Asks the weekday number for each day you have the lesson
        printf("What day is lesson %d?: ", i);
        scanf("%d", &give[0].day[i]);
    }

    fwrite(give, sizeof(give), 1, fptr);
    fclose(fptr);

    fptr = fopen("lessons", "rb");
    fread(receive, sizeof(receive), 1, fptr);

    printf("\n\t ~ Updated information: ~\n\nLesson name: %s\nDay: %d", receive[0].name, receive[0].day[1]);

    for(i = 1; i < k; i++); {  // Prints the extra weekdays if there are any
        printf(", day: %d", receive[0].day[i]);
    }

    printf("\n\n");

    fclose(fptr);
}

showlessons(){

    struct lessons give[1], receive[1];

    FILE *fptr;

    fptr = fopen("lessons", "rb");
    fread(receive, sizeof(receive), 1, fptr);

    printf("\t ~ Current information: ~ \n\nLesson name: %s\nDay: %d\n\n", receive[0].name, receive[0].day[0]);

}

int main(){

  showlessons();
  changelessons();

  return 0;
}

Also, in the first for loop it only ever loops once regardless of what k equals.

Thanks in advance for any help!

Upvotes: 1

Views: 49

Answers (2)

Pablo
Pablo

Reputation: 13580

nicomp pointed out the most obvious error.

But I would also like to point out a few issues I have with your code:

  1. fflush(stdin); This is wrong, undefined behaviour. fflush is used to flusg output streams, stdin is an input stream. See Using fflush(stdin).

    I know that in Windows fflush(stdin) clears the input buffer, but I strongly recommend not to use it, because you lose portability when relaying on features available only in one OS. If you don't care about portability, then use it. If you use that because scanf left stuff in the input buffer, use this instead:

    int c;
    while((c = getchar()) != '\n' && c != EOF);
    

    This is portable.

  2. Never ever use gets in 2018. gets is an unsafe, dangerous functions that has been deprecated in C99 and for good reasons: it doesn't take the size of the buffer into consideration and if the text entered is longer than the buffer can store, it will overflow the buffer. This is an accident waiting to happen. So, never ever use gets again. Use fgets instead and if you don't want to have a newline, you can remove it:

    fgets(give[0].name, sizeof give[0].name, stdin);
    give[0].name[sizeof(give[0].name) - 1] = 0; // remove possible newline
    
  3. Why do you declare an array of struct lessons with dimension 1? What's the point? You don't need an array for this. You could write it like this:

    struct lessons give, receive;
    ...
    
    printf("\n\nWhat's the lesson called?: ");
    fgets(give.name, sizeof give.name, stdin);
    give.name[strcspn(give.name, "\n")] = 0;
    
    ...
    
    fwrite(&give, sizeof give, 1, fptr);
    fclose(fptr);
    
    ...
    
    fptr = fopen("lessons", "rb");
    fread(&receive, sizeof receive, 1, fptr);
    

    Also don't forget to check the return values of fwrite and fread.

  4. Check the return value of fopen, if it returns NULL, you cannot use fread or fwrite. Print an error value and return/exit.

  5. stdout is buffered and when you write to it with printf, it won't necessarily print the characters on screen right away. An exception is when stdout is connected to a terminal and a newline is written with printf. For user interaction this is great, because the user would see the output immediately. That's why most people print a newline along the text.

    If you don't do that but you still want that the user immediately sees the output, then this time you should use fflush:

     printf("What day is lesson %d?: ", i);
     fflush(stdout);
     scanf("%d", &give[0].day[i]);
    

    I don't know if there's a guarantee that scanf flushes stdout when it's connected to a terminal, regardless it is good practice to use fflush(stdout) when you don't print a newline at the end.

Upvotes: 1

nicomp
nicomp

Reputation: 4647

for(i = 0; i < k; i++);

should be

for(i = 0; i < k; i++)

The extra semi colon is a problem. Your loop code is not part of a loop. The semi colon terminates the loop.

Upvotes: 2

Related Questions