0

I just started learning files in c few days ago. In order to understand how to manipulate correctly the functions, I wrote a code who create a new file (w+) read a string and using fputs() put it in the file. Using a function it find how many characters are there. the problem is if I don't rewind before calling the function, the output returned is very large compared to the string the output+string is exactly 4096 every time no matter how big the array. I don't understand why it should just return 0 if I don't rewind the pointer, and why it doesn't return 4096 when I rewind it, instead it returns the correct answer. Here is my code:

#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
int daft(FILE* f){
    int s=0,c;
    while((c=fgetc(f))!=EOF){
        if(!isspace(c))
        s++;
    }
    return s;
}
int main(){
    char *ch;
    ch=malloc(20*sizeof(char));
    FILE *f;
    f=fopen("test.txt","w+");
    if(f!=NULL){
        gets(ch);
        fputs(ch,f);
        printf("n= %d\n",daft(f));
        fclose(f);
        
    }
    free(ch);
    return 0;
    
}
  • I don't think this is an UB. fgetc() simply returns EOF in that case. – Bktero Nov 27 '20 at 13:47
  • 2
    You need to be aware of the fact that your learning material is outdated. `main()` is not the right syntax to define the main function since 2011, and it was discouraged and deprecated for longer still. Likewise `gets()` is not a part of C since 2011, and it was deprecated well before that. You want to [enable compiler warnings and treat them as errors](https://stackoverflow.com/questions/57842756). Beware of Microsoft C, it is an old compiler and Microsoft has no intention of bringing it up to modern standards (they are only interested in C++). – n. m. could be an AI Nov 27 '20 at 14:26
  • 1
    Note that [`gets()` is too dangerous to be used — ever!](https://stackoverflow.com/q/1694036/15168) – Jonathan Leffler Nov 27 '20 at 16:06

2 Answers2

2

You need to flush the stream after writing and before reading:

7.21.5.3 The fopen function
...
7     When a file is opened with update mode ('+' as the second or third character in the above list of mode argument values), both input and output may be performed on the associated stream. However, output shall not be directly followed by input without an intervening call to the fflush function or to a file positioning function (fseek, fsetpos, or rewind), and input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file. Opening (or creating) a text file with update mode may instead open (or create) a binary stream in some implementations.
C 2011 Online Draft

Emphasis added. By not flushing after writing and by not rewinding, the stream is not in a good state to be read from. You've entered the realm of undefined behavior - fgetc returns something that's not EOF for many iterations, and as a result s is incremented to a very large value.

This is why it worked when you used the rewind function, because you reset the stream to be in a good state for reading.

John Bode
  • 119,563
  • 19
  • 122
  • 198
1

EOF is not necessarily stored in the file. Usually, files does not. It is what the function returns when it fails to read.

Also, never use gets()

klutt
  • 30,332
  • 17
  • 55
  • 95
  • Older Microsoft text files do contain the EOF marker `0x1A` and if that character is read by `fgetc()` the function returns the `EOF` flag `-1` even if it is not at the end of the file. – Weather Vane Nov 27 '20 at 14:06
  • understood, but is the difference in the output is because I used gets()? –  Nov 27 '20 at 14:25
  • also when does the function fails to read? is it right after of the characters end? I just don't understand why it gives me different output when I don't use `rewind` –  Nov 27 '20 at 14:40