Can scanf() store values? - c

Hi I am now learning the C language and I have a little problem with a exercise of the book I read. My code is this:
#include<stdio.h>
int main()
{
unsigned char one=0;
unsigned char two=0;
printf("Quantity 1 = ");
scanf("%d",&one);
printf("Quantity 2 = ");
scanf("%d",&two);
printf("The value is %d",one);
return 0;
}
Why when I am trying to see the value of one the initial value appears and not the value after the scanf?

You need to use int type in conjuction with %d specifier, and char with %c specifier. And %u with unsigned integers.
#include<stdio.h>
int main()
{
unsigned int one=0; unsigned int two=0;
printf("Quantity 1 = ");scanf("%u",&one);
printf("Quantity 2 = ");scanf("%u",&two);
printf("The value is %u",one);
return 0;
}
Basicaly, scanf will try to read integer from input and it will try to store it inside memory location that is not large enough, so you will have undefined behavior.
You can find good reference here.
However, if you try to use character for an input type, you may want ask yourself why you won't get a chance to enter a second Quantity (if you type 4 and press enter). This is because second scanf will read enter key as a character. Also, if you try to type 21 (for a twentyone), it will fill the first value with 2 and second with 1 (well, with their ASCII values).
So, be careful - be sure that you always choose the right type for your variables.

Never use scanf.
Never use scanf.
Seriously, never use scanf.
Use fgets (or getline, if you have it) to read an entire line of input from the user, then convert strings to numbers with strtol or its relatives strtod and strtoul. strsep may also be useful.

Check if scanf() is working properly by reading its return value. For quickstart, read the details about scanf() at this link.
What you are doing is inputting a integer using "%d" into an unsigned char variable, therefore scanf() may not be working as it should.

Change
unsigned char one=0; unsigned char two=0;
to
unsigned int one=0; unsigned int two=0;
and also use %u instead of %d then it will print the value after scanf().

You declared the variable one to be a char:
unsigned char one=0;
But then you told scanf to read an int:
scanf("%d",&one); /* %d means int */
Int is bigger than char (typically 4-bytes vs. 1-byte), causing the problem you describe.
Change your scanf to:
scanf("%c",&one); /* %c means char */
Then when you print out the value, also print a char:
printf("The value is %c",one); /* %c means char */

Related

Why in C does taking input using int format to a char change the value of another char variable?

I took input in %d format into a character using scanf() because I didn't want more than 8 bits. But doing so changed the value of another char variable.
Code:
#include <stdio.h>
int main() {
char a;
char b;
printf("Enter a: ");
scanf("%c", &a);
printf("a = %c\n", a);
printf("Enter b: ");
scanf("%d", &b);
printf("\na = %d\n", a);
printf("b = %d\n", b);
}
Output:
Enter a: c
a = c
Enter b: 56
a = 0
b = 56
Screenshot
scanf reads data from stdin and stores them according to the parameter format into the locations pointed by the additional arguments.
scanf("%d", &b);
With %d you are storing an integer into the char variable that can not hold an integer.
the Variable now grows into the other variable in stack above it.
if you compile with the flag "-fstack-protector-all" you should get the
*** stack smashing detected *** error on execution.
The formatting directives in a scanf format string indicate not just how to match the input, but also the type of the corresponding variable in which the resulting value is to be stored. If you pass a pointer to an object of a different type than the corresponding directive expects then you reap undefined behavior.
That's true even for a simple signedness mismatch, but in your case you have a size mismatch. For a %d directive without a size modifier, scanf expects to write the scanned integer value in an object of type [signed] int. If the pointer you pass instead points to a char, and if, as is the case in most implementations, int is larger than char, then it is particularly likely that the resulting undefined behavior manifests in unwanted ways, such as by producing changes in the values of other variables.
If you want to scan a number as a char-sized integer, then you should
Declare the variable as either signed char or unsigned char, not default char, and
Use the correct conversion specifier and size modifier for the chosen data type.
For example,
unsigned char b;
scanf("%hhu", &b);
%u is the format directive for an unsigned integer, and the hh modifier instructs scanf that the destination variable is the size of a char / signed char / unsigned char.
If you want a signed integer then it would be similar, but with the %d formatting directive:
signed char b;
scanf("%hhd", &b);
As a matter of style, do not use default char for numeric data, even if you are confident that the range of values you need to support is a subset of the intersection of the ranges of signed char and unsigned char. Especially so if you plan to use it with formatted I/O functions, because it is implementation-specific whether %hhd or %hhu is the correct directive for a default char.
I agree with the side effect you indicated. This happens when the compiler loads variables in memory one after the other. For example, I examined the change in variable a when a sufficiently large number is typed in variable b. I changed the code as follows.
#include <stdio.h>
#include <stdlib.h>
int main( void )
{
char a, b;
printf( "Address (a): %p\tAddress(b): %p\n", &a, &b);
printf( "Enter the values (a, b): " );
scanf( "%c, %d", &a, &b);
printf( "Value (a): %d\tValue (b): %d\n", a, b);
return EXIT_SUCCESS;
}
Then, when I tested the code, I realized the consequences of this side effect.
The tested code is interpreted in the image below.

Convert scanf to a different argument size

Let's say I have the following to print a character entered by the user (using int to allow EOF in other places):
int ch;
scanf("%d", &ch);
printf("The character you entered was: %c\n", (char) ch);
Here, I am converting to a char in the printf function. How would I do that in the scanf function instead? For example, something like:
int ch;
scanf("%c", & (char) ch); // ???
printf("The character you entered was: %c\n", ch);
How would that be done?
You would scan a char and afterward convert it to int:
char c;
int ch;
if (scanf(" %c", &c) == 1) {
ch = (unsigned char) c;
} else {
ch = EOF;
}
The explicit conversion to unsigned char produces a result analogous to getchar()'s. There is a subsequent automatic conversion from that result to type int. In the case where scanf() fails to scan a character (other than leading whitespace), ch is set explicitly to EOF, much as getchar() would do.
Note also that the given format explicitly skips leading whitespace, as %d and most other format directives automatically do, but %c does not. This is for consistency with your %d variation -- it is not what getchar() does.
If you scan just one char into an otherwise uninitialized int, then you may not use the resulting int value without evoking undefined behavior on account of the three indeterminate bytes. Even if you initialized your int first -- to zero, say -- scanning one byte into it does not necessarily produce an int with the same value as that char, so no, no trick with scanning directly to the int is reliable. Theoretical UB aside, that could not be expected to work as you want on a big-endian machine or if the integer value of the scanned character were negative.
This cannot be done.
In
scanf("%c", xxx);
the xxx part simply must be an expression of type pointer-to-char.
So you must either do
char c;
scanf("%c", &c);
or, if you really want to get it into an int variable, you're going to have to do something like
int i;
char c;
scanf("%c", &c);
i = c;
If you were to try to do
scanf("%c", (char *)&i); /* WRONG */
you're doing something that's at best squirrelly and at worst (in other, related cases) downright undefined. It might seem to work, but it would be quite wrong.
For example, I just tried
int i = 0x01020304;
scanf("%c", (char *)&i); /* WRONG */
printf("i = %c\n", i);
printf("i = %d = %x\n", i, i);
and typed "X". The first printf printed i = X, so it seemed to work. But the second printf printed i = 16909176 = 1020378, which is certainly not the ASCII value of the character 'X'! On a big-endian machine, it probably would have worked even less well.
Why doesn't it work? Well, scanf and %c expect an argument of type pointer-to-char, because %c is going to fill in precisely one value of type char. If you say
scanf("%c", &i); /* WRONG */
it's wrong, and a conscientious compiler will typically warn you with something like "warning: format specifies type 'char *' but the argument has type 'int *'". If you try to shut the compiler up, by writing
scanf("%c", (char *)&i); /* WRONG */
the cast will indeed make the warning go away, and now we're left with the problem that we started with a pointer-to-int, and we're pretending it's a pointer-to-char. scanf will play along with the game, but: it will use the pointer to fill in only one byte of the int variable, leaving the rest completely alone.
Well, you could always do this:
int ch;
scanf("%c",(char*) &ch);
printf("you entered %c\n",ch);

Weird code interaction when scanning and printing chars in C

When you declare two variables char a,b; and then you use first 'a' and then 'b',it prints only b, but if you declare it 'b' then 'a', it has no problem printing both in ASCII,the point of the program is to read 121 and 120 and to print yx. the problem - https://prnt.sc/pr5nww
and if you swap them -https://prnt.sc/pr5mt5
#include <stdio.h>
#include <stdlib.h>
int main(){
char a,b;
scanf("%d",&a);
scanf("%d",&b);
printf("%c",a);
printf("%c",b);
}
This is kind of a confusing situation. When it comes to mixing char and int values (as you might do when investigating the numeric values of characters in a character set), it turns out the rules for scanf and printf are almost completely different.
First let's look at the scanf lines:
char a,b;
scanf("%d",&a);
scanf("%d",&b);
This is, in a word, wrong. The %d format in scanf is for scanning int values only. You cannot use %d to input a value of type char. If you want to input a character, the format for that is %c (although it'll input it as a character, not a number).
So you'd need to change this to
char a,b;
scanf("%c",&a);
scanf("%c",&b);
Now you can type characters like A and $ and 3 and have them read into your char variables a and b. (Actually, you're going to have additional problems if you hit the Return key between typing the characters for a and b, but that's a different story.)
When it comes to printing the characters out, you have a little more freedom. Your lines
printf("%c",a);
printf("%c",b);
are fine. And if you wanted to see the integer character-set values associated with the characters, you could have typed
printf("%d",a);
printf("%d",b);
and that would have worked, too. This is because when you call printf (and other functions ike it), there are some automatic conversions that take place: types char and short int are automatically promoted to (passed as) int, and type float is promoted to double. But these automatic conversions happen only for values of those types (as when calling printf). There a=is no such conversion when you're passing pointers to these types, as when calling scanf.
What if you wanted to read numbers, not characters? That is, what if you wanted to input the number 65 and see it get printed as capital A? There are several possible ways to do that.
The first way would be to continue to use %d in your scanf call, but change the type of your variables to int:
int a,b;
scanf("%d",&a);
scanf("%d",&b);
Now you can print a and b out using either %c or %d, and it'll work fine.
You could also use a temporary int variable, before reassigning to char, like this:
char a,b;
int tmp
scanf("%d",&tmp);
a = tmp;
scanf("%d",&tmp);
b = tmp;
The final, lesser-known and somewhat more obscure way, is to use the h modifier. If you say
char a,b;
scanf("%hhd",&a);
scanf("%hhd",&b);
now you're telling scanf, "I want to read decimal digits, but the target variable is a char, not an int."
And, again, you can print a and b out using either %c or %d, and it'll work fine.
the point of the program is to read 121 and 120 and to print yx
Do
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char a, b;
/* Scan into the half of the half of an int (the leading blank
makes scanf() eat whitespaces): */
scanf(" %hhd", &a);
scanf(" %hhd", &b);
/* Print the half of the half of an int: */
printf("%hhd", a);
printf("%hhd", b);
}
To print the characters literally do the printing part like this:
...
printf("%c", a);
printf("%c", b);
}

How do I fix a run-time error emitted by a safe function from Annex K?

I am starting out in C and I need to write a program that outputs the ASCII character for a given integer.
This is what I have:
#include <stdio.h>
int main(void)
{
char ch;
printf("Enter an ASCII code: ");
scanf_s("%d", &ch);
printf("The character for %d is %c\n", ch, ch);
}
I am getting a run-time error saying that the variable is corrupted, however, the window pops up allowing me to input an integer, and the program gives the correct output.
How do I fix this run-time error?
The %d format specifier expects an int * as a parameter, but you're passing in a char *. Because a char is smaller than an int, the function will attempt to write more bytes than the variable can hold. This invokes undefined behavior which in your case causes a crash.
Either change the type of ch to int, or use the %hhd format specifier which expects a char *.
ch is a variable of type char, but you're trying to read into it using %d, which is the format specifier for an int. That means your scanf writes over extra memory that it shouldn't. Change your declaration of ch to:
int ch;
And your program should work fine.

query regarding sprintf() and scanf()

Take for example
int i=10,j;
float b=3.14,c;
char str[30];
sprintf(str,"%d%f",i,b);
sscanf(str,"%d%f",&j,&c);
printf("%d ----- %f\n",j,c);
OUTPUT :- 103 ----- 0.1400000
As you can see, initially i=10 and b=3.14.
I want that j=10 and c=3.14 by using sprint() and sscanf().
The problem I am facing is that the compiler assigns j=103 and c=0.140000.
Is there any way to get rid of this problem in sscanf()?
Add one space to sprintf. Change:
sprintf(str,"%d%f",i,b)
to
sprintf(str,"%d %f",i,b)
Aside: It would be also safer to use snprintf here:
snprintf(str, sizeof str, "%d %f", i, b)
The best way will be to separate the numbers, using a different sign, but if you know that the first int is 2 chars long you can specify it:
sscanf(str,"%2d%f",&j,&c);
// ^^
You are missing a space
Change
sprintf(str,"%d%f",i,b);
to
sprintf(str,"%d %f",i,b);
#include <stdio.h>
int main()
{
int i=10,j;
float b=3.14,c;
char str[30];
sprintf(str,"%d %f",i,b);
sscanf(str,"%d%f",&j,&c);
printf("%d ----- %f\n",j,c);
return 0;
}
output
~ > ./a.out
10 ----- 3.140000
The %d conversion specifier in sscanf will match any number of contiguous numeric characters in the buffer pointed to by str till it encounters a non-numeric character which it can't match. This will cause the integral part of the float to be read as part of the int value. Therefore you must have a way to separate where you integer ends and float starts in the string str. You can put any non-numeric character as a sentinel to separate int value from the float value.
int i = 10, j;
float b = 3.14, c;
char str[30];
// a # to separate the two values, can be any non-numeric char so that it
// is not mistaken for a digit in the int or float value
sprintf(str,"%d#%f", i, b);
// match the separator character to read int and then float
sscanf(str, "%d#%f", &j, &c);

Resources