Reputation: 19
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?
Upvotes: 0
Views: 1115
Reputation: 5207
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' );
}
Upvotes: 0
Reputation: 215360
Avoiding goto
is generally a good idea (even though some acceptable uses of it exist). Other things to avoid:
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.)
Upvotes: 0
Reputation: 167
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);
Upvotes: 1
Reputation: 6570
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 ) ...
.
Upvotes: 1