0

I have no idea why this does not work:

#include <stdio.h>

int main(){
    FILE* fp = fopen("txt2","wr");
    if(!fp) return 1;

    fprintf(fp,"20");
    fseek(fp,0,SEEK_SET);   
    fprintf(fp,"19");
    rewind(fp);
    
    char c;
    while((c=fgetc(fp))!=EOF)
        printf("%c",c);
}

Here should be write 20, then rewrite to 19, set the position to start of file, and the read the char till EOF (so should print 19). But prints nothing. Why is that?

I have tried to make better check for return poitner to fp (because of wr):

EDIT:

#include <stdio.h>
int main(){
    FILE *fp = fopen("txt","wr");
    if(!fp){
        printf("nada\n");
        return 1;
    }
}

But it compiles without problem. Why is that? The wr should be UB (and thus cause segfault or another err) or?

milanHrabos
  • 2,010
  • 3
  • 11
  • 45
  • 2
    Note that `fgetc()` returns `int`, not `char`. Placing the `int` from `fgetc()` into a `char` value can make identifying `EOF` correctly impossible. – Andrew Henle Jun 22 '20 at 19:26
  • it compiles, even with `wr` as flags – milanHrabos Jun 22 '20 at 19:39
  • @milanHrabos the compiler doesn't check the content of the mode string to determine if it's valid. That's up to you. To the compiler, it's just a string. – lurker Jun 22 '20 at 20:50

1 Answers1

2

The mode "wr" is not valid string for POSIX fopen() or Microsoft fopen(). You probably want to use "w+". Using "r+" would be an alternative, but then the file must exist before you open it.

The implementation of fopen() that you're using probably treats "wr" as equivalent to "w" (unless it reports an error and your program exits — it is a good idea to report why you are exiting). You can't read from a write-only file stream.

Strictly, you should also use int and not char for the variable c because fgetc() returns an int.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • There is no report or error, the gcc does not hepled here (So it is UB). Anyway thanks – milanHrabos Jun 22 '20 at 19:27
  • the solution could be thisone (after changing flags in fopen to w+): `for(int c;(c=fgetc(fp))!=EOF;printf("%c",c));` – milanHrabos Jun 22 '20 at 19:28
  • The way that `fopen()` reports the error is by returning `NULL`. You test for the `NULL` pointer (that's good), but you don't write a message to the user if the program fails to open the file. It just exits with an error status via the `return 1;` which requires testing at the command line. You're using C99 or later semantics in `main()` — you have no final `return 0;` at the end. – Jonathan Leffler Jun 22 '20 at 19:29
  • yes, I do not use `return 0` at the end of main, because main is usually the last process running, and no other process is after (and therefor waiting for return exit status). So I consider using exit status of main to be redundant – milanHrabos Jun 22 '20 at 19:31
  • I disagree about the final `return 0;`, but the C standard committee allows you to get away with omitting it as long as you aren't using C90 (so I disagree with the C standard committee — I don't think it was a good change, but it was made in part for compatibility with C++, where the considerations are different). – Jonathan Leffler Jun 22 '20 at 19:33
  • But of course, the exit status of main could be still good for debugging purposes – milanHrabos Jun 22 '20 at 19:34
  • see my edits. even though making the checking be verbose, it still compile and does not segaful, how's that possible? – milanHrabos Jun 22 '20 at 19:39
  • It compiles because it is syntactically correct; it links because there are no undefined references. When it runs, the `nada` message would appear if the local `fopen()` reports the erroneous mode argument. (The error message should be printed to `stderr`, but that's a minor problem.). If `nada` does not appear, then the file is open for writing; when you try to read from the write-only file stream, you immediately get `EOF` returned from `fgetc ()`, so the program produces no output at all. Note that the compiler does not check the `fopen()` mode argument; that is only checked at run-time. – Jonathan Leffler Jun 22 '20 at 19:41
  • so can you please add to your answer a proper handling of errournous fopen? What to change in order to see the `nada` message? – milanHrabos Jun 22 '20 at 19:43
  • There is no way to report `nada` if the implementation of `fopen()` looks at the string `"wr"` and says "oh, that's a write-only mode" and gets on with life. Or, more accurately, you'd have to do the comparison of the mode string to the values listed in the relevant documentation and then report "my programmer did not read the manual and miscoded the open mode, even though it was a literal string and the test for the invalid mode was a lot harder to write than simply using a valid string". A better error message would include the file name. You'd probably write a function to check the mode. – Jonathan Leffler Jun 22 '20 at 19:45
  • Ok, I see the irony. However, when someony really mistype the open mode in critical app, there should be a method to check this error. Because the fopen will give me valid pointer regardless of flag used, so I cannot check that pointer, but what else should i check? there is nothing to ensure, the open was done properly and will not cause a huge problem more later and cause unexpected results (because IO here is important) – milanHrabos Jun 22 '20 at 19:52
  • If you supply a mode such as `"z"` or `"+w"`, you will likely get a null pointer from `fopen()`. If the mode supplied has a valid mode as a prefix, it is quite common for the valid prefix to be used and the remainder ignored. If you want to be sure that a variable mode is wholly valid, you'd have to write a wrapper function that validates the mode and then calls `fopen()` if it is OK (returning `NULL` if it is not, and maybe setting `errno` to `EINVAL` or thereabouts if it is not OK). The wrapper might or might not report the error on `stderr` — that depends on the constraints in your program. – Jonathan Leffler Jun 22 '20 at 20:05