I know the basics of scanf(); requiring a conversion specifier % and an address to the variable to store the input value &.
While doing an assignment, there was a task that involved inputting an arbitrary number of values, one example would be:
5 4 3 2 1
Into scanf, and then print out number of symbols corresponding to the integer typed (eg. '?'), so it would display the terminal as:
5 4 3 2 1
?????
????
???
??
?
In this case I had put the scanf in a while loop as so:
int i, num;
while(scanf("%d",&num)==1){
printf("%d",num);
for (i=0; i<num; i++){
printf("?");
}
printf("/n");
}
I am totally confused how scanf reads multiple integers in one input line (5 4 3 2 1) when many sources has specified that scanf only takes one integer until it reads a whitespace. From looking at this, my understanding is that the whitespace separating the integers indicate a new iteration following the previous integer?
When I tried to trace how printing works, it printed as:
5 4 3 2 1
5?????
4????
3???
2??
1?
...So my question is how does scanf 'save' all these integers in one line to 'num' and print EACH of the corresponding symbols to the values given AFTER input? Wouldn't integers be replacing the previous in the variable without an array?
Sorry if this question does not make sense - still quite new to coding. Thank you!
Your understanding of scanf is true, scanf only takes one integer until it reads a whitespace.
What makes you confused here is how the algorithm works. Your algorithm first reads the integer 5 and prints "immediately" five ?. It continues to read 4, print four ?, read 3, print three ?, and so on.
scanf stores the line in an internal buffer. If the buffer is not empty, it tries to read from the buffer and remove the portion that was successfully read; if the buffer is empty it waits for user input. On the first iteration of your outer loop (while), the buffer is empty. You input "5 4 3 2 1", so the buffer contains that. The first sscanf("%d",&num) reads the first integer from the buffer, which is 5; the buffer now contains " 4 3 2 1". On the second iteration you read 4, and the buffer will be " 3 2 1". This goes on until the buffer is exhausted. At this point your program continues; it just waits for more input.
scanf 'reads' characters from the standard input stream stdin (if there is nothing there yet it prompts the user to type something to be added to it), and converts them to a format depending on the conversion specifiers used in the format string.
You can think about stdin as a sequence of characters in the memory, and every time the user types something in the terminal and presses Enter what was typed is added to the stdin.
So in your case, when you type 5 4 3 2 1 and presses Enter in the terminal, stdin will receive the sequence of characters "5 4 3 2 1\n" (notice that the new line character was added when you pressed Enter).
Then the scanf("%d",&num), which is expecting only 1 decimal integer number, 'reads' and 'consumes' from stdin the relevant characters that form one continuous decimal integer number.
In this case 5 is read the first time scanf is executed, and " 4 3 2 1\n" is left in the stdin. Then as the condition is satisfied the loop statements are executed. And the second time scanf is executed the leading space is discarded by the %d specifier and 4 is read, leaving " 3 2 1\n" in the stdin. And so on until no decimal integers numbers can be read from the stdin...
Wouldn't integers be replacing the previous in the variable without an array?
There's no array required here at all.
The scanf() function takes the value (assuming white spaces included) and all of them are saved one by one into the variable num. If you use a debugger (suppose using GDB) and set a breakpoint in while(), you'll get to know by stepping into that the variable num is changed in each iteration and the for loop runs till num is reached.
An example of two iterations using a debugger is provided below (focus on num on the left corner):
Iteration 1:
Iteration 2:
Related
The program in question:
#1:
int main(void) {
int size;
scanf("%d", &size);
int v[size];
for(int i = 0; i < size; ++i) {
scanf("%d", &v[i]);
printf("the %d-th element is : %d\n",i, v[i]);
}
return 0;
}
O/P:
5
6 7 8 9 10 11
the 0-th element is : 6
the 1-th element is : 7
the 2-th element is : 8
the 3-th element is : 9
the 4-th element is : 10
My question: Why does it seem like the program does all the print statements after your input?
So does the program kind of 'hold' the print statements to display them after you press <Enter> for a new-line? Is there a better explanation of this behavior somewhere?
**Edit after #dbush's answer**
I need a bit of a clarity on this: so let's say the `size = 5` & my input is `6 7 8 9 10` so I'm asuming the first `scanf` in the loop reads the `6 ` part then reads/stores the data and then passes the rest of the content that's in the input buffer to the next `scanf`'s leaves the rest of the input data in the `input buffer`
Then the program goes towards the printf statement stores that output in some sort of a buffer then it loops back to the 2-nd scanf and that reads the 7 part and all of this goes till the 10<enter> part, now the final scanf reads/stores 11 and since there's a newline, the programs decides that it no longer needs to read from the input buffer and now outputs the rest of the contents from the output buffer to the console.
Is this how it goes or are there some inaccuraries in this analogy?
Edit #2: I found this good blogpost explaining what goes on with scanf's & the input buffer, together with #dbush & #Weather Vane answers to completely answer any doubts I've had regarding this
When reading from a terminal, nothing gets sent to scanf until you press ENTER.
So in your case, you have 6 strings which look like numbers in the input buffer. The first scanf reads just the first number, because that's what its pattern is looking for and leaves the rest in the input buffer. Then the program continues by calling printf, and because the string ends with a newline it gets printed immediately. When the program then loops back around to scanf, there's already data in the input buffer so it reads what's there and returns immediately, and the cycle continues.
So only the first call to scanf is waiting for input from the user, while the others are reading what's already in the input buffer, and the printf calls are having their output go to the terminal immediately since the string to print ends with a newline.
i am new to c and have used python before. This whole buffer overflow stuff is really breaking my mind.
#include <stdio.h>
int main(){
char str1[3];
while(true){
scanf("%2s", str1);
printf("test\n");
}
}
This is a little code i've written to test the syntax and the stdio library. I was really suprised when the program outputted "test" multiple times, depending on how many characters i entered. So for example, when I entered two characters, it printed "test" two times. Can anyone please tell me why this is happening and how I can fix it?
You can figure out what happens by modifying your code as follows:
#include <stdio.h>
int main(){
char str1[3];
while( 1 ){
scanf("%2s", str1);
printf("test: %s\n", str1);
}
}
which simply prints the contents of the str1 alongside of the "test" string.
Here is an example output for an input string of 1234567:
1234567
test: 12
test: 34
test: 56
test: 7
The scanf("%2s", str1); statement reads two characters from the stdin and assings them to the str1. The read characters are "popped" from the input stream, i.e., they are removed. If the stdin happens to contain more characters, the excess ones are left untouched. Therefore, for the given input, when the first scanf is returned, the str1 containes 12\0, and the stdin contains 34567.
Since these are in the infinite loop, the code repeats, scanf gets called again, reading the first two characters from the stdin again, only this time finds 34.
And the process repeats, untill there are no characters left on the stdin, then the scanf waits for the user input, presumably as you would have expected.
Basically, scanf keeps reading instead of waiting for user input, since the stdin already contains something to read.
So for example, when I entered two characters, it printed "test" two times.
This on the other hand, does not make sense, as it should be printing "test" for N/2 times, rounded up, where N is the number of characters you enter.
There is not much that I can suggest for "fixing this", since it is not really clear what you are expecting. But if you want to get rid of the remaining characters in the stdin, you can check this.
You need to clear your input buffer as per this answer
Otherwise, you'll read from the stdin, print it, jump back to the loop head and continue reading, if there is still something in the buffer.
Each time through the loop, scanf("%2s", str1) reads at most 2 non-whitespace characters from the input stream. If there are more than 2 non-whitespace characters available in the stream, the loop will continuously call scanf (and printf) until scanf blocks waiting for data. If the input stream contains ffff\n and has not yet been closed (eg, a user is entering data interactively from a tty), the first 2 calls to scanf will immediately return and printf will be called twice. The 3rd call to scanf will block until more data is available, or the stream is closed, or there is an error.
IF "for loop" is like this,
for(i=0;i<5;i++)
{
scanf("%d",&a[i]);
}
Then,
Input can be given either as,
1
2
3
4
5
Hitting Enter Every time for the next Input.
OR
1 2 3 4 5
With space character between different input values.
Now, How does this thing work?
I mean if loop is running,
then how does it recognizes that Input is given for the next loop cycle wihtout hitting the Enter key.
How does this thing work?
This works because scanf() reads only till a space or newline or tab is encountered.
So, when you give input 1 2 3 4 5, at the first iteration scanf() reads 1 and a space is encountered and scanf() terminates keeping the value 1 to a[0]. At the next iteration2` is read the same way.
The scanf (and family) function with the "%d" format reads white-space delimited input. If the white-space is a newline or a single space doesn't matter.
The Enter key simply tells the input stream system that input is ready (stdin which is used by scanf is line buffered by default), exactly what that input is doesn't matter.
When I run this small code and enter 3 integers on the console, it doesn't print out as it should due to the fwrite statement. It prints only after I keep hitting enter for some time. Help?
P.S: Learning faster ways than scanf and printf.
#include<stdio.h>
int main(){
int size[3];
fread(&size,sizeof(int),3,stdin);
fwrite(&size,sizeof(int),3,stdout);
fflush(stdout);
return 0;
}
This is because fread reads binary data, not formatted text, so when you tell it to read 3 "ints" it will read 3*4=12 bytes of raw data from stdin. If you type "1" "2" "3" that's only three bytes of text, plus three newlines. Once you type twelve bytes it will probably get past that part, but then your program is probably broken, assuming you wanted to read and write actual text.
You mean you're "learning faster ways than scanf and printf." Well, this is not a faster way, it's just a broken way. If you're having a performance issue in some code using scanf & printf, please ask a separate question and we can help with that.
Size of int is 4 bytes so your fread() will try to read 12 bytes (4 * 3).
When you enter something like this on console
1 2 3
it is 6 chars = 3 numbers + 2 spaces + 1 \n
Hence you would have to press enter at lease 6 times so that it reads 6 more bytes.
Better to use scanf() to get integers as
scanf("%d %d %d", &size[0], &size[1], &size[2]);
The %n format specifier,when used in a scanf() is expected to store the count of the number of characters of the format string already processed by the function into an argument of type int*.According to the definition:
The number of characters of the format string already processed is stored in the pointed location.
But in my program,it works so in all but the first scanf().In all scanf()s in my program,excluding the first one,it stores the count of the total number of characters entered from the console,including the newlines (Enter keys).But in the first scanf(), the count is one less than the total count of characters and newlines entered from the console.
Please explain this anomaly as it's really frustrating that I can't detect this simple bug.
#include <stdio.h>
int main ()
{
int a,b,c,d,count;
printf("First Trial\n");
scanf("%d%d%d%d%n",&a,&b,&c,&d,&count); //OUTPUT ANOMALY HERE
printf("count=%d\n",count);
printf("Second Trial\n");
scanf("%d%n",&a,&count);
printf("count=%d\n",count);
printf("Third Trial\n");
scanf("%d%d%n",&a,&b,&count);
printf("count=%d\n",count);
printf("Fourth Trial\n");
scanf("%d%n%d",&a,&count,&b);
printf("count=%d",count);
}
Sample Output
First Trial
253
34
4
83
count=11
Second Trial
25
count=3
Third Trial
234
38
count=7
Fourth Trial
3534
35
count=5
Why in the first trial we get "11" instead of "12?That's my doubt.
CRUCIAL EDIT
Another finding.If for the first scanf(),instead of using Enter keys(newlines) to separate the numbers entered, if I use space,lots of whitespace,then all those whitespace are counted by count as well.For example I get count=21.It means the newlines,spaces,everything is being considered.But why it is one less for first trial?
First Trial
25 35 38 98
count=21
excluding the first one,it stores the count of the total number of characters entered from the console,including the newlines (Enter keys)
You are misinterpreting that. The scanfs do not consume the final newlines used to send the input to the programme, therefore the newline is left in the buffer to be consumed by the next scanf. All but the first scanf consume the newline from the previous input as the first character.
The first scanf consumes the eight digits plus the three newlines between the four numbers, that makes 11 characters.
The second consumes the newline from after the fourth number read in the first scanf, plus the two digits, makes 3 characters.
The third: newline, three digits, newline, two digits: 7 characters.
The fourth: newline, four digits: 5 characters. (then newline + 2 digits for b)
By the way, your quote
The number of characters of the format string already processed is stored in the pointed location.
is incorrect, it's not the number of characters of the format string, but the number of characters read from the input stream:
The corresponding argument shall be a pointer to
signed integer into which is to be written the number of characters read from
the input stream so far by this call to the fscanf function.