0

I'm tring to do a simple exercise here, but i need to understand how EOF works first.

void main()
{
    char s1[1000];
    while (scanf("%s", s1)!=EOF)
        ;
    printf("%s",s1);
}

The idea is to have multiple lines in input, and display them.

The problem I have is that if I put

Hello World
This is stackoverflow

When printf is called, it only prints

stackoverflow

Why isn't it printing everything and how do I make it print?

Regards

Benesh
  • 3,398
  • 1
  • 18
  • 38
Pedro Lino
  • 601
  • 1
  • 9
  • 18
  • 2
    `void main()` is wrong; it's `int main(void)`. – Keith Thompson Mar 27 '14 at 21:49
  • 2
    Why is this? void main() has been working for me... :S – Pedro Lino Mar 27 '14 at 21:56
  • Check this out to know why. http://stackoverflow.com/questions/204476/what-should-main-return-in-c-and-c?lq=1 – avmohan Mar 27 '14 at 22:00
  • 3
    A compiler *may* permit `void main()`, but all C compilers *must* support `int main(void)`. (If you're using a book written by an author who doesn't know that, find a better book.) – Keith Thompson Mar 27 '14 at 22:11
  • The `scanf` function is for *formatted input*. Reading with `%s` reads the next word, and discards whitespace. If you want your output to look exactly like your input, the simplest way is to use *unformatted* input functions like `fread`, `fgets`, or `getchar`. – M.M Mar 27 '14 at 22:13
  • okey ill check with getchar since i don't know how to use the others. Regards – Pedro Lino Mar 27 '14 at 22:18
  • @PedroLino: `void main()` may "wprk" in the sense that it doesn't cause an obvious error such as a segfault, but that doesn't necessarily mean it's right; there are platforms on which a program that uses `void main()` will crash on exit, or fail to load at all. Unless your compiler documentation *explicitly* lists `void main()` as a legal signature, you should not use it. `int main(void)` and `int main(int, char**)` *will* be supported on any implementation. – John Bode Mar 28 '14 at 14:35

7 Answers7

2

Remove the semicolon ;:

    while (scanf("%s", s1)!=EOF)
        printf("%s",s1);

Note that this will still exhibit odd behavior at end of file depending on how it ends exactly. Furthermore, it splits the input into words, which are separated by spaces or new lines. You may want to simply split into lines.

So you may be better served with for instance:

    while (gets(s1)!=NULL)
        puts(s1);

This code fragments reads your input line by line until end-of-file.

To read everything (or as much as your buffer can hold), you can use:

    char s1[1000] = "";
    fread(s1, sizeof(s1) - 1, 1, stdin);
    puts(s1);

However, my preferred method of reading a text file is:

    using namespace std;
    string line;
    while (getline(cin, line))
    {
        cout << line << endl;
    }

That is because usually I want to process a file line by line, and getline with a string ensures the line buffer is always big enough.

  • 1
    I would suggest not to use gets(). The next chunk of code (with fread() and puts() works fine. – Sajib Mahmood Mar 27 '14 at 23:00
  • Usually you will want text files to be processed line by line. And actually std::getline() is my preferred method of reading them. I have added an example to my post. – Klaas van Aarsen Mar 28 '14 at 13:52
1

You probably want this:

  char s1[1000][20];

  int i = 0 ;

  while (!feof(stdin))
     fgets(s1[i++], 20, stdin) ;

  int j ;
  for (j = 0; j < i; j++)
    printf("%s\n", s1[j]);

Here you can enter at most 1000 lines that are maximum 19 characters long.

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
1

What you have is a loop that reads words into a buffer until it reaches EOF (and does nothing with those words), followed by a printf to print the contents of the buffer. The printf is after the loop (not in it), so executes once after the loop completes. At that time, the buffer will contain the last word read, so that is what gets printed.

The EOF return test means "nothing more to be read", which isn't necessarily an end of file (might be an error condition of some kind), but in practice that distinction can be ignored. Looping until your reading function returns EOF or NULL (depends on function) is good practice.

If you want to print each word as it is read, you need to put a printf in the loop.

If you want to store the words for later processing, you need to store them somewhere. That means declaring some storage space, or allocating space on the heap, and some bookkeeping to track how much space you've used/allocated.

If you want lines rather than words, you should use fgets instead of scanf("%s". Note that fgets returns NULL rather than EOF when there's nothing more to be read.

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
  • So there isn't any way to store all my input and store it to treat it later? I want to store the info from input so i can do something with it... – Pedro Lino Mar 27 '14 at 22:11
  • But wasn't i storing it in the s1 array? – Pedro Lino Mar 27 '14 at 22:21
  • @PedroLino: the `s1` array is a simple char array, so each word read overwrites the previous word. If you want to store multiple words (or multiples lines if you'd rather lines than words), you'll need multiple char arrays – Chris Dodd Mar 27 '14 at 22:49
  • so a 2D array like s1[1000][20], and when '\n' is pressed, it goes to 2º line. Is that it? – Pedro Lino Mar 27 '14 at 23:05
0

Because it only prints the last thing that is read from the file ("stackoverflow"). This is caused by the semicolon after the end of your while(...); - this means that you are doing while(...) { /* do nothing */} - which is probably not what you wanted

Also, printf("%s",s1)!='\0'; makes no sense at all. For one thing, printf returns the number of characters printed - '\0' is the value zero written as a character constant. And of course, doing != 0 of the result without some sort of use of the comparison is pretty much pointless too.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • thanks, the !='\0' was a mistake of mine, i've edited :) I want to read the input and store it. That's the idea – Pedro Lino Mar 27 '14 at 21:55
0

Use fgets instead of scanf if you want to read one line at at time. scanf will stop reading when it finds a whitespace. fgets will read till the end of the line.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
0

Use fgets(). Simple and sweet

char buf[1000];
while (fgets(buf, sizeof buf, stdin) != NULL) {
  fputs(buf, stdout);
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

Here is how end-of-file works in C. The input channels are called input streams; disk files and stdin are both input streams. The "end-of-file" state is a flag that a stream has, and that flag is triggered when you try to read from a stream, but it turns out there are no more characters in the stream, and there never will be any more. (If the stream is still active but just waiting for user input for example, it is not considered to be end-of-file; read operations will block).

Streams can have other error states, so looping until "end-of-file" is set is usually wrong. If the stream does go into an error state then your loop will never exit (aka. "infinite loop").

The end-of-file state can be checked by feof. However, some input operations also can signal an error as well as, or instead of, returning the actual data they were intended to read. These functions can return the value EOF. Usually these functions return EOF in both cases: end-of-file, and stream error. This is different to feof which only returns true in the case of end-of-file.

For example, getchar() and scanf will return EOF if it was end-of-file, but also if the stream is in an error state.

So it is OK to use getchar()'s result as a loop condition, but not feof on its own.

Also, it is sometimes not OK to use scanf() != EOF as a loop condition. It's possible that there is no stream error, but just that the data you requested wasn't there. For example, if you scan for "%d" but there are letters in the stream. Instead, it's better to check for successful conversion (scanf returns the number of successful conversions it performed). Then when you exit your loop, you can go on to call feof and ferror to see whether it was due to end-of-file, or error, or just unexpected input.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • -1 for mentioning `feof` -- its not relevant here and will just encourage bad practice – Chris Dodd Mar 27 '14 at 22:05
  • 1
    OP said he wanted to understand how EOF works, and I thought including an explanation of how the `feof` function actually works would help to avoid bad practice . If I did not mention it, he may assume (as many people do, judging by how many wrong uses of `feof` get posted as questions here) that it was equivalent to scanf returning `EOF`, etc. – M.M Mar 27 '14 at 22:08
  • For example there's another answer up there where the guy goes "What you have is a loop that reads words into a buffer until it reaches EOF" , this is confusing at best because if you only check for end-of-file but the stream goes into an error state, then the loop will never exit. – M.M Mar 27 '14 at 22:14
  • No, he checks for returning `EOF`, which means "can't read anymore", and which could be either end of file or an error, but the distinction isn't really important. The fact that others are incorrectly suggesting `feof` is besides the point. – Chris Dodd Mar 27 '14 at 22:20
  • 1
    "returning `EOF`" and "reaching EOF" are different things, the first one means end-of-file or error, and the second one just means end-of-file. My answer tries to make this distinction clear so that people don't make errors such as using `feof` when they shouldn't. – M.M Mar 27 '14 at 22:24
  • I think it adds more confusion than it clarifies. 99% of the time you want "end-of-file or error" and not "end-of-file" in your test, and on those occasions when the distinction between "end-of-file" and "error" is important, you FIRST want the "end-of-file or error" check anyways. – Chris Dodd Mar 27 '14 at 22:57