Linux - NewbieThis Linux forum is for members that are new to Linux.
Just starting out and have a question?
If it is not in the man pages or the how-to's this is the place!
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Enter string :Linux
Enter string :Linux
Enter string :Linux
Enter string :Linux
Enter string :Linux
Enter string :Linux
Enter string :Linux
Enter string :Linux
:
:
This goes on forever. What I was expecting was that the program would print Linux once and then wait for next input from stdin. This error probably might be occuring because the word Linux is still on the stdin of a.out and it is reading the same thing every second (just my guess). So I tried removing the infinite loop in the code, but in that case if I do "uname | ./a.out" it works. But if I do some command that prints mulitple lines of text like "ls | ./a.out" only the first file name is printed and a.out exits. Can anyone suggest any method to solve this problem.
Enter string :Linux
Enter string :Linux
Enter string :Linux
:
:
This goes on forever.
I would expect that, because your program does not check whether stdin has any more input or not. So it reads one line of text and prints that again. In the second and subsequent loop iteration, however, stdin has reached the end of input (that is, feof(stdin) is true). In that case, fgets() does not modify the input buffer (see the reference manual for that case), and you believe you get the same string over and over again.
Quote:
Originally Posted by qwerty4061
What I was expecting was that the program would print Linux once and then wait for next input from stdin.
It does - if you call it without input redirection (piping). Then stdin is the console input, which doesn't have an end-of-file condition.
Quote:
Originally Posted by qwerty4061
Can anyone suggest any method to solve this problem.
Easy: Instead of making an infinite loop using while (1), check the end-of-file condition there:
Code:
while (!feof(stdin))
...
Then your program terminates properly when the input stream ends.
"fgets" gets raw data, printf's "%s" expecta a NULL-terminated string. Try this:
Code:
#include <stdio.h>
int main()
{
char str[81]; // the 81st element is for the NULL character at the end
while (! feof(stdin))
{
printf("Enter string :");
size_t bytes_read = fgets(str, 80, stdin);
str[bytes_read] = '\0';
printf("%s", str);
sleep(1);
fflush(NULL);
}
return 0;
}
What other way is there to call it other than piping?
call your program from the console, just like that - and supply the input via keyboard as usual. :-)
Quote:
Originally Posted by qwerty4061
I replace the infinite loop with EOF check, but now instead of printing infinite times it is printing "Linux" twice. Why is that happening.
Because I didn't finish thinking. Damn.
Well, look: fgets() reads until there is either an end-of-file condition, or a line feed. In your situation, the output of uname that you pipe into your program ends with a line feed. So fgets() reads everything, including the line feed, and then returns that data. At that moment, feof(stdin) doesn't catch yet, because you have read up to the end of the stream, but not beyond. End-of-file is recognized only when you try to read past the end. And that happens in lap 2 of your loop.
That's not nice, because it forces the programmer to produce "spaghetti code".
You can revert to your "while (1)" as the heading of your loop, but now you must supply something that ends the loop as soon as you know it should be ended - and that's after the fgets() call. Insert another line after the fgets() call:
Code:
if (feof(stdin))
break;
That will break out of the loop and continue with the instructions after it when feof(stdin) catches.
Quote:
Originally Posted by qwerty4061
Also wasn't fflush(NULL) supposed to take care of stale values inside STDIN. STDOUT
Yes. But it neither changes the eof() status of the file, nor touches your program's receive buffer. It only discards the rest of available input data you may not have read yet. But honestly, I stopped short on using NULL as an argument, as I would have expected fflush(stdin) here. Using NULL will flush all currently open files (didn't know that yet, thanks), which may not be what you want in a larger project.
Thanks everyone especially Doc CPU for your answers.
Quote:
"fgets" gets raw data, printf's "%s" expecta a NULL-terminated string. Try this:
I think you are wrong here. "man fgets" tells a different story.
Quote:
fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A '\0' is stored after the last character in the buffer.
Quote:
Using NULL will flush all currently open files (didn't know that yet, thanks), which may not be what you want in a larger project.
I was initially using fflush(stdin). I changed it to NULL while tying to figure out why the program is not working.
why so complicated? The return type of malloc() is a void * which is by definition compatible to any other pointer type. So the explicite type cast isn't necessary and just makes it worse to read.
The rtn type is 'void *' so that you CAN cast it to the type you require, which you should do for robust code. It also makes it clearer for the next guy
The rtn type is 'void *' so that you CAN cast it to the type you require
for a type cast to be possible, it wouldn't have to be void *, it could as well be int - though a pointer type is more obvious, of course. But an explicit type cast is always possible, even between totally incompatible types.
Quote:
Originally Posted by chrism01
which you should do for robust code. It also makes it clearer for the next guy
For me, a type cast on the result of malloc() looks more like an attempt of obfuscation. I avoid it for the sake of clarity.
I guess I should have been clearer when I wrote "Better Code". I wrote that in response to DocCPU's earlier comment to feof forcing developers to write spaghetti code.
Quote:
Why use malloc() for a fixed-size string that's only used for the lifetime of a function? use an array:
Yes, you are right. There is no point in using malloc in this code. In my defence, this code was doing something else entirely different initially, I was modifying it in my effort to learn about standard streams.
Quote:
For me, a type cast on the result of malloc() looks more like an attempt of obfuscation. I avoid it for the sake of clarity.
I disagree with you on this. I think it improves readability, I don't have enough programming experience/knowledge to argue about the relative merits about using an explicit cast. If you have any reason as to why not to use an explicit cast in malloc, other than a personal preference I am definitely interested in it.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.