1

I have to write this code, I mean I should read from the file name of students and their mark, and then sort students by the grow of mark. Now I just want to output only mark. I want to display grades using structures. I don't know where the problem is.

text.file

Jon 3
Alina 5
Ron 1
#include <stdio.h>
#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include <stdlib.h>
int main()
{
    const int N = 3;
    int i = 0;
    struct student {
        char surname[50];
        int mark;
    };
    struct student PI1[N];

    char str[50];
    const char s[1] = " ";
    char* token;
    FILE* ptr;
    token = strtok(str, s);
    
    ptr = fopen("test.txt", "r");

    if (NULL == ptr) {
        printf("file can't be opened \n");
    }

    while (fgets(str, 50, ptr) != NULL){
        
        token = strtok(str, s);
        strcpy(PI1[i].surname, token);
        token = strtok(NULL, s);
        PI1[i].mark = atoi(token);
        i++;
    }
    fclose(ptr);
    printf("The marks is:\n");
    printf("%d %d %d", PI1[0].mark, PI1[1].mark, PI1[2].mark);
    return 0;
}
Steve Friedl
  • 3,929
  • 1
  • 23
  • 30
KonstantaV
  • 23
  • 4
  • 1
    Note that `strtok` requires the second argument to be a null terminated string. `const char s[1] = " ";` is not a null terminated string. It's an array with a `' '` in it, no `'\0'`. – Ted Lyngmo Nov 28 '22 at 22:41
  • Have you tried running your code line-by-line in a debugger while monitoring the control flow and the values of all variables, in order to determine in which line your program stops behaving as intended? If you did not try this, then you may want to read this: [What is a debugger and how can it help me diagnose problems?](https://stackoverflow.com/q/25385173/12149471) You may also want to read this: [How to debug small programs?](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/) – Andreas Wenzel Nov 28 '22 at 22:43

1 Answers1

2
  • You need to prevent the program from reading from the file pointer if opening the file fails:
    ptr = fopen("test.txt", "r");
    if (NULL == ptr) {
        perror("test.txt");
        return 1;               // this could be one way
    }
    
  • The second argument to strok should be a null terminated string. const char s[1] = " "; only has room for one character. No null terminator (\0). Make it:
    const char s[] = " "; // or const char s[2] = " "; or const char *s = " ";
    
  • Don't iterate out of bounds. You need to check so that you don't try to put data in PI1[N] etc.
    while (i < N && fgets(str, sizeof str, ptr) != NULL) {
    //     ^^^^^^^^
    
  • Check that strok actually returns a pointer to a new token. If it doesn't, the line you've read doesn't fulfill the requirements.
    while (i < N && fgets(str, sizeof str, ptr) != NULL) {
        token = strtok(str, s);
        if(!token) break;               // token check
        strcpy(PI1[i].surname, token);
        token = strtok(NULL, s);
        if (token)                      // token check
            PI1[i].mark = atoi(token);
        else
            break;
        i++;
    }
    
  • You could also skip the strcpy by reading directly into your struct student since char str[50]; has the same length as surname. str should probably be larger though, but for now:
    while (i < N && fgets(PI1[i].surname, sizeof PI1[i].surname, ptr) != NULL) {
        token = strtok(PI1[i].surname, s);
        if(!token) break;
        token = strtok(NULL, s);
        if (token)
            PI1[i].mark = atoi(token);
        else
            break;
        i++;
    }
    
  • Only print as many marks as you successfully read
    printf("The marks are:\n");
    for(int idx = 0; idx < i; ++idx) {
        printf("%d ", PI1[idx].mark);
    }
    putchar('\n');
    
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108