0

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?

Brijesh Shah
  • 172
  • 8
chumned
  • 19
  • 4
  • How did you try it? – Marievi Nov 03 '17 at 09:38
  • 1
    Kindly show your research / debugging effort so far. Please read [Ask] page first. – Sourav Ghosh Nov 03 '17 at 09:39
  • 2
    You could convert it to a `do { ... } while ();` loop and put the printf/scanf inside that for example. – Ctx Nov 03 '17 at 09:40
  • 1
    Check return value of `scanf`. – BLUEPIXY Nov 03 '17 at 09:41
  • I kinda went arround it and wrote a whole nother programme for it, with an outside function and a for function in the main function because i didn't know how to convert it directly. It works but I still want to know how to convert gotos into other loops. – chumned Nov 03 '17 at 09:42
  • Try `while(scanf("%f", &array[i][0]) != 1 || array[i][0]<0){ printf("Invalid number: "); while(getchar() != '\n'); }` – BLUEPIXY Nov 03 '17 at 09:46
  • As a side note, you should not iterate over the left-most dimension of a 2D array if you can avoid it. This leads to poor data cache performance. – Lundin Nov 03 '17 at 10:33
  • @Lundin But it's ok to define dynamic arrays in C? Or not really? – chumned Nov 03 '17 at 10:57
  • Depends on the circumstances. – Lundin Nov 03 '17 at 11:47
  • @Lundin In this case, I think it will be fine since they are actually accessing the right-most dimension sequentially within the loop, so it's almost like they've unwrapped the innerloop of a nested loop rather than acting like they're iterating through the wrong dimension as far as accesses for caching is concerned. – Christian Gibbons Sep 18 '19 at 19:17

4 Answers4

1

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

i486
  • 6,491
  • 4
  • 24
  • 41
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);
Programmer dude
  • 167
  • 1
  • 5
  • 23
  • As a nit-pick, it is usually a good idea to avoid multiple checks against the same condition. Which often makes do-while a bit problematic to use. – Lundin Nov 03 '17 at 10:47
0

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' );
}
J...S
  • 5,079
  • 1
  • 20
  • 35
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.)

Lundin
  • 195,001
  • 40
  • 254
  • 396