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).
Related
How would I scanf an input of "2 & 3"?
Currently, I have it set up as
char expr[10]={};
printf("Enter the expression:");
scanf("%s", expr);
And at the moment it is just grabbing the 2.
With scanf, the entry must be limited to the size of the buffer -1. In your case 9. To include white-space characters we use %[^\n], that means all the characters except '\n', which therefore makes %9[^\n]
#include <stdio.h>
int main(void)
{
char expr[10];
printf("Enter the expression: ");
scanf("%9[^\n]", expr);
puts(expr);
return 0;
}
If you have other entries in a row, you should also purge the keyboard buffer to get out the characters entered in excess and the '\n' which has not been removed.
As manual page described: The input string stops at white space or at the maximum field width, whichever occurs first.
If you want to read a line from console, you can search "c get line" in google, you will get more results.
for example: founction getline()
I'm trying to read a string including spaces so scanf wouldn't work so I'm trying to use fgets. When I run it and it hits the if statement what prints on screen is:
Please enter the course name.
You entered the course:
Please enter the course ID.
=======================
if(coursetotal==0)/*start of 1 course*/
{
printf("Please enter the course name.\n");
fgets(course[0].name,sizeof(course[0].name),stdin);
printf("You entered the course name: %s\n",course[0].name);
printf("\nPlease enter the four digit course ID.\n");
int temp=0,temp1=0,count=0; /*Variables used to check if 4 digits*/
scanf("%d",&temp);
temp1=temp;
while(temp1!=0)
{
temp1/=10;
count++;
}
if(count==4)/*start of is 4 digits*/
{
course[0].id=temp;
coursetotal+=1;
printf("You entered the course ID: %d\n",course[0].id);
}/*end of is 4 digits*/
else
{
printf("The course ID you input was not 4 digits.\n");
return;
}
printf("You have successfully added the course: %s. The ID is : %d, and you now have a total of %d course.\n",course[0].name,course[0].id,coursetotal);
} /*end 1 course*/
First I have to address the pet peeve I see here:
I'm trying to read a string including spaces so scanf wouldn't work
That's not true at all. There's something called a negated scanset you can use it to read past the white space characters (such as space) that normally terminate scanf()s input for a string.
That said. You should really pick just one input mechanism scanf() or fgets() and use that exclusively. When you intermix, things get weird and missed. The fact that you've done it here tells me you've done it other places and you probably used scanf() prior to this leaving yourself an "unclean" stdin buffer. This will fix your issue.
Now just a quick example for you, given a int (num) and a char * (`string):
scanf("%d", &num);
fgets(string, sizeof(string), stdin);
printf("%d\n%s\n", num, string);
You'll seemingly skip the ability to enter anything for the fgets as it really just took int the newline character leftover from the scanf()'s number entry. You'll see on the output something like:
5
5
// <-- and a couple
// <-- of blank lines
Indicating that you picked up a newline character. Even more obvious if you were to look at the ASCII value of the string's first (and only) character:
printf("%d\n", string[0]); // this would yield 10 the ASCII value of \n
Through my search for a solution I found this question.
Which made me think and make some experiments:
Case 1
#include<stdio.h>
main()
{ char a;
//some code
scanf("%c",&a);
/*This code might not be evaluated(missed)
sometimes*/
//This is how it is solved
scanf(" %c",&a);
//the rest of code
}
case 2
#include<stdio.h>
main()
{ int a;
//some code
scanf(" %d ",&a);
//this one will take 2 numbers instead of one
//the rest of code
}
I don't know much about c language so it would be appreciated if someone explains these results to me.(I'm using turbo c++ if it matters.)
A couple of general notes:
If you want to ask questions about C it would be beneficial for you to read about how the functions work. There is a lot of documentation available online for scanf() for example.
It's always better when you can give full compile-able examples rather than //some code
So in your first case the example would be:
char a, b;
scanf("%c", &a);
scanf("%c", &b); // this one will be "missed"
The reason is that when you enter a character in to stdin you're getting two characters really, what was typed plus an invisible newline character ('\n'). So really the second scanf isn't "missed" it's just picking up a character that doesn't have an ASCII representation.
If you printed these with:
printf("%c %d\n%c%d\n", a, a, b, b);
you would see:
>> ./my_prog
>> a
>> a 97
10
Because you entered "a\n" and the two scanf's read first the "a" then the "\n" respectively.
Using a scanf with a space before it:
scanf(" %c", &b); // this one will work instead
Will tell the scanf that any white space characters (including the newline '\n') left on stdin should be ignored.
In your second case, it's not looking for 2 numbers, it's looking for a number and a white space character. scanf(" %d ", &a) says "ignore any white space, then look for a decimal number, then look for white space". However once the variable (a) is filled it stops reading, because this is how scanf works:
A directive composed of one or more white-space characters shall be executed by reading input until no more valid input can be read, or up to the first byte which is not a white-space character, which remains unread.
So it's not really looking for another number, you can type anything at this point and it will be happy because it's just looking for another white space character to be input. So this:
scanf(" %d ", &a);
could be satisfied by this input:
>> 5
f
First the "%d" matches the 5, then the newline following the f matches the " "
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'm writing this to get student information (full name, id and gpa for the last 3 trimester, so I used structures and a for loop to plug in the information however, after 1st excution of the for loop (which means at student 2) my 1st and 2nd input are shown on screen together. How could I prevent this from happening in a simple and easy way to understand? ( P.S: I already tried to put getchar(); at the end of the for loop and it worked, however; I'm not supposed to use it 'cause we haven't learnt in class)
The part of the c program where my error happens:
#include <stdio.h>
struct Student {
char name[30];
int id;
float gpa[3];
};
float averageGPA ( struct Student [] );
int main()
{
int i;
float average;
struct Student studentlist[10];
i=0;
for (i; i<10; i++)
{
printf("\nEnter the Student %d full name: ", i+1);
fgets(studentlist[i].name, 30, stdin);
printf("Enter the Student %d ID: ", i+1);
scanf("\n %d", &studentlist[i].id);
printf("Enter the Student %d GPA for the 1st trimester: ", i+1);
scanf("%f", &studentlist[i].gpa[0]);
printf("Enter the Student %d GPA for the 2nd trimester: ", i+1);
scanf("%f", &studentlist[i].gpa[1]);
printf("Enter the Student %d GPA for the 3rd trimester: ", i+1);
scanf("%f", &studentlist[i].gpa[2]);
}
average = averageGPA(studentlist);
printf("\n\nThe average GPA is %.2f", average);
return 0;
}
float averageGPA (struct Student studentlist[])
{
int i;
float total = 0.0, average = 0.0;
for (i=0; i<10; i++)
{
total = studentlist[i].gpa[0] + studentlist[i].gpa[1] + studentlist[i].gpa[2];
}
average = total / 30 ;
return average;
}
Computer output:
Enter the Student 1 full name: mm
Enter the Student 1 ID: 12
Enter the Student 1 GPA for the 1st trimester: 3
Enter the Student 1 GPA for the 2nd trimester: 4
Enter the Student 1 GPA for the 3rd trimester: 3
Enter the Student 2 full name: Enter the Student 2 ID: <<<<< Here is the problem!!
Try eating the newline after the last scanf:
scanf("%f ", &studentlist[i].gpa[2]);
^
This is very much like your getchar solution. It's actually superior to getchar, since it only discards whitespace.
But you have to use getchar() to discard the newline character that is still in the input buffer after your last scanf("%f"), which according to given format converts a float and leave in the buffer all other chars.
If you can't use getchar(), use another fgets() at the end of the loop.. but of course getchar() would be better
Edit for explanation: whenever you type on your keyboard characters go in a input buffer waiting to be processed by your application. getchar() just "consumes" one character from this buffer (returning it), waiting for a valid char if the buffer is empty. scanf("%f") only "consumes" characters resulting in a float. So, when you type "5.12<enter>", scanf reads and removes from buffer "5.12" leaving "<enter>". So the next fgets() already finds a newline in the buffer and returns immediately; that's why you should use getchar(): ignoring its returning value you successfully discard "<enter>" from the buffer. Finally, please note that if in the buffer there is only "<enter>", scanf("%f") discards it (since it cannot be converted in a float) and waits for another input blocking application.
One last note: input stream is buffered by your OS default policy, in the sense that application does not receive any character until you type "<enter>".
Use scanf in following way to read the student name:
scanf(" %[^\n]",studentlist[i].name);
The first space in the format specifier is important. It negates the newline from previous input. The format, by the way, instructs to read until a newline (\n) is encountered.
[Edit: Adding explanation on request]
The format specifier for accepting a string is %s. But it allows you to enter non-whitespace characters only. The alternative way is to specify the characters that are acceptable (or not acceptable, based on the scenario) within square brackets.
Within square brackets, you can specify individual characters, or ranges, or combination of these. To specify characters to be excluded, precede with a caret (^) symbol.
So, %[a-z] would mean any character between a and z (both included) will be accepted
In your case, we need every character other than the newline to be accepted. So we come up with the specifier %[^\n]
You will get more info on these specifiers from the web. Here's one link for convenience: http://beej.us/guide/bgc/output/html/multipage/scanf.html
The space in the beginning actually 'consumes' any preceding white space left over from previous input. You can refer the answer here for a detailed explanation: scanf: "%[^\n]" skips the 2nd input but " %[^\n]" does not. why?
I would just say no to scanf(). Use fgets() for all input fields and convert to numeric with atoi() and atof().