-1

I know there are hundreds of topics about it, but I need to ask again. I do have the following code:

char *str;

while(fgets(&str,50,stdin) != NULL && &str != EOF) {
    printf(&str);
}
printf("Test");

I would like to read several lines in my code and do something with them. In that example it's just printing. I would like to end, when there is an EOF and then do other stuff after the while-loop. Unfortunately, in the moment when I am using CMD-D (EOF on mac/CLion), the complete program terminates, no matter whats afterwords, so there is no "Test" at the output anymore.

Does anyone know whats happening? Also note, that I need it as a char pointer, because I want to work with it later.

gsamaras
  • 71,951
  • 46
  • 188
  • 305
Hemmelig
  • 803
  • 10
  • 22
  • 4
    That piece of code is problematic for multiple reasons, including you not knowing what [`fgets`](http://en.cppreference.com/w/c/io/fgets) really does or how it works. The same with [`printf`](http://en.cppreference.com/w/c/io/fprintf). You should probably listen to what your compiler tells you more closely, it should complain loudly about code like that. And then take a few steps back, get a beginners book and start over from the very beginning. – Some programmer dude May 25 '18 at 11:17
  • How could this be upvoted? It is reading **50** characters inside a pointer, where the size of a pointer is never greater than 8 on common architecture! This invokes UB and behaviour is... **undefined** :-( – Serge Ballesta May 25 '18 at 11:19
  • You do not have allocated memory to `str`. You do not need to use the address of operator (`&`) on `str` when you pass it to `fgets`. – Paul Ogilvie May 25 '18 at 11:20
  • 1
    "*I know there are hundreds of topics about it, but I need to ask again.*" I disagree. Also, "*Does anyone know what's happening?*" is far too broad / unspecific. – melpomene May 25 '18 at 11:23
  • Don't read lines "into" a pointer. Ensure `str` actually points at (the first element of) an array that has 50 elements. Then pass `str` as the first argument of `fgets()`, not `&str`. `printf(&str)` would ALSO need to be `printf("%s", str)`. – Peter May 25 '18 at 11:23
  • Thanks to all of you giving me some comments about it, also to gsamaras for correcting my typo mistake. – Hemmelig May 25 '18 at 11:43
  • It looks like you forgot to enable a good set of warnings. For GCC, I recommend `-Wall -Wextra -Wwrite-strings` as a minimum; consider also `-Wpedantic -Warray-bounds` for identifying some other common mistakes. – Toby Speight May 25 '18 at 14:41

2 Answers2

2

In your code, str is just a pointer that doesn't point to allocated memory. Then you ask fgets() to store in str what it read (but where to store it, since there is no memory allocated for str?!). This causes Undefined Behavior, and must be fixed.

A simple solution would be to make str an array of characters.

The EOF you have in your code shows that you didn't read the manual of the function, which states:

Return value:

If the end-of-file is encountered while attempting to read a character, the eof indicator is set (feof). If this happens before any characters could be read, the pointer returned is a null pointer (and the contents of str remain unchanged).

That means that we do not need an extra check.

Putting everything together:

#include <stdio.h>

int main()
{
    char str[50];
    while (fgets(str, 50, stdin)) {
        printf("%s\n", str);
    }
    return 0;
}

which reads the file line by line, and then prints every line.


Useful link: Removing trailing newline character from fgets() input.


PS: You could use as the second argument of fgets() sizeof(str), instead of 50 (the size of the array), but that wouldn't work when str is a pointer that actually points to another location that the memory is stored (for example another array).

gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • 1
    Use `sizeof(str)` as second argument of `fgets()`. – Peter May 25 '18 at 11:27
  • Thanks to both of you for answering me! The example with the File reading which you just deleted a couple of minutes ago helped me to understand a little bit more about it. But my last question would be: How can I see via stdin that the user terminated his entries, so is there something like EOF there as well, or is that just for "real files" to read? – Hemmelig May 25 '18 at 11:40
  • I updated the answer @FranzFerdinand, because your question was with `stdin`. Would you like me to revert it? As for your question, you just give `EOF` from your terminal, `ctrl + D` in Linux and it [should be the same in Mac](https://stackoverflow.com/questions/21364313/signal-eof-in-mac-osx-terminal). – gsamaras May 25 '18 at 11:46
  • 1
    Doesn't matter if it's stdin or a file, because my question would be quite the same on both. Thank you very much for your help, so it was a misunderstanding of using EOF. – Hemmelig May 25 '18 at 11:56
0

Your code should look like:

char str[50];

while(fgets(str,sizeof(str),stdin) != NULL) {
    printf("%s",str);
}
printf("Test");
Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41
  • Rather than `50` as the second argument of `fgets()`, better to use `sizeof(str)`. This only works if `str` is an array though (not if it is a pointer). `fgets()` cannot return `EOF` - check what it ACTUALLY returns on error. – Peter May 25 '18 at 11:25
  • Oops... fixed EOF-->NULL – Paul Ogilvie May 25 '18 at 11:28
  • Hey, thanks for that idea, so in fact I misunderstood something about the pointers. But there is one question left for me: When I am reading from stdin, how do I determine EOF happening then? – Hemmelig May 25 '18 at 11:36
  • @FranzFerdinand On end-of-file or input error, `fgets()` returns `NULL`. – chux - Reinstate Monica May 25 '18 at 11:44