Can I access stdin without keyboard? - c

I have compiled the following code with gcc
int main() {
int a = 0;
fprintf( stdin, "%d", 123 );
fscanf( stdin, "%d", &a );
printf( "%d\n", a );
return 0;
}
In my expectation, the program should executes straightly (i.e., the program never pause and wait for user input). But it still stop, and wait for my input.
I want to know what happen when I try to write something to stdin and how to modify this code and it can execute straightly?

stdin is for input only, stdout is for output. (4566976's answer shows you what happens when you try to output to stdin) See for example the glibc documentation on standard streams
(in short, writing to stdin makes no sense at all)

If you print out the return value of fprintf(stdin you can see that the function call fails.
In the shell you can pipe something into the stdin of the process.
#include <stdio.h>
int main(void) {
int a = 0, ret;
printf("%d\n", ret = fprintf( stdin, "%d", 123 ));
if (ret < 0) perror("fprintf");
fscanf( stdin, "%d", &a );
printf( "%d\n", a );
return 0;
}
$ echo 123 | ./a.out
-1
fprintf: Bad file descriptor
123
$

In addition of the fprintf(stdin, bug you also forgot that stdin is not the keyboard. The latest C11 standard does not know about the keyboard. On a Linux graphical desktop, only the X11 server is reading from the physical keyboard.
Practically speaking, on POSIX systems notably such as Linux, stdin can be a pipe(7) (using pipelines in your shell is very common), a fifo(7), a socket(7), a plain file (thru redirection) or even /dev/null, and of course also a terminal.
The funny thing these days is that terminals are very often virtual emulated devices (I did not see any real physical terminal in this century, outside of museums), read about pseudotty. The details are quite arcane for historical reasons. Read the tty demystified page. See also ANSI escape code wikipage & console_codes(4) and tty(4) (so consider /dev/tty and perhaps /dev/console)
You can check (with isatty(3)) that stdin is a terminal (actually a pseudotty) using isatty(STDIN_FILENO)...
Practically speaking, when you really want to use the terminal, I strongly recommend using a library like ncurses or GNU readline (both are using termios(3))
Don't forget that I/O is generally buffered, and use fflush(3) wisely.
BTW, you should have compiled with all warnings & debug info (gcc -Wall -Wextra -g) then use the gdb debugger. And strace(1) would have been very useful too.
Maybe you wanted to pipe to your own program (but that is weird, and often wrong, unless you take great care about all the implications; it is however a very useful trick for handling signal(7) in event oriented programs, notably those with some GUI). Beware that pipes have a limited buffer size (so avoid deadlocks, probably by having your event loop with poll(2)) and read about PIPE_BUF and write. You might have tried:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
int pfd[2] = {-1,-1};
int a= 0;
if (pipe(pfd)) { perror("pipe"); exit (EXIT_FAILURE); };
if (dup2(pfd[0],STDIN_FILENO)<0)
{ perror("dup2 stdin"); exit(EXIT_FAILURE);};
if (dup2(pfd[1],STDOUT_FILENO)<0)
{ perror("dup2 stdout"); exit(EXIT_FAILURE);};
if (printf("%d\n", 123)<=0) { perror("printf"); exit(EXIT_FAILURE); };
if (fflush(stdout)) { perror("fflush"); exit(EXIT_FAILURE); };
if (scanf("%d", &a)<1) { perror("scanf"); exit(EXIT_FAILURE); };
if (a != 123) { fprintf(stderr, "impossible happened a=%d\n", a); };
fprintf(stderr, "done...got a=%d\n", a);
}
You should read Advanced Linux Programming and learn more about syscalls(2); it has several chapters related to this. Read carefully pipe(2) and dup2(2) and be aware that the above program would be wrong for a larger output (bigger that PIPE_BUF, which on my system is several kilobytes)
BTW, you can get a readable FILE* from a memory buffer using fmemopen(3). For writing (e.g. with fprintf) to an output buffer, consider open_memstream and don't forget to fflush it before accessing the output buffer.

You can ungetc() a few characters and then read them with fscanf().
#include <stdio.h>
int main()
{
int value = 0;
ungetc ( '\n', stdin);//reverse order. newline first here but last from fscanf
ungetc ( '3', stdin);
ungetc ( '2', stdin);
ungetc ( '1', stdin);
fscanf ( stdin, "%d", &value);
printf ( "value is %d\n", value);
return 0;
}
output: value is 123

You're simply incorrect thinking that fscanf(stdin, "format", ...); does not block and wait for input, because it does.

Related

Why write() executes immediately, but printf() not? [duplicate]

#include <stdio.h>
#define MAXLEN 256
int main() {
int n;
char buf[MAXLEN];
while((n = read(0,buf,sizeof(buf))) != 0){
printf("n: %d:",n);
write(1,buf,n);
}
return 1;
}
The output of the program (where the first read and first write is typed by the user and echoed by the terminal) is:
read
read
write
write
n: 5:n: 6:
The output of printf comes after pressing Ctrl+D at the standard input and not along with the subsequent reads. Why does this happen?
Printf is buffered.
You can force printf to 'flush' its buffer using the fflush call:
#include <stdio.h>
#define MAXLEN 256
int main() {
int n;
char buf[MAXLEN];
while((n = read(0,buf,sizeof(buf))) != 0){
printf("n: %d:",n);
fflush(stdout); /* force it to go out */
write(1,buf,n);
}
return 1;
}
In general, printf() being buffered is a good thing. Unbuffered output, particularly to visible consoles that require screen updates and such, is slow. Slow enough that an application that is printf'ing a lot can be directly slowed down by it (especially on the Windows platform; Linux and unixes are typically impacted less).
However, printf() being buffered does bite you if you also fprintf(stderr,) - stderr is deliberately unbuffered. As a consequence, you may get your messages with some printf() missing; if you write to another FILE handle that is also associated with the terminal, and might be unbuffered, make sure you first explicitly fflush(stdout).
The manpage for fgets tells me:
It is not advisable to mix calls to input functions from the stdio
library with low-level calls to read(2) for the file descriptor associ‐
ated with the input stream; the results will be undefined and very
probably not what you want.
So the best solution would be not to to use write and printf on the same descriptor.
Printf is using stdio and it is buffered.
Push it out by sending a changing to "n: %d:\n"
You can use the std fflush() function to flush the std out buffer or you can make use of an additional \n at the end of the control string inside the printf. Something like this
printf("\n :%d:\n",n);
Its always better to use the write() & read() functions in C instead of printf() and scanf(). Printf and scanf have got some problems like printf stores the string parameter in stdout buffer. So a manual flush is required which is done through fflush function or by means of \n. In a small hello world printing program you will not find such a problem as the stdout buffer is flushed at the end of the program execution. Better use write() which works fine. scanf also have the problem of reading spaces and a lot of other problems related to stdin buffer.
For example in the code below:
main() { char a; int i=0,c; for(;i<2;i++) { scanf("%d",&c); scanf("%c",&a);} }
The above program as got the problem of reading \n into stdin on pressing enter. We could resolve this but not flushing the stdin buffer or making use of \n character. Always better to use the read() and write() functions.
Hope that helps....
Use fwrite (streams version) rather than write.
Note that, while is associated with file number 1, it isn't the same thing.

Not able to read input from stdin/STDIN_FILENO in C?

I have this command line argument -
cat file_name | ./a.out
The problem is not reading from the cat command inside the C program as we can do that with read(), fgets(), fgetc() but the actual problem I am facing is after reading the data from cat I am not able to take input from user using fgets.
Here is my sample code
while(fgets(buffer, BUFSIZ, stdin ) != NULL )
puts( buffer ); // Here I have tried strtok( buffer, "\n" ) too.
memset( buffer, 0, BUFSIZ );`
The problem is after this line, it is not asking for the input like the below is not working-
puts("Name: ");
fgets( buffer, BUFSIZ, stdin );
Help me with what's wrong happening here?
When you do cat file_name | ./a.out the standard input of your program is tied to a pipe linking it to the output of cat. Your program will never get to see the user input - the very stream from where it would arrive has been replaced by the aforementioned pipe.
Mind you, I suspect that with some horrible POSIX-specific trickery you may be able to reopen it going straight for the tty device, but it's just bad design. If you need to both read from a file and accept interactive user input just accept the file as a command line argument and use stdin to interact with the user.
Edit
This is an example of the Unix-specific kludges that one can attempt, assuming that the process still has a controlling terminal. After reading all the original stdin, I'm opening /dev/tty (which is the controlling terminal of the process) and re-linking stdin to it.
Disclaimer: this is for entertainment purposes only, don't do this for real.
#include <stdio.h>
#include <stdlib.h>
void die(const char *msg) {
fprintf(stderr, "%s\n", msg);
fputs(msg, stderr);
exit(1);
}
int main() {
/* Read all of stdin and count the bytes read (just to do something with it) */
int ch;
unsigned long count = 0;
while((ch = getchar())!=EOF) {
count++;
}
printf("Read %lu bytes from stdin\n", count);
/* Open the controlling terminal and re-link it to the relevant C library FILE *
* Notice that the UNIX fd for stdin is still the old one (it's
* surprisingly complex to "reset" stdio stdin to a new UNIX fd) */
if(freopen("/dev/tty", "r", stdin) == NULL) {
die("Failed freopen");
}
/* Do something with this newly gained console */
puts("How old are you?");
fflush(stdout);
int age = -1;
if(scanf("%d", &age)!=1) {
die("Bad input");
}
printf("You are %d years old\n", age);
return 0;
}
(previously I had a solution that checked if stderr or stdout were still consoles, which was even more of a kludge; thanks #rici for reminding me of the fact that POSIX has the concept of "controlling terminal", which is accessible through /dev/tty)
If you need to use stdin for user interaction, then you need to use a different file descriptor for reading the input stream.
You could use a specific pre-opened file descriptor and document that (e.g. "the input stream should be connected to fd 3"), but the usual approach is to accept a file name as a command-line argument. You can then provide a named pipe as the argument; shells such as Bash provide process substitution to make that easy:
./a.out <(cat file_name)
When that is run interactively like that, stdin is still connected to the terminal, and can be used at the same time as the stream from the connected command.
(Obviously, if the command actually is cat with a single argument, then you could just provide the filename itself as the argument, but I'm assuming that's a placeholder for a more involved pipeline).

Strange Behaviour because of sleep()

I was just getting familiar with sleep(), i found that
#include<stdio.h>
int main()
{
int i=0;
printf("*********Testing Sleep***********\n");
for(i=0;i<10;i++)
{
printf("%d",i);
sleep(1);
}
return 0;
}
this does not print number per iteration rather dumps all numbers when gets out of loop....
but when i modify printf...
#include<stdio.h>
int main()
{
int i=0;
printf("*********Testing Sleep***********\n");
for(i=0;i<10;i++)
{
printf("%d\n",i);
sleep(1);
}
return 0;
}
and now as i've added '\n' new line it works as expected... why it is behaving strangely in former one...
This is because the output buffer isn't being flushed (in other words, actually committed to the terminal). When you write a newline, the output buffer is more likely to be (but still not always, in some cases) flushed. Many terminal implementations do this to improve performance. To force the behaviour you want, you need to call fflush(stdout); after each printf call, like this:
#include<stdio.h>
int main()
{
int i=0;
printf("*********Testing Sleep***********\n");
for(i=0;i<10;i++)
{
printf("%d",i);
fflush(stdout);
sleep(1);
}
return 0;
}
What you are looking at is line buffered output. Actually writing to output is an expensive operation, so I/O streams are usually buffered. Actually writing the buffer is deferred until a specific event is encountered. In standard C, you have three types of buffering:
fully buffered - the buffer is written when full.
line buffered - the buffer is written when a newline is encountered (your case).
unbuffered - the buffer is written whenever an I/O function is executed. (Good for error logging.)
Writing the buffer is called flushing. That's why there is a stdio function called fflush(). You might also want to check out setvbuf() and its parameter constants, _IOFBF, _IOLBF and _IONBF. I am sure you can figure out what they mean without looking them up. ;-)
Edit: This program delivers as you originally expected:
#include <stdio.h>
// This is the header where sleep() is declared. Don't go without it.
#include <unistd.h>
int main()
{
int i=0;
// setvbuf() can be called on a stream only BEFORE
// you do any I/O on it!
setvbuf( stdout, NULL, _IONBF, 0 );
printf( "*********Testing Sleep***********\n" );
for ( i = 0; i < 10; ++i )
{
printf( "%d", i );
sleep( 1 );
}
return 0;
}
standard output for terminals is line buffered, output is not written unless there is a newline or you manually flush it.
Output is buffered, so that that the OS has an opportunity to optimize output speed. To make sure they are flushed immediately, do fflush (stdout);, but usually, you don't.
This is because printf() uses buffered output for better performance. Buffer is flushed to the console once \n is printed.
Printf is buffered.
You can force printf to 'flush' its buffer using the fflush call.
Or
Simply push the buffer to stdout using \n as in your case .
More detailed discussion is here

Does printf always flush the buffer on encountering a newline?

My machine is running ubuntu 10.10, and I'm using the standard gnu C library. I was under the impression that printf flushed the buffer if there was a newline described in the format string, however the following code repeatedly seemed to buck that trend. Could someone clarify why the buffer is not being flushed.
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
int main()
{
int rc;
close(1);
close(2);
printf("HI 1\n");
fprintf(stderr, "ERROR\n");
open("newfile.txt", O_WRONLY | O_CREAT | O_TRUNC, 0600);
printf("WHAT?\n");
fprintf(stderr, "I SAID ERROR\n");
rc = fork();
if (rc == 0)
{
printf("SAY AGAIN?\n");
fprintf(stderr, "ERROR ERROR\n");
}
else
{
wait(NULL);
}
printf("BYE\n");
fprintf(stderr, "HI 2\n");
return 0;
}
The contents of newfile.txt after running this program is as follows.
HI 1
WHAT?
SAY AGAIN?
BYE
HI 1
WHAT?
BYE
No, the standard says that stdout is initially fully buffered if the output device can be determined to be a non-interactive one.
It means that, if you redirect stdout to a file, it won't flush on newline. If you want to try and force it to line-buffered, use setbuf or setvbuf.
The relevant part of C99, 7.19.3 Files, paragraph 7, states:
At program startup, three text streams are predefined and need not be opened explicitly - standard input (for reading conventional input), standard output (for writing conventional output), and standard error (for writing diagnostic output). As initially opened, the standard error stream is not fully buffered; the standard input and standard output streams are fully buffered if and only if the stream can be determined not to refer to an interactive device.
Just keep in mind section 5.1.2.3/6:
What constitutes an interactive device is implementation-defined.
It is flushed if the output device is an interactive one e.g., a terminal.
You have to flush the output buffer in case the output device can be determined to be non-interactive e.g., a file. New line does not do that automatically.
For details see paxdiablo's answer.
You've got a strange sense of humor. :)
int main()
{
int rc;
close(1);
close(2);
printf("HI 1\n");
fprintf(stderr, "ERROR\n");
You close the filedescriptors used for stdout and stderr, and then immediately try to use the C stdout and stderr FILE streams. Not a great idea, I'm not sure what the C library will do to report the error to you but crashing would be one acceptable possibility.
That oddity aside, when you're using the standard IO stream functions to write, the buffering depends in part upon the destination. If you're writing to a terminal, then usual behavior is line buffering. If you're writing to a pipe, a file, or a socket, then the usual behavior is block buffering. You can change the buffering behavior with the setvbuf(3) function. Full details of the buffering behavior are in the manpage.

write() to stdout and printf output not interleaved?

#include <stdio.h>
#define MAXLEN 256
int main() {
int n;
char buf[MAXLEN];
while((n = read(0,buf,sizeof(buf))) != 0){
printf("n: %d:",n);
write(1,buf,n);
}
return 1;
}
The output of the program (where the first read and first write is typed by the user and echoed by the terminal) is:
read
read
write
write
n: 5:n: 6:
The output of printf comes after pressing Ctrl+D at the standard input and not along with the subsequent reads. Why does this happen?
Printf is buffered.
You can force printf to 'flush' its buffer using the fflush call:
#include <stdio.h>
#define MAXLEN 256
int main() {
int n;
char buf[MAXLEN];
while((n = read(0,buf,sizeof(buf))) != 0){
printf("n: %d:",n);
fflush(stdout); /* force it to go out */
write(1,buf,n);
}
return 1;
}
In general, printf() being buffered is a good thing. Unbuffered output, particularly to visible consoles that require screen updates and such, is slow. Slow enough that an application that is printf'ing a lot can be directly slowed down by it (especially on the Windows platform; Linux and unixes are typically impacted less).
However, printf() being buffered does bite you if you also fprintf(stderr,) - stderr is deliberately unbuffered. As a consequence, you may get your messages with some printf() missing; if you write to another FILE handle that is also associated with the terminal, and might be unbuffered, make sure you first explicitly fflush(stdout).
The manpage for fgets tells me:
It is not advisable to mix calls to input functions from the stdio
library with low-level calls to read(2) for the file descriptor associ‐
ated with the input stream; the results will be undefined and very
probably not what you want.
So the best solution would be not to to use write and printf on the same descriptor.
Printf is using stdio and it is buffered.
Push it out by sending a changing to "n: %d:\n"
You can use the std fflush() function to flush the std out buffer or you can make use of an additional \n at the end of the control string inside the printf. Something like this
printf("\n :%d:\n",n);
Its always better to use the write() & read() functions in C instead of printf() and scanf(). Printf and scanf have got some problems like printf stores the string parameter in stdout buffer. So a manual flush is required which is done through fflush function or by means of \n. In a small hello world printing program you will not find such a problem as the stdout buffer is flushed at the end of the program execution. Better use write() which works fine. scanf also have the problem of reading spaces and a lot of other problems related to stdin buffer.
For example in the code below:
main() { char a; int i=0,c; for(;i<2;i++) { scanf("%d",&c); scanf("%c",&a);} }
The above program as got the problem of reading \n into stdin on pressing enter. We could resolve this but not flushing the stdin buffer or making use of \n character. Always better to use the read() and write() functions.
Hope that helps....
Use fwrite (streams version) rather than write.
Note that, while is associated with file number 1, it isn't the same thing.

Resources