Reputation: 6606
I am writing a super simple command line based program in C. It's just a small test and the code is very simple. So what it is meant to do is to ask the user for their name, maths grade, english grade, computing grade. Then it figures out their average grade and also tells them the name they entered. Yes I know this is an extremely simple program, but I'm still doing something wrong.
The problem is, one part of my code will run first telling the user to enter their name and then once they do this and press enter the rest of my code will run all at once and then stop working. It's weird I just don't understand what is wrong.
#include <stdio.h>
int main(int argc, const char * argv[])
{
char chr;
char firstname;
int mathsmark, englishmark, computingmark, averagemark;
printf("What is your name?\n");
scanf("%c", &firstname);
printf("\n");
printf("What is your maths mark?\n");
scanf("%d", &mathsmark);
printf("\n");
printf("What is your english mark?\n");
scanf("%d", &englishmark);
printf("\n");
printf("What is your computing mark?\n");
scanf("%d", &computingmark);
printf("\n");
printf("Your name is: %c", firstname);
printf("\n");
averagemark = (mathsmark + englishmark + computingmark) / 3;
printf("%d", averagemark);
printf("\n");
chr = '\0';
while (chr != '\n') {
chr = getchar ();
}
return 0;
}
Upvotes: 1
Views: 1035
Reputation: 181
You have (at least) two choices.
char firstname[number_big_enough_to_hold_long_name];
/*or */
char *firstname = malloc(sizeof(char) * number_big_enough_to_hold_long_name);
/* ... code ... */
free(firstname);
Further it would be best to limit width of read. scanf()
does not know the size (available space) of firstname
.
scanf("%number_big_enough_to_hold_long_names", ...
/* i.e. */
char firstname[32];
if(scanf("%31s", firstname) == EOF) {
perror("bad");
return 1;
}
Further you should check if there is anything left before trying next read. I.e. If someone enters "My Name" then only "My" will end up in firstname
and "Name" will be left in input stream.
And getchar()
returns an int
not a char.
Upvotes: 1
Reputation: 49403
You might want to look at a few tutorials. Maybe one on Format specifiers and one on strings in C
scanf()
reads data from stdin
and stores them as specified by the format specifiers. In this case:
char firstname;
scanf("%c", &firstname);
Read 1 character from stdin
and store it to firstname
:
>> What is your first name?
Mike
Now firstname == 'M'
because scanf()
read 1 character as we requested.
What you wanted to do was read a string (a bunch of characters):
char firstname[5]; // an array of characters
scanf("%s", firstname); // store as a string
firstname[4] = '\0'; // Truncate the result with a NULL to insure no overflow
>> What is your first name?
Mike
Now firstname
is [M][i][k][e][\0] because scanf()
read 1 string, as we requested.
Note the same holds true for printf()
, a printf
with a %c
will give you one character where as a printf()
with a %s
will give you all the characters until the NULL terminator.
Upvotes: 1
Reputation: 123488
One major problem is that you've declared firstname
to be a single character long, and when you try to read the name from the console, you're using the %c
conversion specifier, which reads the next single character from the input stream and stores it to firstname
. The remainder of the name is left in the input stream to foul up the remaining scanf
calls.
For example, if you type "Jacob" as a first name, then the first scanf
call assigns J
to firstname
, leaving "acob\n"
in the input stream.
The next scanf
call attempts to convert "acob\n"
to an integer value and save it to mathsmark
, which fails ("acob\n"
is not a valid integer string). Same thing happens for the next two scanf
calls.
The last loop
while (chr != '\n')
{
chr = getchar();
}
finally consumes the rest of "acob\n"
, which contains the newline character (because you hit Enter after typing the name), causing the loop and program to exit.
How do you fix this?
First, you need to declare firstname
as an array of char
:
char firstname[SOME_SIZE] = {0};
where SOME_SIZE
is large enough to handle all your cases. The you need to change scanf
call to
scanf("%s", firstname);
This tells scanf
to read characters from the input stream up to the next whitespace character and store the results to the firstname
array. Note that you don't need to use the &
operator here; under most circumstances, an expression of array type will be converted ("decay") to an expression of pointer type, and the value of the expression will be the address of the first element in the array.
Note that scanf
is not very safe, and it's not very robust. If you enter more characters than your buffer is sized to hold, scanf
will happily store those extra characters to memory following the array, potentially clobbering something important. You can guard against this by using an explicit field width in the conversion specifier, like
scanf(*%29s", firstname);
but in general it's a pain.
scanf
is also not very good at detecting bad input. If you enter "12er" as one of your marks, scanf
will convert and assign the "12"
, leaving the "er"
in the stream to foul up the next read.
scanf
returns the number of successful assignments, so one way to guard against bad input is to check the return value, like so:
if (scanf("%d", &mathmarks) != 1)
{
printf("Bad input detected for math marks\n");
}
Unfortunately, scanf
won't remove bad characters from the stream; you'll have to do that yourself using getchar
or similar.
Upvotes: 5
Reputation: 19333
This is a common mistake amongst newer C/C++ developers. The scanf
function detects you hitting the ENTER/RETURN
key to signal the end of input, but it also catches the \n
character as well at the end of the input string, so you essentially get two RETURNS
being detected.
Please read up on an example of using fgets
and sscanf
here:
http://www.linuxforums.org/forum/programming-scripting/67560-problem-scanf.html
It will resolve this issue very quickly for you. In the meantime, I strongly urge you to check out this book:
http://www.amazon.com/Primer-Plus-5th-Stephen-Prata/dp/0672326965
It is the most commonly used C programming book in high school and colleges in North America, and has TONS of examples for you to work through, including this specific program you demonstrated above. The print version has more examples than the e-book, so I would just cough up the $30.00 for the printed version.
Good luck!
Upvotes: 1