I have a program that prompts the user to input three float numbers and if those numbers are not positive or not digits it prints out "Invalid number" This is the part of the program done with goto loops and I'd like to get rid of it.
float array[n][3];
int i;
for(i = 0;i<n;i++){
one:
printf( "Please enter first number: ");
scanf("%f", &array[i][0]);
while(array[i][0]<0){
printf("Invalid number: ");
goto one;
}
two:
printf("Please enter second number: ");
scanf("%f", &array[i][1]);
while(array[i][1]<0){
printf("Invalid number: ");
goto two;
}
three:
printf("Please enter third number: ");
scanf("%f", &array[i][2]);
while(array[i][1]<0){
printf("Invalid number: ");
goto three;
}
}
How do I convert loops goto one, goto two and goto three; in a while loop, or some kind of a loop?
See my changes. I modified not only the goto case:
double array[n][3];
int i, j;
char * fst[] = { "first", "second", "third" };
for( i = 0; i < n; i++ )
{
for ( j = 0; j < 3; j++ )
{
while ( 1 )
{
printf( "Please enter %s number: ", fst[j] );
scanf( "%lf", &array[i][j] );
if ( array[i][j] < 0 )
printf("Invalid number.\n");
else break;
}
}
}
Similar blocks are combined with a loop and array of words. double is better than float except in cases of very low RAM (embedded systems). goto is transformed to while loop and break. I suppose you say "invalid number" for negative numbers, not failed scanf. If the check is for failed scanf then it can be modified to if ( scanf( "%lf", &array[i][j] ) < 1 ) ....
You could convert it to do { ... } while(...);
Example:
one:
printf( "Please enter first number: ");
scanf("%f", &array[i][0]);
while(array[i][0]<0){
printf("Invalid number: ");
goto one;
}
To
do
{
printf ("Please enter first number: ");
scanf ("%f", &array[i][0]);
if (array[i][0] < 0)
{
printf ("Invalid number: ");
}
}
while (array[i][0] < 0);
Avoiding goto is generally a good idea (even though some acceptable uses of it exist). Other things to avoid:
Code repetition. (Dangerous)
Storing a value into your final data container before the value is valid. (Dangerous)
Iterating over the left-most dimension of a 2D array instead of the right-most one. (Inefficient)
One possible solution to fix all of the above:
#include <stdio.h>
float enter_float (size_t n)
{
const char* STR_NUMBER[] = { "first", "second", "third" };
float result;
printf("Please enter %s number: ", STR_NUMBER[n]);
scanf("%f", &result);
return result;
}
int main (void)
{
size_t n=3;
float array[n];
for(size_t i=0; i<n; i++)
{
float input;
while( (input = enter_float(i)) < 0.0f)
{
printf("Invalid number\n");
}
array[i] = input;
}
}
(Ideally, the code should also check the result of scanf and also make sure there's no buffer overrun by specifying how many items scanf should read.)
You could do like
for(i = 0;i<n;i++){
while(printf( "Please enter first number: ")>0 && scanf("%f", &array[i][0])==1 && array[i][0]<0 && printf("Invalid number: ") );
while(printf( "Please enter second number: ")>0 && scanf("%f", &array[i][1])==1 && array[i][1]<0 && printf("Invalid number: "));
while(printf( "Please enter third number: ")>0 && scanf("%f", &array[i][2])==1 && array[i][2]<0 && printf("Invalid number: ") );
}
Short circuit evaluation is taken advantage of here.
printf() will return the number of characters it printed which is greater than zero if it was successful.
If printf() was successful, scanf() is executed which returns the number of successful assignments. In this case, it should be 1 if it succeeded.
If both the printf() and scanf() succeeded and array[i][j] is less than zero, a printf() to display error message is done and the loop is repeated.
You could make those while loops like
while(printf( "Please enter third number: ")>0 && scanf("%f", &array[i][2])==1 && array[i][2]<0)
{
printf("Invalid number: ")
}
to make it more readable.
Edit:
If the input is not a valid number, scanf() won't read into the variable as the format specifier is %f.
This may cause problem as the invalid input will remain unconsumed in the input buffer. You need to clear your input buffer.
Something like
int ch;
while( (ch=getch())!=EOF && ch!='\n' );
maybe used to consume from input buffer till a newline. See here for more on this.
getchar() returns EOF on error. Note that getchar() returns an unsigned char converted to an int.
To include this, you may modify those while loops to be like
int ch;
while(printf( "Please enter third number: ")>0 && scanf("%f", &array[i][2])==1 && array[i][2]<0)
{
printf("Invalid number: ")
while( (ch=getch())!=EOF && ch!='\n' );
}
Related
int main(){
char answer;
int numbers[100];
int i = 0;
int size;
int max = -9999;
do{
printf("Please enter an number: ");
scanf("%d", &numbers[i]);
printf("Would you like to keep adding numbers:(Y/N)");
scanf("%c", &answer);
scanf("%c");
i++;
}while(answer == 'Y');
size = sizeof(numbers)/sizeof(numbers[0]);
for(int j = 0; j<size; j++){
if(numbers[j]>= max){
max = numbers[j];
}
}
printf("The max number is: %d", max);
return 0;
}
Hello beginner in C, here in my code i am trying to take an arbitrary amount of (the user enters Y if he/she wishes to enter another number.) input as integers and add them to an array and find the maximum of the input using a for loop, however i am not getting the correct output. What could be the error in my code?
Problems include:
Reading a '\n' when a letter is expected
scanf("%c", &answer); reads the character after the prior input of a number (example:9), which is likely the prior entry's '\n' Enter.
Use a space to consume leading white-space like '\n', space, tab, ...
// scanf("%c", &answer);
scanf(" %c", &answer);
Enable all warnings
Invalid/unnecessary code scanf("%c"); will raise a compiler warning with a well enabled compiler.
Best advice in this answer: enable all compiler warnings to save time.
Start at INT_MIN
The maximum input may be less than -9999.
INT_MIN in <limits.h>
// int max = -9999;
int max = INT_MIN;
Iterate to i
Rather than iterate to 100, only need to iterate to i, the count of values entered.
// for(int j = 0; j<size; j++){
for(int j = 0; j<i; j++){
Check return values
scanf() returns a value indicated the number of successful conversions. Use it to validated input successfully happened.
// scanf("%d", &numbers[i]);
if (scanf("%d", &numbers[i]) != 1) {
; // Report error with TBD code.
}
Do not loop too often
// } while(answer == 'Y');
} while(answer == 'Y' && i < 100);
There is no reason to save an array of values
The maximum could be calculated as data is entered.
int max = INT_MIN;
do {
int num;
printf("Please enter an number: ");
if (scanf("%d", number) != 1) {
break;
}
if (num > max) {
max = num;
}
printf("Would you like to keep adding numbers:(Y/N)");
if (scanf(" %c", &answer) != 1) {
break;
}
} while (answer == 'Y' || answer == 'y');
printf("The max number is: %d", max);
Future Improvements
Handle values outside int range. Research intmax_t.
Detect case of no valid input entered. Research fgets()
Detect non-valid Y/N input. Research fgets()
Recover, rather than quit loop with invalid input.
This is a snippet of my code. I'm confused why is digit can't function. It should if we input character/alphabet. The line is digit print "Please enter in numeric " but it doesn't print it. I need your opinion about this.
This my code:
printf("\nenter the amount of food to be purchased : ");
scanf("%d", &b);
printf("\n");
if (b >= 0) {
for (a=1; a<=b; a++){
printf("the price of food of- %d \t : ",a);
scanf("%d", &c);
printf("\n");
if (isdigit(c)) {
printf("Please enter in numeric !!\n");
while ((getchar()) != '\n');
system("PAUSE");
goto cashier;
}
printf("the amount ordered \t : ");
scanf("%d", &d);
printf("\n");
if (isdigit(d)) {
printf("Please enter in numeric !!\n");
while ((getchar()) != '\n');
system("PAUSE");
goto cashier;
}
scanf("%d", &c);. Reads an integer to c. When you call isdigit(c), you are not checking whether the input string is a number, you are checking whether the number inputted corresponds to an ascii character that represents a digit. This is not the intended behavior. What you want is this:
while (scanf("%d", &c) != 1) // Repeatedly get input until scanf reads 1 integer.
{
while (getchar()!='\n'); // Clear stdin.
puts("Please enter a number!");
}
// The resulting number is now stored in c.
This will try to read a number (not a string) into c. If the user does not enter 1 number, scanf() will not return 1 and the loop will try again. make sure that c is declared as an int and not a char, else numbers above 128 will overflow.
How do I make my if statement ask the user to try again if the input is a negative number or a letter?
struct foodstuff {
float amount;
};
void add(struct foodstuff *tmpAdd) {
printf("Write amount: ");
scanf("%f", &tmpAdd->amount);
while (tmpAdd->amount != 0) {
if (tmpAdd->amount < -1 || isalpha(tmpAdd->amount)) {
printf("Type in a valid number!\n");
printf("Write amount: ");
getchar();
scanf("%f", &tmpAdd->amount);
getchar();
}
else {
scanf("%f", &tmpAdd->amount);
getchar();
}
}
};
I think you can rephrase your code to use a do loop instead:
do {
printf("Enter a positive number with no characters:\n");
int result = scanf("%f", &tmpAdd->amount);
while (tmpAdd->amount <= 0 || result != 1);
Note that I have removed the call to isalpha(), which acts only a single character at a time. Instead, I propose just checking that the entered number is a valid float and that it is greater than zero. If scanf does not succeed to read in a valid float, then its return value would be not be 1 and the loop would repeat. And the same is the case for entering a valid float which is a negative number.
As chux said, you could first read the input with fgets() and then parse it.
Like
char buff[100], *ptr;
float f;
while(fgets(buff, sizeof(buff), stdin)!=NULL)
{
buff[strlen(buff)-1]='\0';
f=strtof(buff, &ptr);
if(errno==ERANGE)
{
printf("\nPossible overflow.");
errno=0;
continue;
}
if(f<0 || *ptr!='\0')
{
printf("Type in a valid number!\n");
continue;
}
tmpAdd->amount=f;
printf("\n%f", f);
}
Here, fgets() is used to read the input on each iteration. fgets() will return NULL upon error.
The
buff[strlen(buff)-1]='\0';
is done because fgets() will read in the trailing \n into buff as well. We modify that \n to be the \0 character denoting the end of string with buff[strlen(buff)-1]='\0';.
strtof() is used to extract the value from buff.
It is in stdlib.h.
In case buff has something other than numbers, the number part would be converted and returned by strtof() and the ptr pointer would be made to point to the first non-numeric part of buff.
So if the first character in the string pointed to by ptr is the \0 character, there were no non-numeric parts in buff.
If the input value was too large or too small to be accommodated in a float, errno would be set to ERANGE. You need to include errno.h for that.
If overflow (or underflow) occurred, we set errno to 0 and continue.
And (tmpAdd->amount<-1) would be false even if tmpAdd->amount were -1 and -1 is negative. You need (tmpAdd->amount<0) instead.
Also, your loop would exit only when tmpAdd->amount becomes 0. You could simply do
tmpAdd->amount=0;
if that would do.
Otherwise, you can add a
if(f==0)
{
break;
}
at the end of the while loop.
I did some changes to my code, it looks like this now:
printf("Write amount: ");
scanf("%f", &(tmpAdd + index)->amount);
getchar();
do {
if (tmpAdd->amount <= -1 || isalpha(tmpAdd->amount != 0)) {
printf("Type in a valid number!\n");
printf("Write amount: ");
scanf("%f", &(tmpAdd + index)->amount);
getchar();
}
else if (isdigit(tmpAdd->amount >= 0)) {
scanf("%f", &(tmpAdd + index)->amount);
//getchar();
}
} while (tmpAdd->amount <= -1 || isalpha(tmpAdd->amount != 0));
};
Main looks like this:
int main (void) {
int input, noFood = 0;
int flag = 1;
printf("Welcome to the shopping list manager. \n\n");
struct foodstuff food1;
while (flag == 1) {
printf("1 - add food\n");
printf("2 - print shopping list\n");
printf("3 - end\n\n");
printf("What do you want to do? ");
scanf("%d", &input);
clear();
switch (input) {
case 1: add(&food1, noFood); noFood++; break;
case 2: print(&food1, noFood); break;
case 3: printf("\nExiting program\n"); flag = 0; break;
default: printf("Please enter a valid choice\n");
}
}
return 0;
}
And the output like this:
Output
The only problem remaining is that when I want to add another item (add food) for the second time and I type a letter or a negative number, it doesn't run through the if statements.
This question already has answers here:
fgets doesn't work after scanf [duplicate]
(7 answers)
Closed 6 years ago.
I will try to explain the issue here.
I have written this code that accepts various types of inputs:
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
int main()
{
int number;
printf("press <ENTER> to continue...");
while( getchar() != '\n' );
char *p, s[100];
int n=0;
printf("enter a number: ");
while (fgets(s, sizeof(s), stdin))
{
n = strtol(s, &p, 10);
if (p == s || *p != '\n')
{
printf("Invalid integer, please try again: ");
}
else
break;
}
printf("You entered: %d\n", n);
printf("Enter an integer between 10 and 20: ");
scanf("%d", &number);
while (1)
{
if (number < 10 || number > 20)
{
printf("Invalid value, 10 < value < 20: ");
scanf("%d", &number);
}
else
{
break;
}
}
printf("You entered: %d\n", number);
//part 3
double decpart;
printf("Enter a floating number num: ");
char buf[100];
int len;
char *endptr;
while (1)
{
fgets(buf,sizeof(buf),stdin);
len = strlen(buf)-1;
// right strip spaces (replace by linefeed like fgets ends the input)
while(len>0)
{
len--;
if (buf[len]==' ')
{
buf[len]='\n';
}
else
{
break;
}
}
double floatnum = strtod(buf,&endptr);
if (endptr[0]!='\n')
{
printf("Invalid floating point number, enter again: ");
}
else
{
int intpart = (int)floatnum;
double decpart = floatnum - intpart;
if (decpart == 0.000000){
printf("Invalid floating point number, enter again: ");
}
else
{
printf("Number entered = %.2f\n", floatnum);
break;
}
}
}
double floatnum1;
printf("Enter a floating point number between 10.00 and 20.00: ");
scanf("%lf", &floatnum1);
while (1)
{
if (floatnum1 < 10.00 || floatnum1 > 20.00)
{
printf("Invalid value, 10.000000 < value < 20.000000: ");
scanf("%lf", &floatnum1);
}
else
{
break;
}
}
printf("You entered: %0.2lf\n", floatnum1);
printf("End of tester program for milestone one!\n");
return 0;
}
Problem occurs on Part 3 of this code. I see on screen Enter a floating number num: and immediately without waiting for user input it prints Invalid floating point number, enter again:
This is not the case if I just run part3(commented here in code as //part3) independently, it just works fine.
Any idea, why that is happening?
The reason for this behaviour lies in the usage of scanf followed by fgets
scanf reads a number from standard input, and stops as soon as it encounters a non-digit character, which is the newline in this case.
Next fgets reads a whole line. But now there's still the single newline in the input, which satisfies fgets even though this is only an empty line.
When you skip over whitespace and finally check for a newline, endptr only points to a \0 character. Thus the message
Invalid floating point number, enter again:
To fix this, you must first skip whitespace before reading further with fgets.
I have a trivial question to ask. My program should take postive integers only. If there is anything illegal, the user should be prompted to input a number again.
The code I have for now is:
#include<stdio.h>
int main(){
int reads;
int num=0;
char a;
while(num<=0){
printf("Please Enter positive integer: ");
while(((reads = scanf("%d%c", &num, &a)) != 2 && reads != EOF) || a != '\n' ){
do {
printf("Please Enter positive integer: ");
reads = scanf("%c", &a);
}while(reads != EOF && a != '\n');
}
}
printf("Num is: %d", num);
}
The code above almost did what I want; however, when the input is multiple letters, the output prompts will be print multiple times, which bothers me a lot.
Please Enter positive integer: pdesf
Enter positive numbers only: Enter positive numbers only: Enter positive numbers only: Enter positive numbers only: Enter positive numbers only: dfwerasdfwe
Enter positive numbers only: Enter positive numbers only: Enter positive numbers only: Enter positive numbers only: Enter positive numbers only: Enter positive numbers only: Enter positive numbers only: Enter positive numbers only: Enter positive numbers only: Enter positive numbers only: Enter positive numbers only:
I'd appreciate if you can help me fix this or offer better solutions for this seemly trivial problem. Thanks ahead!
Use fgets to read a whole line into a buffer. If you only want to process the first character, you can just ignore the rest. Something along the lines of:
char buf[MAX_LINE_LEN];
if (fgets(buf, MAX_LINE_LEN, stdin))
{
char a = buf[0];
/* Do handling... */
}
else
{
/* error */
}
Coded in browser, may contain traces of error.
while(num<=0){
printf("Please Enter positive integer: ");
while(((reads = scanf("%d%c", &num, &a)) != 2 && reads != EOF) || a != '\n' ){
printf("Please Enter positive integer: ");
while(getchar() != '\n');
}
}
i have solved your program. Try the following program in Turbo C++:
#include<stdio.h>
#include<conio.h>
main()
{
char n[2],ni;
clrscr();
GET:
printf("Enter positive number: ");
scanf("%s",&n);
if(atoi(n)>0)
{
printf("You have entered ");
ni=atoi(n);
printf("%d",ni);
}
else if(atoi(n)<=0)
{
printf("Wrong choice\n");
goto GET;
}
else
{
printf("Wrong choice\n");
goto GET;
}
getch();
}