Console I/O : printf & scanf not occurring in expected order - c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void eat() // clears stdin upto and including \n OR EOF
{
int eat;while ((eat = getchar()) != '\n' && eat != EOF);
}
int main(){
printf("\n COMMAND : "); char cmd[21]=""; scanf("%20s",cmd);
if(strcmp(cmd,"shell")==0||strcmp(cmd,"sh")==0)
{
getchar(); // absorb whitespace char separating 'shell' and the command, say 'ls'
while(1)
{
printf("\n sh >>> "); // print prompt
char shellcmd[1024]=""; // str to store command
scanf("%1023[^\n]",shellcmd); eat(); // take input of command and clear stdin
if(strcmp("close",shellcmd)==0||strcmp("x",shellcmd)==0)
break;
else
system(shellcmd);
}
}
}
In the code, some anomalous behavior is occurring which I'm unable to catch.
Upon entering sh ls and pressing [ENTER], the expected response is:
1st scanf() stored sh in cmd[] and leaves ls\n in stdin.
getchar() takes up the space.
printf() prints \n sh >>> to Terminal
second scanf() stores ls in shellcmd[], leaves \n in stdin
eat() reads the \n from stdin, leaving it empty
system("ls") is executed
I.e. results should be like this:
COMMAND : sh ls
sh >>>
file1 file 2 file3 ...
sh >>> | (cursor)
BUT
What I get:
COMMAND : sh ls
file1 file2 file3 ...
sh >>>
sh >>> |
Apparently, the 2nd scanf() and shell() are executing before printf() , or at least that's my assumption.
What's amiss?
Compiled on Clang and GCC with cc -Wall -Wextra -pedantic and tested on bash on MacOS as well as Linux

As you can find in the man page:
If a stream refers to a terminal (as stdout normally does) it is line buffered
So you might experience a delay in seeing the message printed by printf whenever it doesn't contain a newline. On the other end, the previos message is displayed as soon as the leading newline of the next printf is sent.
Solutions:
Add a newline at the end your message printf("\n sh >>> \n");
Force the current buffer to be displayed even in absence of a newline by calling flush() function (fflush(stdout))
Change the current stdout buffering behavior with setvbuf() function
setvbuf(stdout,NULL,_IONBF,0);

Related

No output on a character count while loop

I follow the book C programing second edition and try to output this code:
#include <stdio.h>
main()
{
long nc;
nc = 0;
while(getchar() != EOF)
++nc;
printf("%1d\n", nc);
}
and I can't figure out why I don't have any output.
I work on crunchbang++ and to create the output I entered in the terminal:
cc -ansi file.c
then
./a.out
but when I enter characters I have a blank response.
I don't want just the working code, but an explanation, because I really want to learn how it works.
#include <stdio.h>
int main(void)
{
long num_of_chars = 0;
while(getchar() != '\n'){
++num_of_chars;
}
printf("%ld\n", num_of_chars);
}
EOF means End of File.
EOF is not a character. It is a state which indicates no more characters to read from a file stream. When you enter EOF command from the terminal, you are signalling the OS to close the input stream, not putting in a special character.
Now either you can change your code to read a file, emulate EOF, or cancel while loop on different character.
Above example will end while loop on new line.
$ ./main
This is a test
14
Edit:
Tested on linux with EOF.
Ctrl + Z will outright stop the program.
Ctrl + D will output num_of_chars if pressed twice or by doing Enter and then Ctrl + D.
Edit 2:
With EOF.
printf foo | ./your_program Output: 3
echo foo | ./your_program Output: 4 (echo adds newline caharacter)

C program to output characters produces integers instead

I'm writing a program called split.c that takes from the stdin an input.txt file as input and then sends every other word within the input file to stdout and stderr.
My current codes is as follows:
#include <stdio.h>
int main(){
int input;
// keep getting characters until end-of-file
while ((input = fgetc(stdin)) != EOF){
// prints to stdout
fprintf(stdout, "%d", input);
if(input == " ")
printf("\n"); // encounters whitespace so print new line
// prints to stderr
fprintf(stderr, "%d", input);
if(input == " ")
printf("\n"); // encounters whitespace so print new line
}
return 0;
}
In ubuntu I run make then the command ./split < test/input.txt > myout.txt 2> myerr.txt
The expected output should be, for example.
If input.txt has the following: "Is my code working?"
The output should be:
In myout.txt:
"Is
code
In myerr.txt:
my
working?"
Instead I get the following in both files, a huge number:
6511032731101001051181051001179710...............
Any idea was to what may be wrong with the code? Is my thought process wrong? The idea is that it gets the input file, reads each character and then, when a whitespace is found, it prints a new line in stdout, then does the same thing, but now printing to stderr until it reaches EOF.
I'm still learning the in's and out's (pun intended :) ) of using stdin/out/err so I'm not surprised if I'm not coding correctly. Any guidance is appreciated!
You are using the %d specifier that interprets the corresponding argument as a number. You should be using %c to interpret the corresponding argument as a character.

Terminate C program which stdin is linked to output of other program

I have a program x, which I want to cleanly terminate.
You can run it by simply doing ./x and use the terminal to write lines to stdin directly and terminate it by writing exit.
However, if you use: cat file.txt | ./x, the stdin is now piped from the file and therefore you can never type exit.
The best way to end this program would be for it to automatically terminate once the last line was read from the file.
Alternatively, I'd like to re-route stdin back to the terminal if that is at all possible, to further allow manual input as before.
Here is some sample code:
int main() {
// ...
while (ongoing) {
size_t n = 0;
char* ln = NULL;
getline(&ln, &n, stdin);
strtok(ln, "\n");
strtok(ln, "\r");
if (strcmp("exit", ln) == 0) {
break;
}
//...
}
}
you're using getline to read your input. getline returns -1 on EOF. This makes it easy.
if (-1==getline(...))
break;
When you have read all the input from a pipe, EOF will be raised up to indicate that the full input has been reached.
In your example, this will be rougly equivalent with exit, so you can also check the return value of getline to see if the EOF has reached (in which case -1 will be returned).

Unable to understand behaviour of "system" function call in C program

When I run the following program, the output of system("ls -l") is displayed before that of printf. Why does it happen?
#include<stdio.h>
int main()
{
printf("\nHello world");
system("ls -l"); // output of this statement is displayed before that of the preceding
// printf statement
return 0;
}
Thanks.
printf is buffered. AFAIK the buffer is written to the output only when a there is a \n or when you explicitly flush it (via fflush(3)).
So what happens is, printf writes the \n to the output, then buffers the rest of your string. Then ls -l is executed and when your program finishes the buffer is flushed automatically.

EOF in Windows command prompt doesn't terminate input stream

Code:
#include <stdio.h>
#define NEWLINE '\n'
#define SPACE ' '
int main(void)
{
int ch;
int count = 0;
while((ch = getchar()) != EOF)
{
if(ch != NEWLINE && ch != SPACE)
count++;
}
printf("There are %d characters input\n" , count);
return 0;
}
Question:
Everything works just fine, it will ignore spaces and newline and output the number of characters input to the screen (in this program I just treat comma, exclamation mark, numbers or any printable special symbol character like ampersand as character too) when I hit the EOF simulation which is ^z.
But there's something wrong when I input this line to the program. For example I input this: abcdefg^z, which means I input some character before and on the same line as ^z. Instead of terminating the program and print out total characters, the program would continue to ask for input.
The EOF terminating character input only works when I specify ^z on a single line or by doing this: ^zabvcjdjsjsj. Why is this happening?
This is true in almost every terminal driver. You'll get the same behavior using Linux.
Your program isn't actually executing the loop until \n or ^z has been entered by you at the end of a line. The terminal driver is buffering the input and it hasn't been sent to your process until that occurs.
At the end of a line, hitting ^z (or ^d on Linux) does not cause the terminal driver to send EOF. It only makes it flush the buffer to your process (with no \n).
Hitting ^z (or ^d on Linux) at the start of a line is interpreted by the terminal as "I want to signal EOF".
You can observe this behavior if you add the following inside your loop:
printf("%d\n",ch);
Run your program:
$ ./test
abc <- type "abc" and hit "enter"
97
98
99
10
abc97 <- type "abc" and hit "^z"
98
99
To better understand this, you have to realize that EOF is not a character. ^z is a user command for the terminal itself. Because the terminal is responsible for taking user input and passing it to processes, this gets tricky and thus the confusion.
A way to see this is by hitting ^v then hitting ^z as input to your program.
^v is another terminal command that tells the terminal, "Hey, the next thing I type - don't interpret that as a terminal command; pass it to the process' input instead".
^Z is only translated by the console to an EOF signal to the program when it is typed at the start of a line. That's just the way that the Windows console works. There is no "workaround" to this behaviour that I know of.

Resources