Return value of scanf() - c

Here is my code to repeatedly read three variables separated by whitespace from user. The format of input should be 'char int int'(e.g b 3 3 ). I use the return value of scanf function to ensure input is exactly three variables.
#include <stdio.h>
int main(void){
int x, y, nargs;
char command;
while(1){
nargs = scanf("%c %d %d", &command, &x, &y);
printf("%d\n",nargs);
if(nargs != 3){
printf("error\n");
break;
}
}
return 0;
}
Input and Output:
g 4 4
3
b 3 3
1
error
The first line input is no problem. But when I input second line, it shows scanf() only read one variable from this line. What's the problem of my code?

The problem is the \n newline hidden between the two input lines you are sending to stdin. After first scanf you have a '\n' pending on the input stream, then you append "b 3 3" so the whole buffer looks like "\nb 3 3".
Then scanf is called again and \n is matched to %c, after scanf expects whitespace but the buffer has 'b' so it fails after assigning \n to command.
You could try matching with
nargs = scanf("%c %d %d ", &command, &x, &y);
^
so that newline is eaten with the previous scanf, from cppreference:
any single whitespace character in the format string consumes all available consecutive whitespace characters from the input

nargs = scanf("%1s %d %d", &command, &x, &y);
The problem is with the %c for one character. If you change it for %1s you expect an string of one character (the same) but without problems.
With the %c it is better to send the result to an array, and access the content with its index.

Related

C Programming - Role of spaces in scanf()

I wrote the following code:
#include <stdio.h>
int main()
{
int a, b;
printf("Enter values of a and b\n");
scanf(" %d%d ", &a, &b); // Note the two spaces before and after %d
// ^This^
printf("a = %d b = %d\n", a, b);
return 0;
}
The program run something like this:
aps120797#XENON-PC:/mnt/d/Codes/LetUsC$ ./a.out
Enter values of a and b
1
2
3
a = 1 b = 2
My question is that why is it taking three inputs instead of two (two %d is in scanf() ) and even if it is taking three, why is it skipping the last one?
Space in a format string means to skip over any sequence of whitespace (spaces, newlines, tabs) in the input, and stops scanning when it gets to the first non-white character or the end of the input. That next character is left in the input buffer, so it can be read by the next format operator (if there is one) or the next input operation (if you were to call getc() after your scanf(), it would read the '3' character.
When you put a space at the end of the format string, it skips over the newline after 2, and keeps scanning until it gets to the next non-white character. So it has to get to the 3 before it stops.

scanf() function with different format specifier

Below is a program which accepts two character and prints them
#include<stdio.h>
int main()
{
char c1, c2;
printf("\n Enter characters one : ");
scanf(" %c", &c1);
printf("\n Enter character two : ");
scanf("%c", &c2);
printf("\n The the characters are %c and %c ", c1, c2);
return 0;
}
Now one output instance is :-
Enter two characters : a
The the characters are a and
The problem is that I haven't given any space between two format specifier %c
Here I pressed 'a' and then '\n' which gets stored into c1 and c2 respectively. And thus I got output which was not accepted.
I know how to correct this problem.
Now I make the same program for the integers :-
#include<stdio.h>
int main()
{
int a, b;
printf("\n Enter two numbers : ");
scanf("%d%d", &a, &b);
printf("\n The two numbers are %d and %d ", a, b);
return 0;
}
Here we will not found any problem.
I think this time we didn't encounter problem because the second input we give is '\n' or space which is not any integer and thus we get a failure in the reading from the scanf() function so the input buffer is still active and if we press the next input as integer then it gets stored into variable 'b'.
Can you tell me the reason which I thought is correct or not?
Now if it is correct then what will happen if I press again a character. Then also it should not get stored into the variable 'b' but this time 0 gets stored into variable 'b'.
So my question is that what is the reason for proper behavior of the program when I'm trying to make the same program with %d
To answer your question, let's have a look at C11 standard, chapter ยง7.21.6.2
Input white-space characters (as specified by the isspace function) are skipped, unless
the specification includes a [, c, or n specifier.
So, when you have a newline ('\n', which is indeed a white-space character) left in the input buffer,
in case of scanf("%c", &charVar);, the newline is considered as the input, so the second scanf skips asking for the input from user.
in the case of scanf("%d", &intVar); the leftover newline is skipped and it wait for the integer input to appear, so it stops and asks the user for the input.
However, FWIW, in later case, if you input a non-whitespace character and press ENTER, the char input will be considered as an input, causing a matching failure.
Related
[...] If
the input item is not a matching sequence, the execution of the directive fails: this
condition is a matching failure.
It's reading the new line as the newline is a character. Simply changing scanf("%c", &c2); to scanf(" %c", &c2); will make it work.
So in your code:
#include
int main()
{
char c1, c2;
printf("\n Enter characters one : ");
scanf(" %c", &c1);
printf("\n Enter character two : ");
scanf(" %c", &c2);
printf("\n The the characters are %c and %c ", c1, c2);
return 0;
}

why does fscanf read garbage values

I have a simple file as below:
1
3
a 7
and when I run the code below, I get some unexpected result. I initially try to read the first two integers and then read the character a and number 7. There is no white space after the number 1 or 3.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
main(int argc, char **argv)
{
FILE *f;
f = fopen(argv[1],"r");
int num1, num2, num3;
char t;
fscanf(f, "%d",&num1);
fscanf(f, "%d",&num2);
fscanf(f, "%c %d", &t, &num3);
printf("%c %d\n", t, num3);
}
EDIT:
Input is the file with the content:
1
3
a 7
and the output is a new line and some garbage. Expected output should be a 7
EDIT 2: it reads correctly 1 and 3. Then trying to read a single character a if fails
Loooks at what happens when you run this:
fscanf(f, "%d",&num1);
skips whitespace (of which there is none), then reads an integer (1)
fscanf(f, "%d",&num2);
skips whitespace (the newline at the end of the first line) then reads an integer (3)
fscanf(f, "%c %d", &t, &num3);
reads the next caharcter from the input (a newline), then skips whitespace (none) and tries to read an integer. The next input character is 'a', so this fails, and the fscanf call returns 1 without writing anything into num3.
So the problem you are having is that due to the fact that %c does NOT skip whitespace, you are reading the whitespace (newline) instead of the character you expect. The most obvious solution is to add a space () to the format to skip whitespace:
fscanf(f, " %c%d", &t, &num3);
Note that I've also removed the space before %d, as it is redundant (%d always skips whitespace).
In addition, it is always a good idea to check the return value of fscanf to make sure it is reading the number of input items you expect.

scanf works before its execution point

I tried a simple program..function returning integer and character pointer..after i run that code i found some weird acting by scanf..I tried to print message(enter a,b:) read two integer inputs and message(enter c,d:) read two char inputs.but at run time..i found that input for the char c is read rightafter i enter the inputs for a,b..
for eg:
enter a,b: 10
20
enter c,d: g
it gets only one input(for d) and input for c is newline after 20..
for eg 2:
enter a,b: 10
20a
enter c,d: g
it gets only one input(for d) and input for c is a after 20..
why is this happening..please clarify it
int* add(int *a,int *b)
{
return (*a>*b?a:b);
}
char* charret(char *c,char *d)
{
return (*c>*d?c:d);
}
int main()
{
int a,b;
char c,d;
printf("\n\t\tFUNCTION RETURNING INTEGER POINTER\n\t");
printf("Enter the Number A and B:");
scanf("%d %d",&a,&b);
printf("\tEnter the character c :");
scanf("%c %c",&c,&d);
printf("The Biggestt Value is : %d\n\t",*add(&a,&b));
printf("\n\tThe character c= %c hi d= %c",c,d);
// scanf("%c",&d);
printf("\n\tThe Biggestt Value is : %c", *charret(&c,&d));
getch();
return 0;
}
%c will read any character, including the newline character from your previous entry. If you want to read the first non-whitespace character, add a space before %c in your format string:
scanf(" %c %c",&c,&d);
/* ^ added space */
This will cause scanf() to eat any number of whitespaces before reading the character.
For most scanf() specifiers, any leading whitespace is skipped. %c is an exception to this, because it reads a single character value, including whitespace characters. Keep in mind when you press Enter, you've sent a '\n' to the input buffer.
scanf("%d %d",&a,&b);
Reads in two numbers. The \n at the end, from pressing Enter, is left in the buffer.
scanf("%c %c",&c,&d);
Reads in two characters, the first of which will be the \n left in the buffer. One way to get around this is:
while (getch() != '\n');
This will eat everything up to an including a newline. You can put that after the scanf() lines you know will leave a newline behind.

read the data and skip parenthese with scanf

I write a C program to pick the data from the the std input, which starts with a number indicating the number of the data sets, then there are N pairs of data, in the form: (x y), so I write the code as below:
#include <stdio.h>
int main()
{
int n_sets;
scanf("%d", &n_sets);
int i;
for(i = 0; i < n_sets; ++i)
{
int m, n;
scanf("(%d %d)", &m, &n);
printf("%d\t%d\n", m, n);
}
return 0;
}
but it doesn't work. After I input the number of the data set, the program print the uninitialized m&n directly. But when I add a space before the (%d %d), it works fine. Somebody can explain this?
When you have character literals in your argument to scanf(), it expects to find those literals exactly as specified in the format string.
scanf("%d", &n_sets);
correctly reads n_sets, and stops at the newline or other whitespace character in the buffer. The next scanf() :
scanf("(%d %d)", &m, &n);
expects to find an open parenthesis at the beginning of the input, but finds a whitespace character instead. So it fails, and scanf() returns without having read anything. Consequently, your m and n remain uninitialized, and garbage results.
When you put in the space before the open parenthesis like so:
scanf(" (%d %d)", &m, &n);
it tells scanf() to skip any leading whitespace before the parenthesis in the input buffer, so the program works correctly.
change
scanf("%d", &n_sets);
to
scanf("%d\n", &n_sets);
and input your n_sets ending up with a [enter], it works.
Assuming your input is like this:
2 (1 2) (3 4)
There is a space(or new line?) after the first number, so change the scanf in the loop to:
scanf("\n(%d %d)", &m, &n);
// ^^
It sounds like the input into the program has some amount of whitespace before the value you want scanf to parse. The space in the string tells scanf to ignore whitespace. Without it, scanf is looking for an exact match immediately.

Resources