#include <stdio.h>
#include <stdlib.h>
int main() {
char a;
printf("What? \t");
scanf("%s", &a);
printf("U have to %s", a);
return 0;
}
Whenever I build and run this code and enter a value in %s, I get an error and the debug program stops working and closes. But when I use ampersand sign like this:
#include <stdio.h>
#include <stdlib.h>
int main() {
char a;
printf("What? \t");
scanf("%s", &a);
printf("U have to %s", &a);
return 0;
}
in the printf... it works. Why is that? It also differs between the format specifier, such as one doesn't need to put & (ampersand) sign in printf when one uses %c or %d in the scanf. Why does this happen and is it related to the data types and which format specifiers concludes this result?
(sorry for my bad English. I am not a native English speaker and this is my first time here).
What you have here is a classic example of code that seems to work, but for the wrong reasons.
Let's review a few things about printf and scanf. The format specifier %d is for values of type int. You can read an integer like this:
int i;
scanf("%d", &i);
And you can print it back out like this:
printf("%d\n", i);
Why does one use an & and one does not? Well, C uses what's called "pass by value". If we wrote
scanf("%d", i); /* WRONG */
we would be passing the value of i to scanf. But we don't want to pass the (old) value of i to scanf, we want scanf to read a new value, and store it into i. In other words, we want scanf to, in effect, pass the new value of i back to us. For that to work, we instead pass scanf a pointer to the variable i where we want it to store the just-read integer. That's what the & does -- it generates a pointer to i.
When we call printf, on the other hand, the regular way of passing arguments works just fine. We do want to pass i's value to printf so that it can print it out. If we were to call
printf("%d\n", &i); /* WRONG */
it wouldn't work, because printf expects an int, and here we're wrongly handing it a pointer-to-int.
So now we've learned that for integers with %d, printf wants an int and scanf wants a pointer-to-int.
Let's talk about characters. The format %c is for characters. We can read one character with scanf:
char c;
scanf("%c", &c);
And we can print it with printf:
printf("%c\n", c);
Again, the pattern is exactly the same. scanf needs a pointer, so that it can fill in the value, so we pass &c. But printf just needs the value, so we pass plain c.
Now we get to strings. A string in C is an array of characters. Also strings in C are always terminated by a special null character, '\0', that marks the end of the string. So if we wanted to declare a variable that could contain strings up to 9 characters long, we might write
char s[10];
That gives us room for 9 characters, plus the terminating '\0'.
But arrays are special in C: Whenever you pass an array to a function, or whenever you do anything that would require the "value" of the array, what you get instead (what the compiler automatically generates for you) is a pointer to the array's first element.
What this means is that to read a string with scanf and %s, we can just call:
scanf("%s", s);
"But where is the &?", you ask. "I thought you always needed an & when calling scanf!"
Well, not quite. You always need a pointer when calling scanf. And in fact, when you called scanf("%s", s), it was just as if you had written
scanf("%s", &s[0]);
When you use %s with scanf, it expects a pointer to the first of several characters, that is, a pointer to the beginning of an array of characters, where it should begin writing the string it reads. (How does it know how big the array is? What if the user types a string that's too long to fit in the array? We'll get to those points in a moment.)
You can print strings with %s too, of course, and it looks like this:
printf("%s\n", s);
This is, again, just as if you had written
printf("%s\n", &s[0]);
When you use %s with printf, it expects a pointer to the first of several characters which it should begin printing, until it finds the terminating '\0' character.
So %s is special with printf and scanf, because strings are special (because arrays are special). With %d and %c and just about every other format specifier, you usually need a & when you call scanf, and you usually don't want that & when you call printf. But with %s, you usually don't want the & for either printf or scanf.
(And if we think about it a bit more carefully, the exception is not so much that scanf and %s does not need the &. Remember, the rule is really, scanf always needs pointers. The only reason scanf and %s doesn't need an & is that when you pass an array, you get a pointer to the array's first element automatically. So the exception is really for printf and %s: printf and %s does expect a pointer, and the reason printf and %s is designed to expect a pointer is that there's no way to not give it one: it has to accept a pointer, because for strings, that's what you always end up giving it.)
So the rule with %s is that scanf expects a pointer to the first of several characters, and printf expects a pointer to the first of several characters, too.
So now, with all that background out of the way, we can look at your code. You basically wrote
char c;
scanf("%s", &c);
At first this might seem to be kinda, sorta, almost correct. scanf and %s wants a pointer to a character, and you gave it &c, which is a pointer to a character. But %s really wants a pointer to the first of several characters. But you gave it a pointer to just a single character. So when the user types a string, the first character typed will get stored in c, but the rest of the characters, and the terminating '\0', will get written to unallocated memory somewhere off to the right of variable c. They'll overwrite ("clobber") memory that was, perhaps, used for something else. This is a serious problem, but it might not become evident right away.
Finally, you tried to print things out again with printf. You first tried
printf("%s\n", c); /* WRONG */
but this didn't work at all. The reason is that %s with printf expects a pointer-to-char, but you gave it a plain char. Suppose c contains the letter 'A'. This would end up asking printf to go to address 65 and begin printing characters until it finds the terminating '\0'. Why address 65? Because 65 is the ASCII code for A. But there's probably not a proper, null-terminated string starting at address 65 in memory; in fact there's a good chance your program doesn't have permission to read from address 65 at all.
So then you tried
printf("%s\n", &c); /* ALSO WRONG */
and this seemed to work. It "worked" because, if scanf succeeded in storing a complete string into c and the unallocated memory off to the right of it, and if clobbering that memory somehow didn't cause (too many) other problems, then when you pass the pointer &c to printf, printf can find those characters, making up a string, and print them out.
So it "works", but as I said, for the wrong reasons: in the process it stomps all over memory it doesn't "own", and sooner or later, something else is going to not work as a result.
How should you have scanned and printed a string? One way is like this, as we saw before:
char s[10];
scanf("%s", s);
printf("%s\n", s);
Now when scanf gets a pointer to the first element of the array s, it has 10 characters to play with.
We really do have to worry about the possibility that the user will type more than 9 characters. But there's a fix for that: we can tell scanf how long a string it's allowed to read, how many characters it's allowed to write to the array we handed it:
scanf("%9s", s);
That 9 in there tells scanf that it's not allowed to read more than 9 characters from the user. And since 9 is less than 10, there's still room for the terminating '\0' character.
There's much more that could be said about scanf. As chqrlie noted in a comment, it's important to check its return value, to make sure it succeeded in converting as many values as you wanted it to. It's got some strange rules about whitespace. Unless you know what you're doing, you can't intermix calls to scanf with calls to other input-reading functions like getchar or fgets -- you'll get strange results. And, finally, scanf is so persnickety and (in the end) so lacking in truly useful functionality that it's not really worth using at all. But those are topics for another day, since this answer is tl;dr already.
The %s format specifier requires a pointer to a string. When used with scanf, it must be a char array with enough characters for the word you enter plus the trailing null byte that indicates the end of the string. In printf() it has to be a null-terminated char array.
Using a pointer to a char variable doesn't work, because it doesn't have room for the null byte. You're causing undefined behavior by writing outside the variable.
char word[100];
scanf("%s", word);
printf("%s\n", word);
You can use %c to read and write a single character rather than a string of multiple characters.
char letter;
scanf("%c", &letter);
printf("%c\n", letter);
In statement char a; a is a character variable & to scan a char variable use %c format specifier.
scanf("%s",a);/* %s expects base address of char buffer, not single char */
scanf(" %c",&a);/* this is correct */
If you want to scan using %s then your input should be char buffer like char buf[10]. for e.g
char a[10];
scanf("%s",a);
u don't need to put &(ampersand) sign in printf when u use %c or %d ? no need to provide address & to printf() as printf() job is to print not to scan. for e.g
char input;
scanf("%c",&input);/* here you need &, As scanf() will store input char into
address you provided i.e &input */
printf("%c",input);/*here no need &input, bcz input char already stored,
printf will just print the char*/
Well, if you print the address you can use %p.
printf("%p",a);/*a is char buffer */
Just like printf(), I was trying to use optional specifiers in scanf() format string. I tried to use the width and precision specifier. Now in printf() it simply reserves the columns and print according to these specifiers but what happens with scanf()? Like what is meaning of %3d and %3.3f here? Is this even relevant in case of scanf()? I have a little idea that width in this case represents the number of characters that are to be read for some particular format but not sure. Below code explains this further:
#include<stdio.h>
int main()
{
int a;
float b;
printf("Enter Numbers:\n");
scanf("%3d %3.3f",&a,&b);
printf("Entered Numbers are\n");
printf("%d %f",a,b);
return 0;
}
Since you specified in the comments that what you really want to know is 'what if i forcefully try to do it' ... Here are the results (with Clang)
warning: invalid conversion specifier '.'
and
warning: data argument not used by format string
The program compiles , however, since these are just warnings.
Upon executing the binary, and entering the variables asked for:
The "%d" for a gets stored properly.
Regardless of what value is entered, the " %3.3f " for b always stores 0.000000
In short, the it does what almost any other code that compiles with warnings does - not behave as intended. This is neither undefined, nor unspecified behaviour, but it is wrong.
Suggestion : Refrain from asking questions that are of the nature ' what happens if I try to compile this '. Just try and see for yourself !
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.
This code here gives incorrect value of int num if my input for num is for example 11,the printf function will output 0. However if I add static to int num the output produced by printf is correct. Can someone please explain the reason.Also if I make the format specifier for second scanf as %c , then also int value is printed correctly.
#include<stdio.h>
int main()
{
int num;//making it static gives correct result
char ch;int c;
printf("enter the value of num and ch:\n");
scanf("%d",&num);
scanf("%d",&ch);
printf("num = %d and ch = %c",num,ch);
return 0;
}
It's not specifically with printf(), the issue is caused by the erroenous call to scanf().
Quoting C11, chapter §7.21.6.2
[...] Unless assignment suppression was indicated by a *, the
result of the conversion is placed in the object pointed to by the first argument following
the format argument that has not already received a conversion result. If this object
does not have an appropriate type, or if the result of the conversion cannot be represented
in the object, the behavior is undefined.
For %d conversion specifier, the expected type of argument is
d [....] The corresponding argument shall be a pointer to
signed integer.
But, all you're supplying is a pointer to a char. Mismatch. Undefined behavior.
OTOH, for %c conversion specifier,
c Matches a sequence of characters of exactly the number specified by the field
width (1 if no field width is present in the directive).
If no l length modifier is present, the corresponding argument shall be a
pointer to the initial element of a character array large enough to accept the
sequence. No null character is added.
so using
scanf("%c",&ch);
is correct. Alternatively, you can also use
scanf("%hhd",&ch); //char is signed
scanf("%hhu",&ch); //char is unsigned
This
char ch;
scanf("%d", &ch);
will invoke Undefined Behavior, since you are using the format for an integer, to store it in a character.
What you observe is very likely because second scanf with the wrong (tool large for char) format specifier overwrites the automatic variables memory where num is located.
Making num static moves it to the global variables memory and it (kind of) works, but it's still undefined behaviour, some memory have been overwritten somewhere and you may pay the price later on. So the only option is to specify the correct format specifier, here %c as you noted.
Try to add \n, like scanf("%d\n", &num);. Maybe it could help.
And compiler cannot pass if you use that expression, like scanf("%d", &ch);
Ok, I'm a noob with C, but I think the code is basic and straightforward. This program is for a college assignment, and is supposed to have the 'isdigit()' function in it. Here is the code
//by Nyxm
#include <stdio.h>
#include <ctype.h>
main()
{
char userChar;
int userNum, randNum;
srand(clock());
printf("\nThis program will generate a random number between 0 and 9 for a user to guess.\n");
/*I changed it from '1 to 10' to '0 to 9' to be able to use the isdigit() function which
will only let me use a 1 digit character for an argument*/
printf("Please enter a digit from 0 to 9 as your guess: ");
scanf("%c", userChar);
if (isdigit(userChar))
{
userNum = userChar - '0';
randNum = (rand() % 10);
if (userNum == randNum)
{
printf("Good guess! It was the random number.\n");
}
else
{
printf("Sorry, the random number was %d.\n", randNum);
}
}
else
{
printf("Sorry, you did not enter a digit between 0 and 9. Please try to run the program again.\$
}
}
When I try to compile, I get the following error
week3work1.c: In function ‘main’:
week3work1.c:14:2: warning: format ‘%c’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat]
What on earth is going on? I am desperate for help. Any help at all. I am seriously about to just give up on this program. Why is it saying it expects argument of 'char *' when my textbook shows that "%c" is for regular ole 'char'? I am using nano, gcc, and Ubuntu if that makes any difference.
For scanf(), you need to pass a pointer to a char, otherwise it doesn't have any way to store the character, since said char would be passed in by value. So you need &userChar instead.
Let's say userChar is 0 before the call. With your current code, you're basically doing this (as far as utility goes):
scanf("%c", 0);
What you want is this:
scanf("%c", some-location-to-put-a-char);
Which is &userChar.
The man page for scanf mentions this:
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.
replace scanf("%c", userChar); with scanf("%c", &userChar);.
You need to pass in a pointer instead of the value of the char.
scanf("%c",&userChar);