0

The requirements:

Write a C program that executes the following tasks in order:

  • Initially displays the content of the file in the execution window
  • Ask the user for an ID, search for the ID in the file then display a message (in the execution window) in the following format: Student with ID:……… corresponds to ………………. who is majoring in……………… As you print the name of the student in the output, do not print ‘_’!

The problem: It only outputs the first line (aka first student info) from the file, and it does not even ask for the student ID afterward.

The code:

#include <stdio.h>
#include <string.h>
typedef struct {
    int ID;
    char Last_name[30], First_name[30], major[30];
} Class;
int search_for_student(int ID_to_search, Class students[22]) {
    int i;
    for (i = 0; i < 22; i++) {
        if (students[i].ID == ID_to_search)
            return i;
    }
    return -101;
}
void main(void) {
    char line[100];
    int  ID_to_search, i, index, j;
    Class students[22];
    FILE* infp;
    infp = fopen("Section_06.txt", "r");
    if (infp == NULL) {
        printf("File unexistant!\n");
    }
    else {
        for (i = 0; i < 22; i++) {
            fscanf(infp, "%d", students[i].ID);
            printf("%d", students[i].ID);
            fscanf(infp, "%s", students[i].Last_name);
            for (j = 0; j < strlen(students[i].Last_name); j++) {
                if (students[i].Last_name[j] == '_')
                    students[i].Last_name[j] = ' ';
            }
            printf("%s", students[i].Last_name);
            fscanf(infp, "%s", students[i].First_name);
            for (j = 0; j < strlen(students[i].First_name); j++) {
                if (students[i].First_name[j] == '_')
                    students[i].First_name[j] = ' ';
            }
            printf("%s", students[i].First_name);
            fgets(students[i].major, 30, infp);
            printf("%s", students[i].major);
        }
        printf("Enter an ID: ");
        scanf("%d", &ID_to_search);
        index = search_for_student(ID_to_search, students);
        if (index == -101)
            printf("Student not found!");
        else {
            printf("Student with ID: %d corresponds to %s %s who is majoring in %s.", students[index].ID, students[index].First_name, students[index].Last_name, students[index].major);
        }
    }
    fclose(infp);
}
  • 3
    Please _edit_ your question and post some representative input data in a separate code block here. – Craig Estey Feb 21 '21 at 22:44
  • I would start by learning a serviceable way to read a file. See [here](https://stackoverflow.com/questions/3463426/in-c-how-should-i-read-a-text-file-and-print-all-strings) for a representative example. – Robert Harvey Feb 21 '21 at 22:46
  • regarding: `void main(void) {` if your compiler is allowing this statement, then it is a non-compilant compiler! There are only two valid signatures for `main()` They are: `int main( void )` and `int main( int argc, char *argv[] )` – user3629249 Feb 22 '21 at 16:37
  • regarding statements like: `for (j = 0; j < strlen(students[i].Last_name); j++) {` this is comparing a unsigned value with a signed value. ( `j` is a `int` and the function: `strlen()` returns a `size_t` which is unsigned) This will only work correctly for small positive values – user3629249 Feb 22 '21 at 16:40
  • OT: the posted code contains several 'magic' numbers: I.E. 22, 30, 100. 'magic' numbers make the code much more difficult to understand, debug, etc. Suggest using `#define` statements or a `enum` statement to give those 'magic' numbers meaningful names, then use those meaningful names throughout the code. – user3629249 Feb 22 '21 at 16:44
  • OT: regarding: `typedef struct { int ID; char Last_name[30]; char First_name[30]; char major[30]; } Class;` this struct has no 'tag' name, so most debuggers cannot display the fields within the struct. Suggest adding a 'tag' name. Also, it is a poor programming practice to use reserved words (with a variation in the capitalization) for a variable name – user3629249 Feb 22 '21 at 16:48
  • OT: regarding: `int i; for (i = 0; i < 22; i++)` one of the objectives of good programming practice is to limit the scope of variables. Therefore, suggest: `for ( int i = 0; i < 22; i++)` so the scope of the variable `i` is limited to the body of the `for()` statement. – user3629249 Feb 22 '21 at 16:51
  • OT: regarding statements like: `int ID_to_search, i, index, j;` Pllease follow the axiom: *only one statement per line and (at most) one variable declaration per statement.* – user3629249 Feb 22 '21 at 16:53
  • OT: regarding: `printf("File unexistant!\n");` Error messages should be output to `stderr`, not `stdout` and when the error indication is from a C library function, should also output to `stderr` the text reason the system thinks the error occurred. The function `perror()` is made for that purpose. Also, since the call to `fopen()` failed, there is nothing more to do than 'cleanup' and exit, probably via `exit( EXIT_FAILURE );` Calling `fclose()` on the file that not open is an error than can cause your program to crash – user3629249 Feb 22 '21 at 16:59
  • OT: regarding statements like: `fscanf(infp, "%d", students[i].ID);` This statement can fail! always check the returned value (not the parameter values). The `scanf()` family of functions returns the number of successful 'input format conversion' specifiers. Suggest: `if( fscanf(infp, "%d", students[i].ID) != 1 ) { handle the error }` – user3629249 Feb 22 '21 at 17:04
  • OT: regarding statements like: `fscanf(infp, "%s", students[i].First_name);` When using the `input format conversion specifier: `%s` (and/or %[...]) always include a MAX_CHARACTERS modifier that is 1 less than the length of the input buffer, because those specifiers always append a NUL byte to the input. This avoids any possibility of a buffer overflow and the resulting undefined behavior – user3629249 Feb 22 '21 at 17:08

3 Answers3

1

there are several points:

  1. main should return int

  2. fscanf(info, "%d", &students[I].ID); // '&' has been missed.

  3. the file read loop

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

is not good.

while(fgets(buff, sizeof(buff), infp)!=NULL){
}

should be better. the file might have more or less lines;

  1. it's not good to combine fscanf with gets. please use fgets to read line and sscanf or strtok to get fields.
Paul Yang
  • 346
  • 2
  • 9
0

You miss an & on this line:

fscanf(infp, "%d", students[i].ID);

Change to:

fscanf(infp, "%d", &students[i].ID);
alex01011
  • 1,670
  • 2
  • 5
  • 17
0

regarding:

The problem: It only outputs the first line (aka first student info) from the file, and it does not even ask for the student ID afterward.

the code of interest is

    printf("Enter an ID: ");
    scanf("%d", &ID_to_search);
    index = search_for_student(ID_to_search, students);
    
    if (index == -101)
        printf("Student not found!");
    else {
        printf("Student with ID: %d corresponds to %s %s who is majoring in %s.", students[index].ID, students[index].First_name, students[index].Last_name, students[index].major);
    } 
}  // end if/else, not the end of a `for() loop

Notice that the above code is the end of a 'else' code block, not part of a for() loop, so only will be executed once

Also, if less than 22 students to input, the call to fscanf() will return EOF rather than updating any student info. Are you sure the input file actually contains 22 instances of student info? does it even contain more than 1 instance of student info?

rather than using a hardcoded count of 22, for:

for (i = 0; i < 22; i++) 
    {
        fscanf(infp, "%d", students[i].ID);

suggest using the returned value from that first call to fscanf() similar to:

i = 0;
while( fscanf(infp, "%d", students[i].ID) != EOF )
{
    ....
    i++;
} 
user3629249
  • 16,402
  • 1
  • 16
  • 17