Improper scanning in C - c

I want to scan a character immediately after scanning a long type in C.But it fails when I use this code.It scans properly only if I define a separate scanning function for character.Can anyone tell me why it is so?
Code:
#include <stdio.h>
int main()
{
int a;
long b;
char c;
float d;
double e;
scanf("%d%ld%c", &a, &b, &c);
scanf("%f%lf", &d, &e);
printf("%d\n%ld", a, b);
printf("\n%c\n%.3f\n%.9lf", c, d, e);
return 0;
}
Input:
3 12345678912345 a 334.23 14049.30493
Output:
3
12345678912345
0.000
0.000000000
Why is it so?

c Matches a sequence of characters whose length is specified by
the maximum field width (default 1); the next pointer must be a
pointer to char, and there must be enough room for all the char‐
acters (no terminating null byte is added). The usual skip of
leading white space is suppressed. To skip white space first,
use an explicit space in the format.
3 12345678912345 a 334.23 14049.30493
^
The %c in your code matches the first space character following "12345678912345". That leaves the "a" to match with %f. It is not a match so the second scanf() call fails (and returns 0 for no matches).
RETURN VALUE
These functions return the number of input items successfully matched
and assigned, which can be fewer than provided for, or even zero in the
event of an early matching failure.
As pointed out in the comments above, your problem goes away if you add a space to your format string before the %c - it will then skip the whitespace and match on the 'a'. Then the pointer will move past the 'a' and the second scanf will work correctly.
int number_matched;
number_matched = scanf("%d%ld %c", &a, &b, &c)

Related

(C) Scanf - input gets 0 every time

Each time i set a value in b after a, the value is reset to 0 in a.
In other words, as the code goes, no matter what i input in a it will be always 0 after the second scanf function.
EDIT: I need to use b as char type for the essay, for memory efficiency, so i can't set b to int, but i need to input integer in there.
EDIT2: I need to input an integer in b, example for an input:
1
2
from that point if i
printf("%d",a);
i get 0.
unsigned short a;
char b;
scanf("%hu",&a);
scanf("%d",&b);
You are using the wrong format specifier with
scanf("%d", &b);
It should be
scanf("%c", &b);
However since there is a previous scanf statement there is a newline still in the buffer, and to filter that out you can use
scanf(" %c", &b);
Most format specifiers automatically filter out leading whitespace but %c and %[] and %n do not.
It is unclear from the mistake whether the format specifier is at fault, or the variable type.
%d requires an int:
int b;
Then, you should check the return value of your scanf() calls. Do both calls return 1?
(scanf() returns the number of input items assigned. Because both your calls have one %..., you must return 1 in both cases.)
with char b; and scanf("%d",&b);, scanf will write sizeof (int) bytes to b.
This will corrupt other memory.
scanf("%hhd",&b); will only write one byte to b.

What is the specific reason for the runtime error I'm getting here?

#include<stdio.h>
#include<string.h>
void main()
{
char a,b,c;
printf("Enter alien names:\n");
scanf("%s\n%s\n%s\n",a,b,c);
printf("The alien names are %s, %s and %s. A meteor hit %s's spaceship. A star scratched %s\'s spaceship. But %s fixed %s and %s\'s spaceships. The three became friends and are from the planet BYG (which means BLUE YELLOW GREEN)",a,b,c,a,b,c,a,b);
}
What is the specific reason for the runtime error I'm getting here?
To solve this issue you should simply consider to use strings (arrays of chars) to contain the different names.
Here is an example how to do that:
void main()
{
// The string "a" can contain up to 100 symbols (chars).
char a[100];
printf("Enter an alien name:\n");
scanf("%s",a);
printf("The alien name is %s.", a);
}
The difference between "char a" and "char a[100]" is that in the first case the variable "a" corresponds to a single character and in the second it corresponds to a string - an array of chars which can contain up to 100 characters.
The posted code has undefined behavior, because the variables a, b, and c are of type char, while the %s conversion specifier in the call to scanf() is expecting a pointer to the first element of a character array that can hold the input string. Mismatched conversion specifers and arguments in a scanf() call lead to undefined behavior, and attempting to write too many characters into the receiving array causes undefined behavior.
The first problem can be fixed by declaring a, b, and c as arrays large enough to hold expected input:
char a[100], b[100], c[100];
...
scanf("%s\n%s\n%s\n", a, b, c);
Note that arrays decay to pointers to their first elements in most expressions, including function calls, so here a is a pointer to the first element of the character array a[]; this is equivalent to &a[0].
There is still a possibility for undefined behavior if the user enters too many characters. To avoid this, always specify a maximum width when using scanf() to read user input into a string. Note here that the specified width is the maximum number of characters that will be read for that input item, not including the null terminator, \0, which will be automatically added by scanf(), so the maximum width must be at least one less than the size of the receiving array:
scanf("%99s\n%99s\n%99s\n", a, b, c);
But if you compile and run this code, you will find that it does not behave as expected. After the third name is entered, the program will continue waiting for more input. This is because the \n character is a whitespace character, and when scanf() encounters a whitespace character in a format string, it reads and discards zero or more whitespace characters in the input until a nonwhitespace character is encountered, or until no more characters can be read. The %s directive tells scanf() to read characters until a whitespace character is encountered. So when the user presses Enter after the final name, scanf() completes matching input characters for the final name and returns the \n character to the input stream; then the \n is reached in the above format string, and scanf() matches the aforementioned \n character in the input stream, and any further whitespace characters that are encountered. This will end if the user enters another nonwhitespace character, or signals end-of-file from the keyboard (e.g., with Ctrl-D or Ctrl-Z).
To avoid this complication, remember that it is almost never correct to end a scanf() format string with a whitespace character. Also, there is no need to use \n rather than a space character, since both are simply interpreted as whitespace directives by scanf():
scanf("%99s %99s %99s", a, b, c);
It would further improve the posted code if the return value from the call to scanf() were checked before attempting to use the input. Since scanf() returns the number of successful assignments made, this value should be 3:
#include <stdio.h>
#include <string.h>
int main(void)
{
char a[100], b[100], c[100];
printf("Enter alien names:\n");
int ret_val = scanf("%99s %99s %99s", a, b, c);
if (ret_val == 3) {
printf("The alien names are %s, %s and %s. A meteor hit %s's "
"spaceship. A star scratched %s\'s spaceship. But %s "
"fixed %s and %s\'s spaceships. The three became friends "
"and are from the planet BYG (which means BLUE YELLOW GREEN)\n",
a, b, c, a, b, c, a, b);
} else {
puts("Input error");
}
}
What is the specific reason for the runtime error I'm getting here?
The function scanf using the format specifier %s expects to be passed the address of a char array, in which to place the input data. For example an array such as
char a[100];
However, you pass simple char variables a and b and c which can hold values in the range -128 to 127, or 0 to 255, depending on whether the implementation's char is signed or unsigned.
These variables were not even initialised, so indeterminate values were passed to scanf. But even if they had been initialised, it is very likely that the values passed will cause a segfault, when used as addresses.
My compiler issued 2 warnings for each of a, b and c passed to scanf.
warning C4477: 'scanf' : format string '%s' requires an argument of type 'char *', but variadic argument 1 has type 'int'
warning C4700: uninitialized local variable 'a' used
Please enable and act on all compiler warnings.
//There are things that shoudn't be there. Im not a pro but this is what I think.
#include<stdio.h>
#include<string.h>//you have include this library but you didn't use a function from it.
//I think what you want to do is use the str functions like strcpy
//but in this case you don't need to use it.
void main()
{
char a[25],b[25],c[25];//Here you declared a character a, b and c. But if you want to store a string, you have to declare an array of characters. So instead of a, b, c, it's a[someValue], b[someValue] and c[someValue].
//Declare an array with a size that you think will cover the whole "alien name". e.g. a[25]..
//but i don't know, maybe you did it on purpose. Maybe you just want to name the aliens with one character like A, B, C. But if you want to name the aliens with a long name, you must declare an array.
printf("Enter alien names:\n");
scanf("%s\n%s\n%s\n",a,b,c);//You don't need to put the "\n" between those "%s". "\n" means "newline". It will work without it because scanf automatically reads next set of characters when it meets white space of newline.
//--so you can remove "\n" in there and replace it with space. But you can leave it there also but you really have to remove the last "\n" because scanf will search again for the next
//--new line before it will end asking for input and pressing enter will not work because you have to type another set of characters before scanf will read the last "\n" that you put at scanF.
//Another mistake here is the format specifier that you used (%s). It doesn't match declaration because you declare char a, b, c, that will only store one character each.
//In case that you're really just storing one character each alien's name, you have to use the "%c" instead of "%s" and you must pass the reference of the char variable in
//--scanf, e.g. scanf("%c %c %c", &a, &b, &c);
//Just remember that if you plan on storing a string or a long name there, you must declare an array like I said at the beginning.
//--and if it's an array, you don't need to include the '&' on every variable when you're passing it in scanF.
//There's nothing wrong here if you're alien's names are string.
printf("The alien names are %s, %s and %s. A meteor hit %s's spaceship. A star scratched %s\'s spaceship. But %s fixed %s and %s\'s spaceships. The three became friends and are from the planet BYG (which means BLUE YELLOW GREEN)",a,b,c,a,b,c,a,b);
}
The specific reason for the runtime error is this line:
scanf("%s\n%s\n%s\n",a,b,c);
The %s conversion specifier tells scanf to read a sequence of non-whitespace characters from the input stream (skipping over leading whitespace) and store that sequence to an array of char pointed to by the corresponding argument. The problem is that a, b, and c are not pointers to char; they're single char objects that haven't been initialized. The odds of any of them containing a value that corresponds to an address that scanf can write to is almost non-existant.
First, change the declarations of a, b, and c tochar a[SOME_LENGTH] = {0}; // initialize array contents to 01
char b[SOME_LENGTH] = {0};
char c[SOME_LENGTH] = {0};
where SOME_LENGTH is a number that's long enough to contain the longest string you expect to enter plus one extra space for the string terminator. IOW, if the longest string you intend to read is 10 characters long, then your declarations need to be
char a[11] = {0};
char b[11] = {0};
char c[11] = {0};
Secondly, change your scanf call to
scanf( "%(SOME_LENGTH-1)s %(SOME_LENGTH-1)s %(SOME_LENGTH-1)s", a, b, c );
where (SOME_LENGTH-1) is the length of your buffer minus 1. Again, assuming SOME_LENGTH is 11:
scanf( "%10s %10s %10s", a, b, c );
This will help prevent a buffer overrun in the event you enter a string longer than what the buffer is sized to hold.
Both the %s conversion specifier and a blank space in the format string tell scanf to consume and discard any leading whitespace. You can run into trouble specifying whitespace characters in the format string.
Additional notes:
main returns int, not void - change your main to
int main (void)
{
...
}
If there are fewer elements in the initializer than there are in the array, then excess elements are initialized to 0. So in this case, the first element is *explicitly* initialized to 0, and the remaining elements are *implicitly* initialized to 0.

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.

What is the correct specifier for char, double and float?

#include <stdio.h>
int main()
{
int i;
long int l;
long long int ll;
char a;
float F;
double D;
scanf("%i%li%lli%c%f%lf",&i,&l,&ll,&a,&F,&D);
printf("%i\n%li\n%lli\n%c\n%f\n%lf\n",i,l,ll,a,F,D);
return 0;
}
When I tried to print the value of a,F and D in the above program, it is printing 'h' for 'char' and 0.000000 and 0.000000 for float and double every time .
input: 3
444
12345678912345
a
334.23
14049.30493
output:3
444
12345678912345
0.000000
-0.000000
printf
There's no way to pass a char or a float to printf. They'll be promoted to int and double respectively in the processing of being passed.
When you pass a double, you can use %f or %lf (the latter was added in C99 though, so some older compilers don't support it).
If you want your int printed as a character, you can use the %c conversion. If you want it printed as a number, you can use the %d or %i conversion.
scanf
For scanf you don't want to pass any of the above--you want to pass a pointer to a (char | float | double).
As for the conversion to use, for a pointer to char you can use either %c or %s.
%s reads a "word"--it skips white-space characters, then reads a group of non-white-space characters.
%c does more like "raw" reading--for example, if you specify %15c it reads the next 15 characters, regardless of whether they're white-space or not.
With both %c and %s, you always want to pass a with (like %15s instead of just %s) to assure that the user can't enter too much data and overflow the buffer you've provide. scanf("%s", whatever); is pretty much equivalent to using gets.
With scanf, you pass %f to read a float and %lf to read a double.
Use %c for char .
Note - You should check return of scanf .
Demo
When you read your input, the character you read is the white-space between 12345678912345 and a. That means that the next format, the floating point, will try to read the letter a as a floating pointer value which will not work, and the scanf function will return without being able to correctly read and parse all input, leading to your output not matching the input. Many standard and system function returns a value saying if it succeeded or failed, the same with the scanf function, and if it doesn't fail completely it will return the number of successfully scanned and parsed items, which would be less than expected in your case.
The scanf reference in one of my comments will tell you that most formats skip leading white-space, but "%c" does not. If you want to skip leading space before attempting to parse a character, you need to tell scanf to do that, by inserting an actual space in the format string, like this:
scanf("%i%li%lli %c%f%lf",&i,&l,&ll,&a,&F,&D);
// ^
// Notice space here

whitespace in the format string (scanf)

Consider the following code:
#include<stdio.h>
int main() {
int i=3, j=4;
scanf("%d c %d",&i,&j);
printf("%d %d",i,j);
return 0;
}
It works if I give 2c3 or 2 c 3 or 2c 3 as input if I have to change the value of variables. What should I do if I want the user to enter the same pattern as I want means if %dc%d then only 2c3 is acceptable and not 2 c 3 and vice versa if it is %d c %d?
Whitespace in the format string matches 0 or more whitespace characters in the input.
So "%d c %d" expects number, then any amount of whitespace characters, then character c, then any amount of whitespace characters and another number at the end.
"%dc%d" expects number, c, number.
Also note, that if you use * in the format string, it suppresses assignment:
%*c = read 1 character, but don't assign it to any variable
So you can use "%d%*c c%*c %d" if you want to force user to enter: number, at least 1 character followed by any amount of whitespace characters, c, at least 1 character followed by any amount of whitespace characters again and number.
If you want to accept 1c2 but not 1 c 2, use the pattern without the space:
scanf("%dc%d", &x, &y);
If you want to accept 1c2 and 1 c 2 (and also 1 \t \t c \t 2 etc), use the pattern with the space:
scanf("%d c %d", &x, &y);
If you want to accept 1 c 2 but not 1c2, add a fake string containing whitespace:
scanf("%d%*[ \t]c%*[ \t]%d", &x, &y);
Here the format string %[ \t] would mean "read a string that contains any number of space and tab characters"; but using the additional *, it becomes "expect a string that contains any number of space and tab characters; then discard it"
I think I would read the scanf result into different variables (i.e. not reuse i and j) as "%d%s%d". Then check the string you got from the %s and if it matches your requirements, use the other variables to overwrite i and j.
Force a string parsing first :
char a[100], b[100];
scanf("%99s c %99s", a, b);
Then use sscanf() to convert the strings to int.

Resources