2

Code:

#include <stdio.h>

void main() {
    FILE *ptr;
    char buff[255];
    ptr = fopen("Test.txt", "w+");

    if (ptr != NULL) {
        printf("Success\n");
    }

    fputs("Hello", ptr);

    fgets(buff, 255, (FILE *)ptr);
    printf("%s", buff);
    fclose(ptr);
}

The file "Text.txt" has the content "Hello" when I opened it, but I just can't print it out with fgets. What did I do wrong here?

Yunnosch
  • 21,438
  • 7
  • 35
  • 44
Richard
  • 5,945
  • 7
  • 37

3 Answers3

4

You didn't rewind the file before reading. fseek(ptr, 0, SEEK_SET); or rewind(ptr);

LoztInSpace
  • 5,254
  • 1
  • 13
  • 25
4

Read up, e.g. https://en.cppreference.com/w/c/io/fopen

Bold by me.

In update mode ('+'), both input and output may be performed, but output cannot be followed by input without an intervening call to fflush, fseek, fsetpos or rewind, and input cannot be followed by output without an intervening call to fseek, fsetpos or rewind, unless the input operation encountered end of file. In update mode, implementations are permitted to use binary mode even when text mode is specified.

Yunnosch
  • 21,438
  • 7
  • 35
  • 44
3

There are multiple problems in your code:

  • You must issue a call to fseek(), fsetpos() or rewind() to switch between writing to and reading from the stream, and vice versa.

  • The prototype for main without arguments is int main(void).

  • There is no need to cast ptr in fgets(buff, 255, (FILE *)ptr);. Useless casts can hide type mismatches and other similar bugs.

  • You do not test the return value of fgets() before passing buff to printf(). This has undefined behavior if fgets() fails, a it does in your case.

  • You do test the return value of fopen(), but still pass a potentially null ptr to other stream functions, invoking undefined behavior.

Here is a corrected version:

#include <stdio.h>

int main(void) {
    FILE *ptr;
    char buff[255];

    ptr = fopen("Test.txt", "w+");
    if (ptr == NULL) {
        printf("Cannot open Test.txt\n");
        return 1;
    }
    printf("Success\n");

    fputs("Hello", ptr);
    rewind(ptr);
    if (fgets(buff, sizeof buff, ptr)) {
        printf("%s", buff);
    } else {
        printf("Cannot read from stream\n");
    }
    fclose(ptr);
    return 0;
}
chqrlie
  • 98,886
  • 10
  • 89
  • 149
  • Okay thank you for all the corrections! @chqrlie Why should I `int main(void)` though? I have never had problems using `void main()`. – Richard Jul 10 '18 at 09:24
  • I also see that people like to `return 1` when there's an error, is that the norm? – Richard Jul 10 '18 at 09:43
  • @chrqlie Also, you used `sizeof buff`, does it mean the same as `255`? What if it was `int buff[255]` instead, can I still use `sizeof buff`? And don't `sizeof` require parentheses `()`? – Richard Jul 10 '18 at 09:48
  • @WealthyPlayer: `sizeof buff` evaluates to `255` at compile time because `buff` is an array of `char`, so it is the same except it is safer to use an expression that will not get out of sync if you later decide to change the size in the definition of `buff`. If `buff` was an array of `int`, `sizeof buff` would be `255 * sizeof(int)`, but il would be incorrect to pass an array of `int` to `fgets()`. The number of elements of an array `a` can be computed (at compile time) as `sizeof(a) / sizeof(*a)`. – chqrlie Jul 10 '18 at 15:10
  • @WealthyPlayer: `sizeof` requires parentheses when applied to a type as in `sizeof(int)`, they are optional for variable and expression arguments, `sizeof` is then just another prefix operator like `~` and `!`. Some people prefer to always parenthesize the argument for consistency and readability. Linux Torvalds is notoriously anal about this. I personally use parentheses if `sizeof` is part of a larger expression such as `sizeof(*p) * 10` which I find less ambiguous than `sizeof *p * 10`. – chqrlie Jul 10 '18 at 15:13