13  Repetições com do while

\(\newcommand\Id[1]{\mbox{\textit{#1}}}\)

Este capítulo contempla a estrutura e aspectos lógicos do do while, cuja função é executar comandos repetitivamente.

13.1 A estrutura de repetição do while

O do while é uma estrutura de repetição condicional e, assim, depende de uma dada condição para determinar se haverá ou não outra repetição. Em oposição ao while (Capítulo 11) e ao for (Capítulo 12), o teste de continuidade é feito depois da execução do comando.

do comando while ( condição_de_continuidade ) ;

Nessa estrutura de repetição, o primeiro passo é a execução de comando que, como nas demais estruturas, pode ser um comando simples ou um bloco de comandos. Terminada a execução, a condição_de_continuidade é avaliada, seguindo para nova repetição se for verdadeira ou encerrando do while se não for.

Assim, esta estrutura executa comando pelo menos uma vez.

Para exemplificar, o trecho de código seguinte ilustra uma leitura de um valor real garantindo que esteja no intervalo de 0 a 10 (inclusive).

/*
Leitura de valor com garantia de estar no intervalo [0, 10], com releitura
    se necessário
Requer: uma sequência de valores terminada por um no intervalo [0, 10]
Assegura: apresentação do último valores
*/
#include <stdio.h>

int main(void) {
    double valor;
    do {
        char entrada[160];
        printf("Digite um valor: ");
        fgets(entrada, sizeof entrada, stdin);
        sscanf(entrada, "%lf", &valor);
    } while (valor < 0 || valor > 10);

    printf("\nValor aceito: %g.\n", valor);

    return 0;
}
Digite um valor: 12.2
Digite um valor: -3.05
Digite um valor: 7.4

Valor aceito: 7.4.

A lógica da leitura é direta: faz a leitura e, caso não esteja no intervalo especificado, faz a leitura novamente. Neste caso, a primeira leitura é necessária e seu valor sempre é relevante.

Um detalhe relevante é o escopo das declaraçoes de variáveis: como entrada é usada apenas localmente, é declarada dentro do bloco de comandos do do while; valor, por sua vez, tem que ser declarada fora (antes) do bloco, caso contrário não existiria para ser escrita depois da repetição.

Curiosidade

Em um laço do while, as variáveis declaradas dentro do bloco de comandos ficam tão restritas ao próprio bloco que não podem nem ser acessadas na condição da repetição.

do {
    bool eh_valido;  // declaração interna

    ...
} while (eh_valido);  // `eh_valido` não existe aqui...

13.2 Exemplos

Nesta seção há alguns exemplos de programas que utilizam a estrutura de repetição do while.

13.2.1 Leitura de senha

Este exemplo é de um programa que solicita uma senha para autorizar ou não a execução. A senha é hardcoded (i.e., fixa no código e nada versátil) e há um limite de três tentativas.

/*
Processamento somente mediante senha
Requer: uma sequência de tentativas de senha terminada com a senha correta
    ou com comprimento máximo de três tentativas
Assegura: apresentação de mensagem autorizando ou negando acesso conforme a
    a senha esteja ou não correta
*/
#include <stdio.h>
#include <stdbool.h>
#include <string.h>

int main(void) {
    bool validou_senha = false;
    int numero_tentativas = 0;
    do {
        numero_tentativas++;
        printf("Digite a senha: ");
        char senha[160];
        fgets(senha, sizeof senha, stdin);

        validou_senha = strcmp(senha, "12345678\n") == 0; // é igual?
    } while (!validou_senha && numero_tentativas < 3);

    if (validou_senha)
        printf("\nAcesso autorizado.\n");
    else
        printf("\nAcesso negado.\n*** Este problema será reportado.\n");

    return 0;
}
Digite a senha: senha
Digite a senha: senha123
Digite a senha: 123456

Acesso negado.
*** Este problema será reportado.

Neste código há o uso da função strcmp, declarada no arquivo de cabeçalho string.h. Ela retorna zero se as duas cadeias de caracteres passadas como parâmetro forem iguais1. Uma observação interessante é que senha é declarada dentro do bloco do do while, uma vez que ela não é necessária fora dele; o mesmo comentário não é válido para validou_senha.

13.2.2 Pense em um número de 1 a 15.000!

O programa deste exemplo se propõe a adivinhar um número pensado pelo usuário em no máximo 13 tentativas.

/*
Pense em um número de 1 até 15.000 para eu adivinhar qual é!
Requer: respostas do usuário dizendo se o valor é maior (+) ou menor (-)
    que o número pensado
Assegura: a apresentação do número pensado pelo usuário em até 14 tentativas
*/
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>

int main(void) {
    printf("Pense em um número de 1 a 15000 e responda...\n");
    sleep(8);  // 8s para pensar!

    int inicio_intervalo = 1;
    int fim_intervalo = 15000;
    int numero_tentativas = 0;
    int tentativa;
    bool acertei = false;
    do {
        numero_tentativas++;
        tentativa = (inicio_intervalo + fim_intervalo) / 2;

        printf("É o %d?\n", tentativa);
        printf("Responda + se o número for maior, - se for menor "
               "ou = se eu acertei: ");
        char resposta[160];
        fgets(resposta, sizeof resposta, stdin);
        switch (resposta[0]) {
            case '+':
                inicio_intervalo = tentativa + 1;  // tentarei número maior
                break;
            case '-':
                fim_intervalo = tentativa - 1;  // tentarei número menor
                break;
            case '=':
                acertei = true;  // UFA!
                break;
            default:
                printf("Não entendi a resposta... tente de novo.\n");
                numero_tentativas--;  // essa tentativa não conta!
        }

        if (!acertei) {
            if (numero_tentativas == 13)
                printf("Minha ÚLTIMA CHANCE!!!\n");
            else if (numero_tentativas > 10)
                printf("Só tenho mais %d chances.. :-(\n",
                       14 - numero_tentativas);
            sleep(0.7);  // pausa leve de dramaticidade
        }
    } while (!acertei && fim_intervalo >= inicio_intervalo);

    if (acertei)
        printf("\n\nBeleza! Acertei em %d tentativas!\n", numero_tentativas);
    else
        printf("\n\nHummmm! Algo de errado não está certo aqui...\n"
               "Suas respostas foram corretas?\n");

    return 0;
}
Pense em um número de 1 a 15000 e responda...
É o 7500?
Responda + se o número for maior, - se for menor ou = se eu acertei: +
É o 11250?
Responda + se o número for maior, - se for menor ou = se eu acertei: +
É o 13125?
Responda + se o número for maior, - se for menor ou = se eu acertei: +
É o 14063?
Responda + se o número for maior, - se for menor ou = se eu acertei: -
É o 13594?
Responda + se o número for maior, - se for menor ou = se eu acertei: -
É o 13359?
Responda + se o número for maior, - se for menor ou = se eu acertei: +
É o 13476?
Responda + se o número for maior, - se for menor ou = se eu acertei: =


Beleza! Acertei em 7 tentativas!

  1. Manipulações de cadeias de caracteres são tratadas em detalhes no Capítulo 16.↩︎