C scanf not working as intended (Help!) - c

Was working on a program that prompts a user to enter a phone number and than prints it out using . instead of - so and when I run it it doesn't even let me input anything it just runs and gives me random values. So here's a look at the full program.
int item_number, year, month, day, first, middle, last;
//float unit_price;
printf("Enter item number: ");
scanf("%d", &item_number);
printf("Enter unit price: ");
scanf("%f", &unit_price);
printf("Enter purchase date (mm/dd/yyyy): ");
scanf("%d /%d /%d", &month, &day, &year);
printf("Item\t\tUnit\t\tPurchase\n\t\tPrice\t\tDate");
printf("\n%d\t\t$%6.2f\t\t%.2d/%.2d/%.2d\n", item_number, unit_price, month, day, year);
//here is the code that gives me the problem explained above.
//also if i comment the code above it works.
printf("Enter phone number [(xxx) xxx-xxxx] : ");
scanf("(%d) %d - %d", &first, &middle, &last);
printf("You entered %d.%d.%d", first, middle, last);

The problem you have encountered, is probably one of the most common problems encountered by new C programmers -- the improper use of scanf. Specifically, when you attempt to read the telephone number, stdin contains, e.g.:
"\n(888) 555-1212"
(the '\n' the result of pressing Enter after (mm/dd/yyyy) is entered)
As a result, the input waiting in stdin does not match "(%d...", and a matching failure results. Why? There is a newline at the beginning of the characters in stdin. The "%d" format specifier (all numeric conversion specifiers) will skip leading whitespace.
However, the leading whitespace does not precede the integer, it precedes the "(" which is not skipped by your format string. With scanf, a " " (space) in the format string, will cause any number of whitespace characters to be skipped/discarded. So as BLUEPIXY correctly notes, you need to add the space before the "(" in the format string to have scanf ignore the '\n' waiting in stdin.
Beyond that, you make the same mistake and misuse of scanf that nearly all new C-programmers do -- failing to check the return. scanf returns the number of successful conversions that take place based on the conversion specifiers in the format string.
At minimum, you must check the return of scanf (and in fact on ALL USER INPUT functions) to provide minimal validation that you do in fact have valid input stored in your variables to proceed forward with in your code. If you fail to check the return, you can have no confidence that undefined behavior isn't being invoked from that point forward. So validate all user input.
A minimal rewrite of your code that puts those pieces together would be:
#include "stdio.h"
int main (void) {
int item_number, year, month, day, first, middle, last;
float unit_price;
printf("Enter item number: ");
if (scanf ("%d", &item_number) != 1) { /* validate item */
fprintf (stderr, "error: invalid input (item_number)\n");
return 1;
}
printf("Enter unit price: ");
if (scanf ("%f", &unit_price) != 1) { /* validate unit */
fprintf (stderr, "error: invalid input (unit_price)\n");
return 1;
}
printf("Enter purchase date (mm/dd/yyyy): ");
/* validate date */
if (scanf ("%d /%d /%d", &month, &day, &year) != 3) {
fprintf (stderr, "error: invalid input (mm/dd/yyyy)\n");
return 1;
}
printf ("\t\tUnit\t\tPurchase\nItem\t\tPrice\t\tDate");
printf ("\n%d\t\t$%6.2f\t\t%.2d/%.2d/%.2d\n",
item_number, unit_price, month, day, year);
printf ("Enter phone number [(xxx) xxx-xxxx] : ");
/* validate phone */
if (scanf (" (%d) %d - %d", &first, &middle, &last) != 3) {
fprintf (stderr, "error: invalid input [(xxx) xxx-xxxx]\n");
return 1;
}
printf ("You entered %d.%d.%d\n", first, middle, last);
return 0;
}
Example Use/Output
$ ./bin/scanf_phone
Enter item number: 3
Enter unit price: 19.95
Enter purchase date (mm/dd/yyyy): 03/01/2017
Unit Purchase
Item Price Date
3 $ 19.95 03/01/2017
Enter phone number [(xxx) xxx-xxxx] : (800) 555-1212
You entered 800.555.1212
(note I tweaked the format to put Item on the 2nd line...)
Look things over, and spend the time it takes to understand man 3 scanf. It is time well spent.

If you are using Xcode, then write your printf statements like so:
printf("Enter item number:\n");
Put a newline(\n) at the end.

Related

C : when asking for 2 inputs from a user the 2nd question will not prompt an input to be stored in a variable

If I try grade or fullname one at a time I will get the expected result
"Enter your Grade: "
"Your grade is x"
"Enter your full name:"
"Your full name is xxxx xxxx"
If I run below the print out is
Enter your Grade:2
Your grade is 2
Enter your full name: Your full name is
I can't figure out why I am not been prompted for a second input especially as I know it works when tried on its own */
int main()
{
char grade;
printf("Enter your Grade: ");
scanf("%c", &grade);
printf("Your grade is %c \n", grade);
char fullName[20];
printf("Enter your full name: ");
fgets(fullName, 20, stdin); /*2nd argument specify limits of inputs*, 3rd means standard input ie command console */
printf("Your full name is %s \n", fullName);
return 0;
}
scanf("%c"); buffer problem, %c will only eat one character, so or \n will stay in the buffer for the next one to read.
Try this
#include <stdio.h>
#include <stdlib.h>
int main()
{
char grade;
printf("Enter your Grade: ");
scanf("%c", &grade);
getchar(); // here
printf("Your grade is %c \n", grade);
char fullName[20];
printf("Enter your full name: ");
fgets(fullName, 20, stdin); /*2nd argument specify limits of inputs*, 3rd means standard input ie command console */
printf("Your full name is %s \n", fullName);
return 0;
}
use getchar(); to eat the extra character in the buffer.
Don't mix scanf() with fgets() - in this case, the newline present in the buffer, left untouched by scanf() will be fed to fget() and it won't "ask" for any new input.
Better to use fgets() in all the user-inputs.
The problem lies in this line scanf("%c", &grade); Whenever you use scanf() always keep in mind that the enter key will be stored in your buffer. Since enter key was in your buffer, it went right into fullName when fgets(fullName, 20, stdin); is executed. That's way you got your output:
Enter your Grade:2
Your grade is 2
Enter your full name: Your full name is
You can solve the problem by using getchar(); or getch(); right after scanf(); to capture the Enter key and ensures that fullName get the correct input. Another way to solve it is to use fflush(stdin);. They basically do the same thing, but fflush(stdin); clear Enter key from the buffer. Therefore, fflush(stdin); should be used after scanf(); to clear the unwanted Enter key left by scanf();
This is a long one and have a lot to take in, but I hope this information helps :)))

Trying to understand how different ways of input happen in C however the fgets() tends to skip

I am new to C and trying to learn how different inputs work. I wrote the this code to try getChar(), sscanf(), and fgets(). My first fgets() works perfectly fine but it skips the second one after I ask the user to enter a date. Am I using these functions in a way they are not supposed to be used. What are possible ways to solve this.
Also are there any other ways of receiving user input that would be more beneficial given certain scenerios.
#include <stdio.h>
#define MAX 12
#define MAX_DATE 100
int main(int argc, const char * argv[]) {
char buf[MAX];
char date[MAX_DATE];
char day[9], month[12];
int year;
printf("This code shows various ways to read user input and also how to check for input\n");
printf("Enter a String less than 11 characters for input: ");
fgets(buf, MAX, stdin); //stdin is used to indicate input is from keyboard
printf("Enter a char: ");
char inputChar = getchar(); //gets next avalible char
printf("\nThe char you entered is: "); putchar(inputChar); //puts char prints a char
printf("\nsscanf allows one to read a string and manupilate as needed.\n");
printf("\nEnter a date as follows: Day, Month, Year");
fgets(date, MAX_DATE, stdin);
sscanf(date, "%s, %s, %d", day, month, &year);
printf("\nFormatted values as follows... \n");
printf("day: %s\n", day);
printf("month: %s\n", month);
printf("year: %d\n", year);
return 0;
}
/*
Output for the code:
This code shows various ways to read user input and also how to check for input
Enter a String less than 11 characters for input: hey
Enter a char: a
The char you entered is: a
sscanf allows one to read a string and manupilate as needed.
Enter a date as follows: Day, Month, Year
Formatted values as follows...
day:
month:
year: -1205589279
Program ended with exit code: 0
*/
Your second fgets is not being skipped. It is getting the rest of your line.
In your example, when prompted by "Enter a char: ", you are entering "a" followed by a newline. getchar gets the "a" character. fgets starts at the character directly after that, meaning it is reading the newline after the "a" and returning.
If you call fgets(buf, MAX, stdin); after your getchar() to discard the rest of the line, your program will work as you expect.
#contrapants nicely explains the reason for the "skips the second one". When the user types a Enter, the 'a' is read by getchar() and the '\n' is then read by fgets(), without waiting for additional input.
For a learner, I recommend to only use fgets() for input.
printf("Enter a char: ");
fgets(buf, sizeof buf, stdin);
char inputChar = 0;
sscanf(buf, "%c", &inputChar);
Am I using these functions in a way they are not supposed to be used.
A side issue occurs when reading into a buffer without insuring no overflow. Use width limits.
char day[9], month[12];
//sscanf(date, "%s, %s, %d", day, month, &year);
int count = sscanf(date, "%8s , %11s , %d", day, month, &year);
if (count != 3) {
Handle_unexpected_input_somehow();
}

How to scan a "0" on the months that have one digit?

I am doing this C program where I need to input a date and see whether it is a valid date. However, I do not know how to scan a "0" in front of the days and months that have one digits. Also, the program requires to scan "/" as well. If the user inputs "07-14-1999" it has to be invalid because the user did not input "/". What should I do with these two problems? The following is the code I have so far. Thank you.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int day, month, year;
printf("Please enter a date to check validity (in the form of MM/DD/YYYY): ");
scanf("%i%i/%i%i/%i%i",&month, & month, &day, &day, &year, &year, &year &year);
printf("%i%i/%i%i/%i%i",month, month, day, day, year, year, year, year);
}
You want to scan three integer numbers, so you should use %d once for each number in scanf:
scanf("%d/%d/%d", &month, &day, &year);
To validate input it makes sense to check number of successfully scanned integers:
int res = scanf("%2d/%2d/%4d", &month, &day, &year);
if (res != 3) {
/* error */
}
Here %2d means that the max length of that input integer is 2 digits.
If everything is scanned correctly you can validate ranges for month, day and year.
To print leading zero:
printf("%02d/%02d/%04d", month, day, year);
Here %02d means that the integer is printed by minimum two symbols and zero is prepended if there is only one symbol.
It is trickier to make sure that the number of input symbols is correct. The above scan pattern also accepts date "1/1/1999". To simplify and to avoid scanning each symbol separately it is possible to read input as a string:
int day, month, year;
/* buffer length is enough for 10 date symbols + 1 null terminating
* character + 1 for too long input */
char buf[12];
char dummy_end_test;
printf("Please enter a date to check validity (in the form of MM/DD/YYYY): ");
/* scan as a string with maximum field width 11, check that the number
* of input characters is exactly 10 */
if (scanf("%11s", buf) != 1 || strlen(buf) != 10) {
printf("incorrect input length\n");
return 1;
}
/* parse integer numbers from string
* try to read symbol dummy_end_test to filter input as 11/1/19999 or 11/11/199x
* if it is possible to read one more character after four digits of year
* the number of scanned entries is 4 that is invalid input */
int ret = sscanf(buf, "%2d/%2d/%4d%c", &month, &day, &year, &dummy_end_test);
if (ret != 3) {
printf("error\n");
return 1;
}
Here I used sscanf that scans formatted input from string.
Anyway it is needed to validate ranges for day, month and year. All those numbers must be greater than 0. Maximum day depends on month and/or on leap year.

C - scanf gets skipped over (even with " %d")

I am trying to figure out why I can't get this to run properly. I just want four inputs from the user, and run the calculation at the end.
#include <stdio.h>
#include <math.h>
int main(){
double amount; /* amount on deposit */
double principal; /* what's the principal */
double rate; /* annual interest rate */
int year; /* year placeholder and no. of total years */
int yearNo;
printf("What is the principal? ");
scanf("%d", &principal);
printf("What is the rate (in decimal)? ");
scanf(" .2%d", &rate);
printf("What is the principal? ");
scanf(" %d", &principal);
printf("How many years? ");
scanf(" %d\n", yearNo);
printf("%4s%21s\n", "Year", "Amount on deposit");
/* calculate the amount on deposit for each of ten years */
for (year = 1; year <= yearNo; year++){
amount = principal * pow(1.0 + rate, year);
printf("%4d%21.2f\n", year, amount);
}
return 0;
}
It properly asks for the principal and rate, but then skips over the question about Principal and asks for years. Then it just sits there waiting for a "ghost" entry?
I've been reading that the scanf() adds some whitespace when hitting enter but thought the space before the %d would fix that?
I also saw you could add do { c=getchar(); } while ( c != '\n'); after each scanf but that seems to crash the program (I added int c = 0; to the beginning too).
Thanks for any help or ideas!
EDIT:
When I change the erroneous format specifier from:
scanf(" .2%d", &rate);
to:
scanf(" %d", &rate);
I then get a crash after entering my values.
.2%d is not a valid format string.
For a start, the % has to come first. In addition, if you're after a floating point value, d is not the right character - it's for integral values.
You should be using something like %f (you don't need width or precision modifiers).
On top of that, you've made a minor mistake of not using a pointer for one of your scanf calls:
scanf(" %d\n", yearNo);
That's probably going to cause a crash, and should be changed to:
scanf(" %d\n", &yearNo);
And, as a final suggestion, it's totally unnecessary to use whitespace before (or a newline after) %d or %f family of format specifiers. The scanner automatically skips whitespace before both of those.
So, the only two scanf format strings you need in this program are "%d" and "%lf" (f is for floats, lf is for doubles).

Ambigious nature of scanf taking input before it is asked to enter from user?

#include<stdio.h>
void main(){
int num1,num2;
printf("\n Enter number 1 \t "); // Ask for input one. >>>>>>>> line 1.
scanf("%d ",&num1);
printf("\n Entered number is %d \n",num1);
printf("\n Enter number 2 \t "); // Ask for input Two. >>>>>>>>> line 2.
scanf("%d ",&num2);
printf("\n Entered number is %d \n",num2);
return;
}
I wish to know REASON.Please do provide it.
The code above accepts two inputs,first input is asked(By executing line 1) then user enter one number then terminal should ask to enter second input but instead it is taking other number(before executing line2 ) and then asking to enter second input(i.e after executing line 2).
In the End is is displaying the two input that are taken before executing line two but after executing line 1.
I am confused.I am interested to know reason.
I am using GCC 4.8.2 on ubuntu 14.04 64 bit machine.
Remove spaces between the scanf of access specifier.
scanf("%d ",&num1);
to
scanf("%d",&num1);
Because the scanf get the another value due to that spaces.
And kept in the buffer. After the memory has got it get assigned.
It is for all scanf function.
if I input like
Enter Number1 1
2
Entered number is 1
Enter number2 3
Entered number is 2.
It is better to use int main() and in the end write return 0;
use fflush(stdout); to flush your buffer.
After editing here is the final code
#include<stdio.h>
int main(){
int num1,num2;
printf("\n Enter number 1 \t "); // Ask for input one. >>>>>>>> line 1.
scanf("%d ",&num1);
printf("\n Entered number is %d \n",num1);
printf("\n Enter number 2 \t "); // Ask for input Two. >>>>>>>>> line 2.
fflush(stdout);
scanf("%d ",&num2);
printf("\n Entered number is %d \n",num2);
return 0;
}
Here is the Demo.
You need to put
fflush(stdout);
before the scanf
This will flush your buffer
(also a good idea to check the return value of scanf)
You have given a space in scanf for %d. If you remove that space after %d the program will run
Let's take this apart slowly
#include <stdio.h>
// void main(){
int main(void) {
int num1, num2;
printf("\n Enter number 1 \t ");
scanf("%d ",&num1);
printf("\n Entered number is %d \n",num1);
...
Use a proper function signature for main() - but that is not the main issue.
Code prints "\n Enter number 1 \t "
"%d" directs scanf() to scan for text convertible to an int in 3 steps:
A: Scan for optional leading white-space like '\n', '\t', ' '. Throw them away.
B: Scan for text representing an integer like "+1234567890". If any digits found, save the converted result to the address &num1.
C: Scanning continues in step B until a char that does not belong to the int is found. That char is "un-read" and returned to stdin.
(This is where you get in trouble as suggested by #Chandru) " " directs scanf() to scan for any number (0 or more) white spaces including '\n', '\t', ' ' and others. Then they are thrown away - not saved.
B: Scanning continues!! until a non-white-space is found. That char is "un-read" and returned to stdin.
Lastly scanf() return the value of 1 as that is how many field specifiers were converted. Code sadly did not check this value.
Recall stdin is usually line buffered, which means input is not available to user IO until Enter is hit.
User enters 1 2 3 Enter and scanf() scans the "123" and saves 123 to &num1. Then it scans "\n" as that is a white-space in step 4. and it continues waiting for more white-space.
User enters 4 5 6 Enter and the first scanf() which is not yet done, scans '4', sees it is not a white space and puts '4' back in stdin. scanf() finally returns after 2 lines are entered. At this point "456\n" are waiting in stdio for subsequent scanf().
The second scanf() then perpetuates the issue.
Recommend use fgets() only for all user input, at least until your are very skilled in C.
printf("\n Enter number 1 \t ");
char buf[100];
fgets(buf, sizeof buf, stdin);
if (sscanf(buf, "%d", &num1) != 1) Handle_BadInput();
else printf("\n Entered number is %d \n",num1);

Resources