Invalid conversion identifier '.' - c

So I'm writing code to interpret a users input about whether they're payed an hourly wage or set salary. I've started a switch statement and the first statement within it is a printf() & a scanf() statement that reads
printf("Enter hourly wage: ");
scanf("\n $%5.2d", &hRate);
the compiler keeps giving me an error message for the scanf() statement that says: "invalid conversion specifier . ".
I've gone through and checked the program, and I've tried changing the statement, taking out the $ and what not, and nothing seems to work.
Any thoughts?

scanf does not allow an optional . in a conversion specification.
. can be used with some printf conversion specifiers.
scanf("%5d", &hRate); // allowed
scanf("%5.2d", &hRate); // not allowed
printf("%5.2d", hRate); // allowed

'.' is not a valid part of a format specifier for "%d".
Anyway, the value you need to read is certainly of the form " $ xxx.xx"
Read the hourly wage as a floating point value.
printf("Enter hourly wage: ");
double dhRate;
if (scanf(" $%lf", &dhRate) != 1) Handle_BadInput();
// covert to cents if needed
int hRate = round(dhRate * 100.0);
Another approach would read as dollars and cents
printf("Enter hourly wage: ");
int hRate_d, hRate_c;
if (scanf(" $%d.%d", &hRate_d, &hRate_c) != 2) Handle_BadInput();
// covert to cents if needed
int hRate = hRate_d * 100 + hRate_c;
A better solution would read the entire line using fgets() and then parse it using sscanf(), strtol(), etc.

Related

Why is scanf failing to read inputs correctly?

I cant figure out whats wrong. Am i using format specifiers in wrong way? Someone please help i am very new to coding.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char name[20];int age;char grade;double gpa;char area[10];
printf("User Input\n");
printf("Enter your name: ");
fgets(name,20,stdin);
printf("Your name is %s\n",name);
printf("Enter your age: ");
scanf("%d\n",&age);
printf("Your age is %d\n",age);
printf("Enter you grade: ");
scanf("%c\n",&grade);
printf("Your grade is %c\n",grade);//Why is this giving an int output?
printf("Enter your gpa: ");
scanf("%f\n",&gpa);
printf("Your gpa is %f\n",gpa);
printf("Enter your area: ");
scanf("%s\n",&area);
printf("Your area is %s",area);//This shows grade input
return 0;
}
Output
You use fgets correctly when reading name. I'd recommend also using fgets for all your other inputs, and then parsing the intended values out of them. For example:
char age_str[20];
fgets(age_str, 20, stdin);
age = strtol(age_str, NULL, 10);
This is preferable to using scanf directly for non-string inputs since if input fails to match a format string, it will remain in stdin and screw up the other scanf calls.
If you would like to use scanf correctly:
Check its return value to see if it matches the number of format specifiers in the string. If not, some inputs were not successfully read. You may want to use a do/while loop for this.
Begin your format strings with a space, as in " %c", so that any whitespace remaining in stdin will be skipped over.
Don't end your format strings with a newline.
Some things to remember about scanf:
Most conversion specifiers like %s, %d, and %f will skip over leading whitespace - %c and %[ will not. If you want to read the next single non-whitespace character, use " %c" - the leading blank tells scanf skip over any leading whitespace before reading the next non-whitespace character;
For what you are trying to do, you should not use \n in your format strings - it will cause scanf to block until you enter a non-whitespace character;
You do not need to use the & operator on array expressions like area; under most circumstances, array expressions are converted to pointer expressions1. Honestly, you should read area the same way you read name, using fgets (and you should always check the result of fgets), or you should specify the maximum field width in the specifier: scanf( "%9s", area ); (a 10-element array can hold up to a 9-character string, since one element has to be reserved for the string terminator);
You should get in the habit of checking the result of scanf - it will return the number of successful conversions and assignments. For example, scanf( "%d %d", &x, &y ) will return 2 if both x and y are read successfully. It will return EOF if end-of-file is signaled or there's a read error.
scanf will read up to the next character that doesn't match the conversion specifier - IOW, if you're using %d, then scanf will skip over any leading whitespace, then read up to the next character that isn't a decimal digit. That character is left in the input stream. This means if you're using %d and type in 123e456, scanf will read up to that 'e' character and assign 123 to the target. If you try to read again with %d, scanf will immediately stop reading on that e and return 0 without assigning anything to the target (this is called a matching failure). This will continue until you remove that 'e' from the input stream (such as with getchar or fgetc or scanf with the %c specifier, etc.
You need to make sure the types of the arguments match the format specifier. %s expects an argument of type char *, %d expects int *, %f expects float *. %x expects unsigned int *, %lf expects double *, etc.
This is one of the "deeply unintuitive" aspects of C I was talking about in my comment.

Scanf/Printf in C...what's going on here?

I am self-learning C and I am currently studying the Scanf and Printf functions.
I adapted this program to test myself:
char topping[24];
int slices;
int day, year;
float cost;
char month[10];
printf(" How much does a pizza cost in your area?\n");
printf("$");
scanf(" %f", &cost);
printf("What is your favorite one-word pizza topping?\n");
scanf(" %s",topping);
printf("How many slices of %s pizza, topping can you eat in one sitting\n",topping);
scanf(" %d", &slices);
printf(" What is today's date (enter in the following format 1-Jan-2016 )\n");
scanf(" %d-%s-%d", &day, month, &year);
printf("\nWhy not treat yourself to dinner on %d-%s-%d and have %d slices of %s pizza ? It will only cost you %.2f", day, month, year,slices, topping,cost);
The purpose of the exercise is for me to grasp an understanding of scanf functions and how "delicate" they can be.
My test program here runs well...except for the output in the year variable.
Why is the output in the year variable spitting out gibberish and how can I fix it?
Thank you.
Here's the problem. The %s specifier means to read any characters up until the next whitespace. So , after %d- has matched 1-, then the %s matches Jan-2016. Then the next %d fails as there is nothing left to match.
First of all you should always be checking the return value of scanf so you know whether there was a matching failure. For example in this case:
if ( 3 != scanf(" %d-%s-%d", &day, month, &year) )
{
printf("Matching failure occurred.\n");
// do something else...
}
else
{
printf("Why not treat yourself...
Secondly, to actually avoid the problem. The scanf function is pretty limited as you can see. To use other delimiters instead of whitespace, you can use the scanset specifier %[.....] instead:
scanf(" %d-%9[^-]-%d", &day, month, &year)
(with the same error checking). The scanset specifier means to read any characters (possibly including whitespace) that matches the characters inside the [], except that a ^ indicates to NOT match the next character. So this will read everything up until the next -. Also I added the 9 to avoid overflowing your buffer of size 9+1.
Of course this means if the person never types another - then the program goes a bit weird. You can fix this by making the format string more and more complicated; or you can instead read an entire line with fgets and then use the sscanf function with the aforementioned string. This will catch the case of the person pressing Enter before typing another -.
In fact it turns out it's usually a good idea to read a whole line at a time and then go back and process that line.
At some stage you will get tired of how awful scanf is, and make your own parser.

Simple C program not calculating correctly

So, I'm completely new to programming, and I'm learning to program C. I'm trying to write a simple program in C to calculate commission as follows
#include<stdio.h>
int main()
{
float fRate, fSales_Price, fCost, fCommission;
printf("\nEnter your commission rate: ");
scanf("%.2f",&fRate);
printf("\nEnter the price of the item sold: ");
scanf("%.2f", &fSales_Price);
printf("\nEnter the original cost of the item: ");
scanf("%.2f", &fCost);
fCommission = (fRate / 100) * (fSales_Price - fCost);
printf("\nYour commission is: %.2f", fCommission);
}
Whenever I try to run it, two things happen. First, if I try to enter any decimals into the program, e.g. if I said the rate was 12.5, it immediately skips the other inputs and completes the program, saying commission is 0.00. If I ignore decimals, the program runs fine until the end, when I still get commission as 0.00. Any suggestions?
Your format specifier is wrong, you must use compiler warnings if you do, then you wouldn't be asking this, because that format specifier is invalid, you cannot limit the number of decimal places with scanf() it's been discussed in many questions on SO, more importantly you don't need to, and it wouldn't be meaningful, so just remove the .2 from your format specifier, and instead, check that scanf() succeeded before using the values.
"%.2f" is an illegal format string for scanf, so your code causes undefined behaviour. The correct format string is "%f".
Also you should check the result of scanf. If scanf fails, the bad data is not consumed from the input and so subsequent scanfs fail too (this is why you see the other inputs skipped).
For example:
if ( 1 != scanf("%f", &fRate) )
{
printf("Invalid input for fRate.\n");
exit(EXIT_FAILURE);
}
"%.2f" is not a valid format for scanf. See scanf() manual page for details.
The easiest format to use is "%f".
Also, it's a good practice to check the return value of scanf so you know when the operation was successful.
if ( scanf("%f", &fRate) != 1 )
{
// Error reading the data.
// Deal with the error.
}

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).

having trouble with a "\n" and scanf

Here is the code
printf("\n");
printf("Enter a integer vaule:");
scanf("%d" , &num3);
printf("You entered: %015d", num3);
printf("Enter a float value:");
scanf("%f", &deci3);
printf("You entered: %15.2f", deci3);
printf("\n");
the output is
Enter a integer vaule:4.4
You entered: 000000000000004
Enter a float value:You entered: 0.40
The problem is this code is not stopping at
printf("Enter a float value:");
and this scanf
scanf("%f", &deci3);
seems to be getting its value from the previous scanf
The %d conversion stops wherever the integer stops, which is a decimal point. If you want to discard the input there, do so explicitly… getc in a loop, fgets, or such. This also allows you to validate the input. The program should probably complain about 4.4.
The scanf function works this way per the specification:
An input item shall be defined as the longest sequence of input bytes (up to any specified maximum field width, which may be measured in characters or bytes dependent on the conversion specifier) which is an initial subsequence of a matching sequence. [Emphasis added.]
In your example, the following C string represents the contents of stdin when the first scanf call requests input: "4.4\n".
For this initial call, your format string consists of a single specifier, %d, which represents an integer. That means that the function will read as many bytes as possible from stdin which satisfy the definition of an integer. In your example, that's just 4, leaving stdin to contain ".4\n" (if this is confusing for you, you might want to check out what an integer is).
The second call to scanf does not request any additional input from the user because stdin already contains ".4\n" as shown above. Using the format string %f attempts to read a floating-point number from the current value of stdin. The number it reads is .4 (per the specification, scanf disregards whitespace like \n in most cases).
To fully answer your question, the problem is not that you're misusing scanf, but rather that there's a mismatch between what you're inputting and how you're expecting scanf to behave.
If you want to guarantee that people can't mess up the input like that, I would recommend using strtol and strtod in conjunction with fgets instead.
This works, but it dont complains if you type 4.4 for the int
#include <stdio.h>
int main() {
char buffer[256];
int i;
float f;
printf("enter an integer : ");
fgets(buffer,256,stdin);
sscanf(buffer, "%d", &i);
printf("you entered : %d\n", i);
printf("enter a float : ");
fgets(buffer,256,stdin);
sscanf(buffer, "%f", &f);
printf("you entered : %f\n", f) ;
return 0;
}
use a fflush(stdin) function after the fist scanf(), this will flush the input buffer.

Resources