-1

I have a .txt file following the syntax:

studentName1 grade1
studentName2 grade2
.
.
.

I want to develop the C function int changeGrade(String name, int old_grade, int new_grade, String fileName)

That changes the grade of the specified Student with the new one.

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

typedef char String[30];

void changeGrade(String name, int old_grade, int new_grade, String fileName) {

    long pos;
    String temp;
    int grade;
    int test = 0;

    if ((old_grade <= 10) && (old_grade >= 0)) {

        FILE * fp = fopen(fileName, "r+");

        while ((!test) && (!feof(fp))) {

            pos = ftell(fp);

            fscanf(fp, "%s %d\n", temp, & grade);
            if (strcmp(name, temp) == 0 && grade == old_grade) {

                fseek(fp, pos, SEEK_SET);
                fprintf(fp, "%s %d", name, new_grade);
                test = 1;

            }
        }
        fclose(fp);
    } else printf("Error,you must specify the grade");

}

int main(int argc,
    const char * argv[]) {

    changeGrade("Carl", 7, 6, "students.txt");

}

The code works, but if i have something like changeGrade("Carl",10,7,"students.txt") I get

Carl 70

Why?

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
Osmion
  • 19
  • 5
  • It would be polite to format the question properly... There's the preview, so you should see how it looks before posting. – hyde Aug 22 '19 at 14:48
  • 2
    Short answer to your question: you cant insert or erase chars in the middle of text file. You need fixed width fields if you want to do what you are trying, and need to overwrite the entire field with new value (probably using spaces if your data does not fill entire length of field). – hyde Aug 22 '19 at 14:51
  • What are you doing with your loop? Don't check `tell` and `feof`, just check the value returned by `scanf`. – William Pursell Aug 22 '19 at 14:53
  • If you have a read error and never find your desired string, you've got an infinite loop. See discussion at https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong/ – William Pursell Aug 22 '19 at 14:54
  • Errors belong on stderr. Always. `fprintf( stderr, "Error,you must specify the grade\n");` – William Pursell Aug 22 '19 at 14:55
  • Short answer: if you overwrite the string `10` with a `7`, you get `70`. If you want to get `7\n`, you need to overwrite the `0` with `\n`. And then either live with a blank line, or shift all characters in the file by one position. It's almost always easer to write the data to a new file (and rename it to the original name) than to change data in a file. – William Pursell Aug 22 '19 at 14:59
  • You're misusing `feof()`. That only returns true *after* an attempt to read *past* the end of the file. Read [**Why is “while ( !feof (file) )” always wrong?**](https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong) You also need to check the return value for `fscanf()`. – Andrew Henle Aug 22 '19 at 15:27
  • As in [this question](https://stackoverflow.com/questions/57595087/why-stop-functioning). 1. `pos = ftell(fp)` is the wrong place: this isn't typically the start of the items which you try to overwrite, but the location of the first whitespace following the previous call to `fscanf`. 2. You need more action when switching from write back to read. As [`fopen` man page](https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/fopen-wfopen?view=vs-2017) says: *When you switch from writing to reading, you must use an intervening call to either `fflush` or to a file positioning function.* – Weather Vane Aug 22 '19 at 17:12
  • First of all thank you! Second, the code isn't mine. The "developer" is my Operative System professor and this is the proposed solution of the exercise i mentioned above. Third, yes, this solution sucks and this is why i asked for your help ;) – Osmion Aug 23 '19 at 08:45

1 Answers1

0

Although I cannot condone doing this in C, nor the approach you are currently taking, the simple fix is for you to ensure that all your grades are the same width. If you must preprocess the file to make everything 2 digits, do that with something like: awk '{$2 = sprintf("%2d",$2)}1' input-file

Once that is done, just use a 2 digit grade all the time. That is, write:

fprintf(fp, "%s %2d", name, new_grade);
William Pursell
  • 204,365
  • 48
  • 270
  • 300