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).
Related
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.
For years, I don't do anything in C and now I can't do simple things, I was accustomed to cin and cout and now Java. I was trying to make a simple program to calculate the average X amount of exams notes. The output are "random numbers" and checking to interrupt the program occurs before entering a note. Why is that?
#include <stdio.h>
int main(void) {
int numeroDeNotas;
float nota = 0.0;
float notaAuxiliar = 0.0;
char continuar;
int media;
do{
printf("Enter the exam grade\n");
scanf("%f", ¬aAuxiliar);
nota += (int) notaAuxiliar;
numeroDeNotas++;
printf("Do you want to continue? Enter n if you want to stop\n");
scanf("%c", &continuar);
}while(continuar != 'n');
printf("%d\n\n", nota);
printf("%d\n\n", numeroDeNotas);
media = nota/numeroDeNotas;
printf("Average grade: %d", media);
return 0;
}
nota is a float, but you are using %d format code to print it. %d expects an int; you need %f to print floating point numbers.
C's standard I/O formatting is definitely not typesafe. When you provide a format code, you have to make sure the corresponding argument has the right type. However, if you had compiled with the -Wall option (at least, with gcc or clang), the compiler would have warned you.
Also, scanf("%c", &continuar); reads a single character without skipping whitespace, which will be the character immediately following the number read by scanf("%f", ¬aAuxiliar);. That character is most likely a newline. You need to skip whitespace before reading the y or n, so you could use:
scanf(" %c", &continuar);
numeroDeNotas was declared with a variable type - float. So you can't use %d later in your code when writing a printf statement.
numeroDeNotas
variable is declared but no where initialized. and you are incrementing in do while loop.
media = nota/numeroDeNotas;
printf("Average grade: %d", media);
and you are using garbage value to calculate media which is undefined output. initialize numeroDeNotas to zero.
I am writing a program to work out who should pay what in the household, based upon their income. The desired behaviour is the following:
Print welcome message and ask how many people are in the household.
If the number entered is 10 or below, ask for their names.
Ask for each persons income. <- this is where the issue is
Display total income.
Calculate and display result.
Obviously this program is not complete and I need to stop the user entering negative values, but the biggest problem is that when the user enters each persons income, upon hitting the return key it does not ask for any more user input and the totalEarnings comes out as 0.
I am used to programming in C++ so I'm hoping I've just missed a quirk of C.
main.c
#include <stdio.h>
int main(void){
short numberOfPeople = 0;
char* names[10] = {0,0,0,0,0,0,0,0,0,0};
float earnings[10] = {0,0,0,0,0,0,0,0,0,0};
float totalEarnings = 0;
float bills = 0;
printf("Welcome!\nThis program calculates who should pay what for the bills in a proportional manner, based upon each persons income.\nHow many people are in your household?\n\n");
do {
printf("You can enter up to 10: ");
scanf("%d", &numberOfPeople);
} while(numberOfPeople > 10);
puts("");
for(short j = 0; j < numberOfPeople; ++j){
printf("What is person %d's name? ", j+1 );
scanf(" %s", &names[j]);
}
puts("");
for(short i = 0; i < numberOfPeople; ++i){
printf("How much did %s earn this month? ", &names[i]);
scanf(" %.2f", &earnings[i]);
totalEarnings += earnings[i];
}
printf("\nTotal earnings are %.2f.\n\n", &totalEarnings);
printf("How much are the shared bills in total? ");
scanf(" %.2f", &bills);
puts("");
for(short k = 0; k < numberOfPeople; ++k){
printf("%s should pay %.2f", &names[k], &bills);
}
puts("");
return 0;
}
You have not allocated any memory to hold the names so are scanf-ing them into null.
All bets are off after this point.
You have problems with extra & characters in the printf calls, which others have noted.
The problem you are reporting is likely caused by the line:
scanf(" %.2f", &earnings[i]);
The problem is that . in scanf formats has no defined meaning (it may be being ignored, or it may be causing the scanf call to fail.) The 2 limits the input to 2 characters, so will fail if anyone has an income with more than 2 digits. So you need to get rid of those and what you REALLY need is to CHECK THE RETURN VALUE of scanf to see if it is failing and do something appropriate if it is. Something like:
while (scanf("%f", &earnings[i]) != 1) {
scanf("%*[^\n]"); /* throw away the rest of the line */
printf("That doesn't look like a number, what did they earn this month? ");
}
Something similar should be done with all the other scanf calls.
As #LoztInSpace pointed out, names is not allocated.
And another mistake is you're using & operator with %s and %f specifiers in in your printf() calls. It won't give result as expected.
Also, is your intention really a loop to ask for "number of peoples"?
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.
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().