Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 1 year ago.
Improve this question
So this is my code, and...
#include <stdio.h>
int main()
{
int order, stock;
char credit;
printf("\nEnter order value: ");
scanf("%d", &order);
printf("Enter credit (y/n): ");
scanf("%s", &credit);
printf("Enter stock availabilty: ");
scanf("%d", &stock);
if (order <= stock && credit == 121 || credit == 89)
{
printf("Thank you for ordering from us, the items will be shipped soon.\n\n");
}
else if (credit == 78 || credit == 110)
{
printf("Your credit is insufficient, hence as per company policy we cannot ship your ordered items.\n\n");
}
else if (order > stock && credit == 121 || credit == 89)
{
printf("We're falling short on supply, hence we'll ship the items we have in stock right now.\nThe remaining balance will be shipped as soon as stock arrives.\n\n");
}
else
{
printf("Invalid data.");
}
return 0;
}
... this was my input:
Enter order value: 12
Enter credit (y/n): Y
Enter stock availabilty: 10
The expected output was supposed to be:
We're falling short on supply, hence we'll ship the items we have in stock right now. The remaining balance will be shipped as soon as stock arrives.
However the program printed this:
Thank you for ordering from us, the items will be shipped soon.
Can someone explain me why this happened??
The line
scanf("%s", &credit);
is wrong.
The %s format specifier expects a pointer to the address where it should write the input as a string. When doing this, you must ensure that there is sufficient memory in that location to write the string.
However, at the specified memory location, there is only space for a single character, because with the line
char credit;
you only declared a single character.
For storing the string "Y", you need at least space for two characters, one for the character Y and one for the terminating null characer of the string. In C, strings always have a terminating null character at the end.
Of course, it would be possible to could solve this problem by adding space for a second character, and limiting the number of matched characters to 1, in order to ensure that there will be enough space for storing the string.
char credit[2];
[...]
scanf( "%1s", credit );
However, I do not recommend this solution. Instead, I recommend that you use the %c format specifier instead of the %s format specifier. The %s format specifier is intended for entire strings, whereas the %c format specifier is intended for individual characters.
Therefore, this solution would probably be better:
char credit;
[...]
scanf( "%c", &credit );
However, this solution has one problem. The previous function call to scanf
scanf( "%d", &order );
will not have consumed the entire previous line, but will only consume as many characters as possible to match the number. All characters that are not part of the number, including the newline character, will be left on the input stream.
Therefore, if you call
scanf( "%c", &credit );
afterwards, the %c format specifier will probably match the newline character, instead of the Y in the next line. See this question for further information on this problem:
scanf() leaves the newline character in the buffer
In order to solve this problem, you can instruct scanf to first discard all whitespace characters (newline characters are whitespace characters), before attempting to match the %c format specifier:
scanf( " %c", &credit );
Another way of solving the problem of leftover characters would be to use fgets instead of scanf. This solution has the advantage that the behavior of that function is more intuitive, as it normally reads exactly one line of input per function call. In contrast to scanf, it does not normally leave leftovers of a line on the input stream. See this guide for further information:
A beginners' guide away from scanf()
Related
I wrote the below C code to check if a number is present in an array whose elements are input by the user. But weirdly it's skipping the the third printf statement, directly taking the input and printing Enter the number you wish to look for after taking that input. What is causing this? Included input and output box below code.
CODE:
#include <stdio.h>
#include <stdlib.h>
void main() {
int arr[30], size, i, num, flag=0;
printf("Enter size of array. \n");
scanf("%d",&size);
printf("Enter %d array elements one by one. \n",size);
for (i=0; i<size; i++) {
scanf("%d \n",&arr[i]);
}
printf("Enter the number you wish to look for. \n");
scanf("%d",&num);
for(i=0;i<size;i++) {
if (num == arr[i]) {
flag++;
}
}
if (flag>0) {
printf("The number %d is present in the array.",num);
} else {
printf("The number %d is not present in the array.",num);
}
}
INPUT/OUTPUT:
Enter size of array.
5
Enter 5 array elements one by one.
1
2
3
4
5
5
Enter the number you wish to look for.
The number 5 is present in the array.
You can see that Enter the number you wish to look for. should come before 5, but it is not so.
Solved
Simply fixed by removing \n from scanf.
In scanf, a space character already represents any whitespace. So in your "%d \n" the function already processes the new line right after the last digit, but then you force it to wait for another newline.
This causes the program to wait for yet another line. After it's input, the program continues and asks for the number to search, and at that point the input was already entered.
Just use only one space in scanf, it will already work for the newline, ideally before the digit itself so that you don't need one extra line to complete the operation:
scanf(" %d", arr + i);
The space in the input format string "%d \n" tells the input system to
consume... all available consecutive whitespace characters from the input
(described here)
So when you enter your last number 5, the system now tries to consume all whitespace characters. To do that, it waits for additional input, until it's not a whitespace. So, paradoxically or not, to consume spaces, the system has to read a non-space, which is the second 5 you input.
To fix this behavior, you can tell your system to input only a number, without consuming whitespace:
scanf("%d",&arr[i]);
However, this will leave the whitespace in the buffer, which may interfere with later input. To discard the whitespace, you can use various techniques, described e.g. here.
In my opinion, the most correct technique (however, maybe the most cryptic one) is
scanf("%d%*[^\n]%*c",&arr[i]);
%d - read the number
%*[^\n] - read a string, terminated by a newline byte; discard it and don't store it anywhere
%*c - read a byte (which is a newline byte); discard it and don't store it anywhere
BTW in your format string "%d \n", there are two whitespaces: a regular space and an end-of-line. They both tell scanf to consume all whitespaces in input. The effect is exactly the same as with one space "%d " or with one end-of-line "%d\n", so this particular format string may be highly confusing to whoever reads your code (including yourself).
This program works as long as the "major" variable is only one word. For example, CIS is a valid input but Computer Information Systems is not. How do I fix this?
#include<stdio.h>
int main()
{
char major [51];
int classes;
printf("What is your major? ");
scanf("%50s", major);
printf("How many classes are you taking this semester? ");
scanf("%d", &classes);
printf("Your major is %s and you are taking %d classes this semester.\n", major, classes);
}
You can use %50[^\n] to match up to 50 characters until a newline is encountered, and store them in major[]. The newline will be left behind in the input stream, but the %d conversion specifier automatically skips over leading whitespace characters.
Note that if the user enters more than 50 characters, there will be extra characters in the input stream to discard before calling scanf() to get the number of classes.
Your problem is scanf stops at the first white space. What you need to do is keep reading until you read the end line character.
It's possible to do this with scanf but there are better options. fgets() comes to mind immediately. https://www.tutorialspoint.com/c_standard_library/c_function_fgets.htm
A few searches on Stack overflow will yield a ton of topics about the scanf() vs fgets() vs others.
Using fscanf() vs. fgets() and sscanf()
I want to ask a specific question and get a Y/N answer read in by the user. I will need to use the character Y or N to change the outcome of the next question eventually, which is why I need the character to be saved so I can retrieve it later. I don't want to use a string or a for/while loop. Also, why do I need to include the * after "%c*"?
#include <stdio.h>
#include <stdlib.h>
int main ()
{
int avgTemp, lowestTemp, temperature;
char choice ='Y';
char decision ='N';
printf("What is the average temperature?\n");
scanf("%d", &avgTemp);
printf("What is the lowest temperature in last 24 hours?\n");
scanf("%d", &lowestTemp);
printf("Has the temperature been over 99 degrees F for more than 30 minutes?
Please answer Y for yes and N for no.\n");
scanf("%c*", &choice);
printf("choice is %c", choice);
return 0;
}
Also, why do I need to include the * after "%c*"?
%c* means to scan for a character and then a * (which it will discard). Maybe you meant %*c which means do the scan but discard it. You don't need either of them.
scanf is a very problematic function and should be avoided. Your program illustrates the problem. scanf does not read a whole line. scanf will only scan stdin up to what you asked for and then stop. This means extra input and newlines can sometimes be left on the input stream for the next unsuspecting scanf. From the man page...
Each successive pointer argument must correspond properly with each
successive conversion specifier (but see the * conversion below). All
conversions are introduced by the % (percent sign) character. The format string may also contain other characters. White space (such as blanks, tabs, or newlines) in the format string match any
amount of white space, including none, in the input. Everything else matches only
itself. Scanning stops when an input character does not match such a format character. Scanning also stops when an input conversion cannot be made (see below).
This makes it very easy to accidentally leave characters on the input buffer. Each of your scanf("%d") will read in the number and stop. This leaves a newline on the input buffer. This is fine for %d because...
Before conversion begins, most conversions skip white space
...but not for %c.
Matches a sequence of width count characters (default 1); the next pointer must be a pointer to char, and there must be enough room for all the characters (no terminating NUL is added). The usual skip of leading white space is suppressed. To skip white space first, use an explicit space in the format.
So you need scanf(" %c") to make it work at all.
scanf is to be avoided because it's very, very vulnerable to unexpected input. Try giving "foo" to the first question. All the scanf("%d") will silently fail. And scanf("%c") will read f.
Instead, read the whole line with getline (preferred as it handles memory allocation for you) or fgets and then use sscanf on the resulting string. This avoids all the above problems.
Can anyone tell me why my code works fine until I get to the final scant, where I ask the user if they'd like to play again? For some reason, the program seems to ignore this line of code. Please be gentle as I'm new to programming and trying to teach myself Objective-C. This program is typical for noobs, where I generate a random number, ask the user to guess, then ask if they'd like to play again. Thank you.
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
#autoreleasepool {
int randomNumber = arc4random_uniform(100); // This is a random number generator that gens a num betw 0 and 100
int userNumber; // This is the number that the user picks intially
int attempts = 0; // This is the number of attempts the user makes during each game
int games = 0; // This is the number of games the user has played
char play = 'n'; // This is whether the user wants to play again, intially set to 'y'
scanf("%c", &play);
while (play == 'y') {
NSLog(#"Random number is: %d", randomNumber);
NSLog(#"Enter a number between 0 and 100");
scanf("%d", &userNumber);
games++; // Increment the number of games the user has played to 1
if (userNumber == randomNumber) {
attempts++;
NSLog(#"Congratulations. You guessed correctly!");
}
attempts++;
while (userNumber != randomNumber) {
if (userNumber < randomNumber) { // Guess is too low
attempts++; // attempt is incremented
NSLog(#"Too low. Try again!"); // User tries again
scanf("%d", &userNumber);
}
if (userNumber > randomNumber) { // Guess is too high
attempts++; // attempt is incremented
NSLog(#"Too high. Try again!"); // User tries again
scanf("%d", &userNumber);
}
}
NSLog(#"Congratulations. You guessed correctly!");
NSLog(#"It took you %d attempts to guess correctly", attempts);
NSLog(#"Do you want to play again?");
scanf("%c", &play); // --------- Here is where things to wrong ---------
} // while play is yes
} // autoreleasepool
return 0;
} // main
Converting comments into answer:
Probably, the final scanf() reads a newline and continues (the numbers don't read the newline). Maybe put a blank before the %c:
scanf(" %c", &play);
Check the return value from scanf(), and maybe even check which character was read.
Riposte:
That space before the %c did the trick. How does anyone ever learn things like that? I think it was reading the \n char rather than what I wanted it to read, which was either 'y' or 'n'. For my understanding, the %d integer doesn't read in the newline, but the %c does? Is that correct? And the way to prevent this is to use a space? I just don't get how I would ever know to do that.
And the response:
By reading the manual page for scanf() very carefully, many times over, or by bitter experience (or by answering lots of questions on SO about it). The scanf() family of functions are extremely powerful and extremely difficult to use accurately. I generally recommend using fgets() to read lines of input:
char line[4096];
if (fgets(line, sizeof(line), stdin) != 0)
{
...use line...
}
combined with sscanf() to parse the data on the line. It generally leads to fewer surprises of the sort you just ran into. You should always check that scanf() made as many conversions as you expected.
The role of white space in scanf()-family format strings is intricate. Most of the conversion specifiers skip leading white space (including newlines) automatically, so a format string "%d%d" will read to integer values where the first may be preceded by an arbitrary amount of white space, and the second may also be preceded by an arbitrary amount of white space. The conversion will stop at the first character that could not be part of the second integer (unless there was an error earlier). If you type 8 and newline as input, then the conversion stops on the newline (\n) and leaves if for the next input to read.
The numeric conversions and the string conversion %s all skip leading white space. The single-character format (%c) and the scan set %[a-z] do not skip leading white space.
When a white space character appears in the format, as in "%d %c", then it represents an arbitrary amount of white space in the data, including zero. Thus, in each of the following lines, the variable receiving the %c format will get Z each time:
123Z
123 Z
123 Z
123
Z
(The last two lines are read together for the last input.)
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;
}
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.
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!
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.
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.
getchar
scanf
And search "ansi c char arrays tutorial" or similar.