chumned
chumned

Reputation: 19

How do I convert this goto loop in a while loop?

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

Answers (4)

J...S
J...S

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

Lundin
Lundin

Reputation: 215360

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

Upvotes: 0

Programmer dude
Programmer dude

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

i486
i486

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

Related Questions