How to get the program out of the loop

Asked

Viewed 184 times

0

In the exercise I am doing, it is asked that when the number of repetitions is 0, finish the execution, but when I type 0 it does nothing and continues to read numbers. It reads a number K of repetitions, then the central coordinates of a place (thinking of a graph, these two entries would define the 0 of the place) and the following two numbers are where is '?' residence and with this we need to define where this is located (northwest, northeast, southeast, southwest)

this is the code:

#include <stdio.h>

int main(){
    int K = 1, N, M; //n e m = ponto 0 do grafico, divisas para as regioes
    int X, Y; // onde a residencia se encontra
    int i;

    while(scanf("%d", &K) != 0){

        scanf("%d %d", &N, &M);
        i = K;

        for(; i > 0; i--){
            scanf("%d %d", &X, &Y);

            if(X == N || Y == M){
                printf("divisa\n");
            }

            else if(X > N && Y > M){
                printf("NE\n");
            }
            else if(X < N && Y > M){
                printf("NO\n");
            }
            else if(X > N && Y < M){
                printf("SE\n");
            }
            else{
                printf("SO\n");
            }
        }
    }

    if(K == 0)
        return 0;

    return 0;
}
  • I believe you are misinterpreting the return of the scanf function. When you inform 0 to the value of K the return of scanf("%d", &K) will be 1.

  • Complementing: the scanf("%d", &K) will return 0 if instead of you inform some value inform only EOF ( D) and this way there will be no assignment to K and the return of the function will be 0.

1 answer

2


scanf() has this prototype:

    int scanf(const char *format, .. variaveis...);

That means she returns one int. And you must read a lot. That int is the total of values read, and it may be that you have not read anything and then your program is gone. scanf() was not written to read data from the keyboard and it is a nightmare to do so. There is a reason for it to have that name: scan formatted input is its purpose. And the keyboard is anything but formatted input: 105 freedom keys. I think scanf() was written by Ken Thompson, one of the best developers of all time. To read formatted input. It’s not his fault.

An example like in your program

#include <stdio.h>
int main()
{  
    for (int X = 1, Y=0; X != 0;)
    {
        printf("Entre dois inteiros [0 0 para sair]: ");
        scanf("%d %d", &X, &Y);
        printf("\tLidos %d e %d\n", X, Y);
    };  // for()
};  // main()

It is not a beautiful program :( but it reads two numbers until the first one is 0. It does not test the return of scanf(), does not attempt to consume data that has been entered by mistake, nothing. Here is a typical result

Entre dois inteiros [0 0 para sair]: 1 1
        Lidos 1 e 1
Entre dois inteiros [0 0 para sair]: 2 2
        Lidos 2 e 2
Entre dois inteiros [0 0 para sair]: 5 6
        Lidos 5 e 6
Entre dois inteiros [0 0 para sair]: 5



45666
        Lidos 5 e 45666
Entre dois inteiros [0 0 para sair]: 2w
        Lidos 2 e 45666
Entre dois inteiros [0 0 para sair]:    Lidos 2 e 45666
Entre dois inteiros [0 0 para sair]:    Lidos 2 e 45666
Entre dois inteiros [0 0 para sair]:    Lidos 2 e 45666

... 

In short

  • when you type only the obvious, one number and the other, ok
  • when you type a number you can hit 500 enter and the screen walks until the other number appears, but then it’s okay
  • if you tap a letter for example, such as "2w" in the above case, the program will loop and will "read" the 2 numbers before, 2 and 45666 in the case, for all eternity or until you cancel the program. And the blame is on the program

Why does this happen?

someone actually typed in '2', 'w' and then ENTER. scanf() does this: scan. go there and find the w. And it’s with the mission of scanning two numbers. It’s not there. The function can’t just discard what’s there because it can be given important. Another function can go there and read the letters for example. scanf() is a scanner. There is no "rubbish" or "clear the buffer": is information that is there. It has to be consumed by the program and not by a scanner hoping to read a int and then another.

How to fix this m3rd@?

  • In general the best is never to use scanf() to read from the keyboard. It was not written for this.
  • Read the return value. Each specifier, that section that has a % and not two, equals something to be read. Unless you have an asterisk in front, but I’m not rewriting the manual here. So you’re using "%d %d" can return 1, 2 or zero. If you do not test the life follows, in joy and sadness, the way it works. See the sample program at the end
  • After scanf() be satisfied, read everything on the line up to and including the '\n', for example using a loop like this, with ch declared as int:
    do { ch = getc(stdin); } while ((ch != '\n') && (ch != EOF));
  • if you are using Windows you can call --- windows. h --- Flushconsoleinputbuffer(Getstdhandle(STD_INPUT_HANDLE)); the official for this

  • don’t use fflush() for inflows. fflush() is only guaranteed for outflows.

  • You can try something with the specifiers of scanf(), %[1234] for example accepts only these 4 digits. %[^1234] accepts everything except these digits. Then %[^\n] accepts everything except one enter, the one newline, and if you are reading as text you will read the whole line

  • can read letters with fgetc() or lines with fgetc(), more secure. And then convert to the digits using the dozens of C functions such as strtol()

  • even so can go wrong. When you can’t risk mocking the screen or reading something inappropriate you

    • sets the list of accepted keys
    • read without echo and without changing the cursor
    • if valid you show the letter and advance the cursor, otherwise for example play a short beep or vibrate
    • if you read the field everything goes back to normal and processes the value. It’s what you do in the bank, in the store... This when the device requires reading characters and has no graphical interface

Back to your show

        Y

        ^
  NO    |    NE
        |
-----------------> X
        |
  SO    |    SE

You want to read a coordinates like this, with the origin in (M,N), in K cycles of (X,Y) points and tell what quadrant they are in. Or if they are in the chevron.

I took the liberty of editing your program and including a few things to get around the problem of using scanf(), in the line of what I wrote above. And I included a little bit of Boole algebra to simplify the logic and use a table, the Truth Table of the times of George, the creator. I changed the entry of the dots to use a comma between them, I found it more consistent with the Cartesian notation, and it is better to scanf() Boole logic, algebra and a bitmask

  • if (X>N) is on the north side
  • if (Y<M) is on the West side
  • using the value 2 to be NORTH and the value 1 to be EAST you have a table of 4 values.
  • if the address (X,Y) is on one of the axes, is "on the motto" as he wrote in his program, and so this is the fifth option.
  • in C and other ZERO languages is FALSE. 1 is true. So you understand that every expression becomes a number. (X>2) is 1 if X is greater than 2, or 0

So you can use a table like this

    const char* quadrante[5] = {
        " na Divisa de ",
        " a SO de ",
        " a NO de ",
        " a SE de ",
        " a NE de " };

And a variable int idx = 1; and calculate the index thus:

            if (X > N) idx += 2;
            if (Y > M) idx += 1;

And use a single printf() to write the answer in the program.

            printf("    (%d,%d)%s(%d,%d)\n", X, Y,
              quadrante[( 1 + (X>N)+(X>N) + (Y>M)) * (X!=N) * (Y!=M)], M, N);

And see it like that on the screen

    (-1,-1) a SO de (0,0)

Perhaps you find it simpler. The computer surely thinks: it is absurdly fast to evaluate a bitmask. And easier to control logic: you just need to adjust to such a truth table as George said. No need to hunt code in the program.

Here is a test program

Typed on top of your code with changes to protect against invalid data on the keyboard.

#include <stdio.h>

int main()
{
    const char* quadrante[5] = {
        " na Divisa de ",
        " a SO de ",
        " a NO de ",
        " a SE de ",
        " a NE de " };
    unsigned ciclos = 0;
    int N, M; // n e m = origem do grafico, divisas para as regioes
    int X, Y; // onde a residencia se encontra
    int res = 0;
    int idx = 0;
    int ch;
    const char* mascara = " %d,%d";

    // loop ate ler algo
    do { printf("\nTotal de ciclos (0 para encerrar): "); }
    while ((res = scanf("%d", &ciclos)) != 1);

    while (ciclos != 0)
    {
        printf("=> %d ciclos\n", ciclos);
        // loop ate ler dois valores 
        do { 
            printf("\nCoordenadas N,M separadas por virgula: ");
            res = scanf(mascara, &N, &M);
            do { ch = getc(stdin); } while ((ch != '\n') && (ch != EOF));
        }   while (res!=2);

        for (unsigned i = 1; i <= ciclos; i++)
        {   // UM CICLO
            idx = 1; // cada (X,Y) tem um indice
            printf("\n=> Ciclo %d de %d\n", i, ciclos);
            do {
                printf("\n    Onde fica? X,Y separados por virgula: ");
                res = scanf(mascara, &X, &Y);
                do { ch = getc(stdin); } while ((ch != '\n') && (ch != EOF));
            }   while (res!=2);
            // menos contas: (X>N) vale 2 (Y>M) vale 1
            if (X > N) idx += 2;
            if (Y > M) idx += 1;
            printf("    (%d,%d)%s(%d,%d)\n", X, Y,
              quadrante[( 1 + (X>N)+(X>N) + (Y>M)) * (X!=N) * (Y!=M)], M, N);
        };  // for()

        do { printf("\nTotal de ciclos (0 para encerrar): "); }
        while ((res = scanf(" %d", &ciclos)) != 1);
    };
    return 0;
};  // main()

Here’s a normal execution

Total de ciclos (0 para encerrar): 8
=> 8 ciclos

Coordenadas N,M separadas por virgula: 0,0

=> Ciclo 1 de 8

    Onde fica? X,Y separados por virgula: 1,1
    (1,1) a NE de (0,0)

=> Ciclo 2 de 8

    Onde fica? X,Y separados por virgula: 1,-1
    (1,-1) a SE de (0,0)

=> Ciclo 3 de 8

    Onde fica? X,Y separados por virgula: -1,-1
    (-1,-1) a SO de (0,0)

=> Ciclo 4 de 8

    Onde fica? X,Y separados por virgula: -1,1
    (-1,1) a NO de (0,0)

=> Ciclo 5 de 8

    Onde fica? X,Y separados por virgula: 0,1
    (0,1) na Divisa de (0,0)

=> Ciclo 6 de 8

    Onde fica? X,Y separados por virgula: 1,0
    (1,0) na Divisa de (0,0)

=> Ciclo 7 de 8

    Onde fica? X,Y separados por virgula: 0,0
    (0,0) na Divisa de (0,0)

=> Ciclo 8 de 8

    Onde fica? X,Y separados por virgula: 1,1
    (1,1) a NE de (0,0)

Total de ciclos (0 para encerrar): 0

The program loops in the readings until it reads the expected values.

[compiled on Windows with CL 19.27 compiler]

Browser other questions tagged

You are not signed in. Login or sign up in order to post.