problems with scanf and conversion specifiers - c

Here you can see my source code:
#include <stdio.h>
int main()
{
char yourname;
char yoursex;
int yourage = 0;
printf("Hey, what's your name?\n");
printf("My name is: ");
scanf("%s", &yourname);
printf("Oh, hello %s! \n\n", &yourname);
printf("Are you a boy or a girl?: ");
scanf("%s", &yoursex);
printf("Nice to know you are a %s! \n\n", &yoursex);
printf("How old are you %s? I am ", &yourname);
scanf("%d", &yourage);
printf("I see you are %d, you have many years then!", &yourage);
return 0;
}
I was trying things that I didn't knew, and strangely it is not working for me. What's the problem? Also, why it needs to be %s and not %c? If I use %c instead it does not work!
Where it says:
How old are you %s? instead of putting my name, it says ''oy''
and instead of showing my age in the last line, it shows a big number.

These are the very basics of C Programming, and I strongly advise you to get a decent book - The C Programming Language by Dennis Ritchie would be a good start.
There are numerous errors in your code.
A char can contain only one character, like 'A', or 'a' or something like that. When you're scanning a name, it is going to be a group of characters, like 'E', 'd', 'd', 'y'. To store multiple characters, you need to use a character array. Also, the format specifier used to scan/print characters is %c, %s is for when you need to scan a group of characters, also called a string into an array.
When you use printf, you do not supply a pointer to the variable you are trying to print (&x is a pointer to variable x). The pointer is a 32/64-bit integer, which is likely why you see a random integer when trying to print. printf("%c\n", charVar) is sufficient.
scanf does not need an & while using %s as the format specifier, assuming you have passed a character array as the argument. The reason is, scanf needs to know where to store the data you are reading from the input - and that is given by a pointer to the memory location. When you need to scan an integer, you need to pass an &x - which means, pointer to memory location of x. But when you pass a character array, it is already in the form of a memory address, and doesn't need to be preceded by an ampersand.
I once again recommend you look up some decent tutorials online, or get a book (the one I mentioned above is a classic). Type the examples as given in the material. Experiment. Have fun. :)

%s is for reading a string -- multiple characters delimited by whitespace. %c is for reading a single char.
You declare your yourname and yoursex vars as characters, and then try to read strings into them. The string read will overwrite random other things in the stack frame and misbehave or crash.
You want to declare yourname and yoursex as character arrays, so they can hold strings:
char yourname[32];
char yoursex[32];
then, when reading into them, you want to include a length limit so they don't overflow:
scanf("%31s", yourname);

This is a single character:
char yourname;
But %s indicates that the variable is a string (i.e., an array of characters terminated by a NUL). That's why you need %c. If you really did mean to use a string, then define the variable like
char yourname[32]; /* just pick a big enough size */
Also, you are correct to use the address of the variable with scanf(), but printf() needs the value. So instead of
printf("I see you are %d, you have many years then!", &yourage);
use
printf("I see you are %d, you have many years then!", yourage);
The "big number" is the memory address.

Make sure you read the comments in code!
#include <stdio.h>
int main()
{
char yourname[10];
char yoursex[5]; // boy or girl + null terminator
int yourage = 0;
printf("Hey, what's your name?\n");
printf("My name is: ");
scanf("%s", &(*yourname)); // & and * cancel each other out,
// thus take a look at the next scanf()
printf("Oh, hello %s! \n\n", yourname); // yourname is now an array
printf("Are you a boy or a girl?: ");
scanf("%s", yoursex);
printf("Nice to know you are a %s! \n\n", yoursex);
printf("How old are you %s? I am ", yourname);
scanf("%d", &yourage); // ok
printf("I see you are %d, you have many years then!", yourage); // here you don't
// need the address of the variable!
return 0;
}

The expression char yourname; only holds space for a single character, so quite likely you end up corrupting the memory space when scanning for yourname. You should allocate a bigger buffer and make sure that you don't overrun its length by setting a maximum number of characters to be read with the scanf function; as described in some of the other answers.
The fact that the following printf print correctly the name doesn't mean that the memory doesn't get corrupted; as C/C++ don't really check the boundary of any strings or arrays used at runtime.
As suggested by others, starting by reading a good book about C and/or C++ wouldn't a bad idea.

Related

Why is the output 6487620 (profit) by giving any input in this c program used to show profit or loss [duplicate]

#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 */

scanf and printf not printing right values

What is going on here?
The code goes like:
#include<stdio.h>
#include<string.h>
int main()
{
char name[15];
char name_[15];
char answ[1];
printf("What's your name?\n");
scanf("%s", name);
strcpy(name_, name);
printf("Yes / No: ");
scanf("%s", answ);
printf("Hello! %s\n", name_);
printf("You said: %s\n", answ);
return 0;
}
With input "name" and "yes" the expected output is that it says:
Hello! name
You said: yes
Instead I get:
Hello! es
You said: yes
I also tried adding spaces before %s with no results.
So what exactly am I missing here?
answ can contain only 1 character. So currently, the extra character "es" + '\0' gets written into the memory assigned to name_.
So, "es" gets printed.
You've only allocated space for a one-character yes/no answer, but are writing more characters into it.
This results in undefined behaviour.
You need to allocate more space for answ, not forgetting about the NUL terminator.
You have created a classic exploitable buffer overrun but in your code. This is why most modern compilers would advise you to swap sscanf to sscanf_s or similar. As other people have pointed out, you overwrite the next variable on the stack.
I wanted to provide this answer to basically say: never ever use sscanf or any of the obsolete, insecure C functions. Even if this is probably just a toy example, get the practice in to write modern C code. You’ll benefit from this in the long run.

C printf function data formats

Very simple C printing question!
#include <stdio.h>
#include <conio.h>
int main() {
int Age = 0;
printf("Enter your Age\n");
scanf("%d",&Age);
char Name;
printf("Enter your Full name\n");
scanf("%s",&Name);
printf("My name is %s and I am aged %d" ,&Name,Age);
return 0;
}
When I input "blah" and 1, for some reason this returns:
"My name is Blah and I am aged 1929323232"
I presume I am misunderstanding a data format in either the scanf or the printf functions but can't work it out.
The problem is because of line
char Name;
Name is of type char. That means that it is supposed to store only one character. As a result
1. The scanf() is not able to store the input text properly (this will result in a crash in most cases or other undefined behaviour depending on the system - which judging by the output you provided is what you got)
2. (if the code didn't crash) Treating Name as a string with the %s argument in printf() essentially outputs garbage.
The type that corresponds to strings in C is char * (or char[]). Essentially, changing Name to some statically allocated char-array while performing the necessary changes in the next lines should fix your error:
char Name[256]; //allocated 256 bytes in Name array
printf("Enter your Full name\n");
scanf("%s",Name); // removed & before Name
printf("My name is %s and I am aged %d" ,Name,Age); // same here
You could also opt to go with a dynamically allocated string of type char * but I guess that's a different topic altogether.
As a general suggestion, I think you should look at pointers more closely. Especially in C, almost all string operations involve being aware of pointer mechanisms.

How to take character input in an array in C?

char name[2];
scanf("%c",name);
printf("%c",name);
I am just starting to learn C. I'm curious about the above code, what I got from the printf output, is not the same with the character I typed in. Rather the output was some funny looking symbol. Can someone explain this to me?
For the %c specifier, scanf needs the address of the location into which the character is to be stored, but printf needs the value of the character, not its address. In C, an array decays into a pointer to the first element of the array when referenced. So, the scanf is being passed the address of the first element of the name array, which is where the character will be stored; however, the printf is also being passed the address, which is wrong. The printf should be like this:
printf("%c", name[0]);
Note that the scanf argument is technically ok, it is a little weird to be passing an array, when a pointer to a single character would suffice. It would be better to declare a single character and pass its address explicitly:
char c;
scanf("%c", &c);
printf("%c", c);
On the other hand, if you were trying to read a string instead of a single character, then you should be using %s instead of %c.
Either Read a single char
char name[2];
scanf("%c",name);
printf("%c",name[0]);
Or read a string
char name[2];
scanf("%1s",name);
printf("%s",name);
You need %s since because name contains 2 elements. %c is used for single character so if you want the user to input something for e.g. "as"(without "") and the program to print it out you need %s.
char name[2];
scanf(" %s", name);
printf("%s",name);
if you give your input which contains characters less than or equal to two you will get a correct output just as your input if your input contains characters greater than 3 then it doesn't work

Interactive, randomized program in C

My goal with this program is to incorporate the users inputs into a sort of interactive/randomized story but I'm not sure how I'm supposed to get the inputs from the users to fit between *ptrDescription, *ptrBeginning, *ptrMiddle, and *ptrEnd. Any help would be much, much appreciated!
#include <stdio.h>
#include<stdlib.h>
#include<time.h>
#include <string.h>
#include <ctype.h>
int main(void){
int i;
char name[20];
char color[20];
int age;
char sentence[1];
//array of pointers to char arrays
char *ptrDescription[]={"the painfully handsome","the one and only","who seemed much older than"};
char *ptrBeginning[]={"was blissfully ignoring","could clearly see","had no idea"};
char *ptrMiddle[]={"the huge truck","the falling meteor","the bucket of milk","the mailman","the most powerful wizard"};
char *ptrEnd[]={"that was barreling toward them.","on the horizon."};
srand(time(NULL));
printf("Enter your first name: ");
scanf("%s", &name);
printf("\nEnter your age: ");
scanf("%d", &age);
printf("\nEnter your favorite color: ");
scanf("%s", &color);
for (i = 0; i < 1; i++)
{
//strcpy(sentence,ptrDescription[rand()%3]);
//strcat(sentence," ");
//strcat(sentence,ptrBeginning[rand()%3]);
//strcat(sentence," ");
//strcat(sentence,ptrMiddle[rand()%5]);
//strcat(sentence," ");
//strcat(sentence,ptrEnd[rand()%2]);
//strcat(sentence,".");
//sentence[0]=toupper(sentence[0]);
puts(sentence);
}
getch();
return 0;
}
EDIT:
I've edited a section of my code so that directly following for (i = 0; i < 1; i++) it now looks like this:
snprintf(sentence, sizeof sentence,"%s, %s %d year old, %s %s %s %s", name, ptrDescription[rand()%3], age,ptrBeginning[rand()%3], ptrMiddle[rand()%5], ptrEnd[rand()%2]);
There are tons of strange characters after the sentence in the output, like Japanese characters and stuff. I'm not sure why they're there, though. This is what it looks like exactly:
"Enter your first name: Justin
Enter your age: 20
Justin, the arrogant 20 year old, was purposefully ignoring the most powerful wizard that was barreling toward them. 汽$0HβHζ(テフフフフフフフフフフフフフH・(DキHH広$0陏&・汽$0タHζ(テフフフフフフフフフフフフフフフH WH・ H櫛H・t9HνHテ<"
Anyone know how I can get rid of them?
If you already have a name and an age, it's just a matter of inserting them into the correct place in sentence, right? So strcat(sentence, name) would work for name. age is a little trickier since you have to format the number first, and strcat won't do it for you. One solution would be to use sprintf(buf, "%d", age), and then concatenate buf (which is a scratch char array you would have to declare).
Any time you work with strings in C, you have to be concerned about having enough space in the target buffer. Your program can run out of space during both input and output. For the output, I would get rid of sentence altogether; since you just end up writing to stdout I would printf("%s", [part]) each part as you go along. For reading, scanf supports adding a length argument to the format string.
If you use one of the *printf functions, there are 2 things you must be careful about:
The arguments you pass are correct for the format string you use
Your buffer ends up null-terminated
Your current problem is with #1 - your format string promises 7 arguments to follow, but you only supply 6. snprintf grabs a "random" 7th value from the stack, interprets it as a char pointer, and copies whatever it finds there to sentence. You could see similar problems if your format string promised a char pointer but you placed an int in a given position. In this case the format string is a constant, so a smart compiler can validate that your format string matches the subsequent parameters. You'll want to get into the habit of taking compiler warnings seriously and not ignoring them.
The second point could be an issue if your sentence ended up bigger than your sentence buffer. If there is no room for a null-terminator, one won't be applied. You can check the return value of snprintf, or you can defensively always write a 0 to the last array position.

Resources