⚡ Cap 06: Laços Indeterminados (while, do-while) e Sentinelas
Bem-vindo ao sexto capítulo da Especialização em Engenharia de Sistemas com Linguagem C (C17/C23)! ⚡
Executar manualmente um conjunto de comandos dezenas, centenas ou milhões de vezes seria inviável. As Estruturas de Repetição (Loops) são os mecanismos que permitem automatizar tarefas repetitivas, processar fluxos contínuos de dados e criar menus interativos que permanecem em execução até que uma condição de parada seja satisfeita.
🗺️ Mapa Conceitual do Capítulo
graph TD
A["Laços de Repetição em C"] --> B["1. Os 3 Componentes Fundamentais"]
A --> C["2. Estrutura while (Pré-teste)"]
A --> D["3. Estrutura do-while (Pós-teste)"]
A --> E["4. Padrões de Algoritmos"]
B --> B1["Inicialização, Condição de Continuidade e Atualização"]
C --> C1["Avalia antes de executar (0 a N iterações)"]
D --> D1["Executa antes de testar (no mínimo 1 iteração garantida)"]
E --> E1["Contadores, Acumuladores, Sentinelas e Validação de Dados"]
🔁 1. Os Três Componentes Obrigatórios de um Laço
Todo laço de repetição determinístico ou condicional depende estritamente de três elementos:
- Inicialização: A definição do valor de partida da variável de controle antes do início do laço (ex:
int i = 1;). - Condição de Continuidade: A expressão lógica testada a cada volta. Enquanto for verdadeira (diferente de 0), o laço continua (ex:
i <= 10). - Atualização / Passo: A alteração do valor da variável de controle em direção à condição de parada (ex:
i++oui += 2).
flowchart TD
INIT["1. Inicialização\nint contador = 1;"] --> COND{"2. Condição\ncontador <= 10 ?"}
COND -- Sim (Verdadeiro) --> CORPO["Executa Corpo do Laço\nprintf('%d', contador);"]
CORPO --> ATUAL["3. Atualização\ncontador++;"]
ATUAL --> COND
COND -- Não (Falso) --> FIM["Fim do Laço (Prossegue o programa)"]
style INIT fill:#0284c7,stroke:#38bdf8,color:#ffffff
style COND fill:#d97706,stroke:#f59e0b,color:#ffffff
style CORPO fill:#059669,stroke:#34d399,color:#ffffff
style ATUAL fill:#db2777,stroke:#f472b6,color:#ffffff
⏳ 2. A Estrutura while (Laço com Pré-Teste)
Na estrutura while, a condição de continuidade é avaliada antes de qualquer comando do corpo ser executado. Se a condição for falsa logo no primeiro teste, o corpo do laço não executará nenhuma vez (0 iterações):
#include <stdio.h>
int main(void) {
int contador = 1; // 1. Inicialização
// 2. Condição de Continuidade
while (contador <= 5) {
printf("Volta #%d\n", contador);
contador++; // 3. Atualização
}
return 0;
}
🔄 3. A Estrutura do...while (Laço com Pós-Teste)
Na estrutura do...while, o corpo do laço é executado primeiro e o teste condicional é realizado no final. Isso garante que o código seja executado obrigatoriamente pelo menos uma vez:
#include <stdio.h>
int main(void) {
int opcao;
do {
printf("\n=== MENU DE CONTROLE ===\n");
printf("1. Status do Servidor\n");
printf("2. Reiniciar Servicos\n");
printf("0. Sair\n");
printf("Escolha uma opcao: ");
scanf("%d", &opcao);
if (opcao == 1) printf(">> Servidor Operacional!\n");
else if (opcao == 2) printf(">> Reiniciando...\n");
} while (opcao != 0); // Ponto e vírgula obrigatório no final!
printf("Sistema encerrado.\n");
return 0;
}
📊 4. Padrões Clássicos de Algoritmos em Laços
1. Padrão Contador vs Padrão Acumulador
- Contador (
cont++): Registra a frequência/quantidade de eventos ocorridos (incremento constante de 1 em 1). - Acumulador (
soma += valor): Acumula a soma total de valores variáveis. Deve sempre ser inicializado com zero (0.0).
2. Repetição com Valor Sentinela
Quando a quantidade exata de repetições não é conhecida previamente, utiliza-se um valor sentinela especial (como 0 ou -1) para sinalizar o término da entrada de dados:
int valor;
int soma = 0;
int totalItens = 0;
printf("Digite numeros inteiros positivos (ou 0 para encerrar):\n");
scanf("%d", &valor);
while (valor != 0) { // 0 é o valor sentinela de parada
soma += valor; // Padrão acumulador
totalItens++; // Padrão contador
scanf("%d", &valor);
}
3. Validação de Dados de Entrada
Garante que o usuário informe apenas dados dentro de limites válidos antes de prosseguir:
double nota;
printf("Digite a nota do aluno (0.0 a 10.0): ");
scanf("%lf", ¬a);
// Enquanto a nota for inválida, força o usuário a digitar novamente
while (nota < 0.0 || nota > 10.0) {
printf("Nota invalida! Digite um valor entre 0.0 e 10.0: ");
scanf("%lf", ¬a);
}
🚫 5. A Anatomia do Laço Infinito e Como Evitá-lo
Um Laço Infinito (Infinite Loop) ocorre quando a condição de continuidade permanece perpetuamente verdadeira, travando a CPU em consumo de 100%:
// ❌ ERRO GRAVE: Esquecimento da atualização da variável de controle
int i = 1;
while (i <= 10) {
printf("%d\n", i);
// Falta o i++! O 'i' valerá sempre 1 e o laço nunca terminará!
}
🔍 6. Diagnóstico & Resolução de Problemas (Troubleshooting)
| Sintoma Observado | Causa Provável | Como Resolver |
|---|---|---|
| O programa trava, o console congela e o cursor pisca indefinidamente | Laço infinito provocado pela ausência de incremento/atualização da variável de controle. | Verifique se a variável testada no while está sendo modificada dentro do corpo do laço. |
O laço do-while não compila acusando erro de sintaxe |
Esquecimento do ponto e vírgula ; após o parêntese do while(...). |
O do { ... } while(cond); exige ; obrigatório no final. |
| A soma acumulada exibe números gigantescos e bizarros | A variável acumuladora não foi inicializada com 0 (continha “lixo de memória”). |
Sempre inicialize acumuladores na declaração: double soma = 0.0;. |
🏆 7. Desafio Prático de Consolidação
Enunciado do Desafio:
Desenvolva um programa em C chamado coletor_sensores.c que monitore leituras de pressão de uma caldeira industrial:
- O programa deve receber leituras inteiras de pressão em PSI.
- A leitura deve ser repetida continuamente até que o operador digite
-1(valor sentinela de parada). - Ignore leituras negativas diferentes de
-1emitindo um aviso de ruído no sensor. - Ao final da coleta, calcule e exiba:
- A quantidade total de leituras válidas registradas (Contador).
- A média aritmética das pressões coletadas (Acumulador / Contador).
- A maior pressão registrada durante o monitoramento.
🔍 Ver Solução Comentada do Desafio
#include <stdio.h>
int main(void) {
int valor;
int totalTransacoes = 0;
int somaTotal = 0;
int maior = -1;
printf("Digite valores inteiros positivos (ou -1 para encerrar):\n");
while (1) {
printf("Valor: ");
if (scanf("%d", &valor) != 1 || valor == -1) {
break; // Sentinela de parada
}
if (valor < 0) {
printf("Valor invalido ignorado.\n");
continue;
}
totalTransacoes++;
somaTotal += valor;
if (valor > maior) maior = valor;
}
printf("====================================================\n");
printf(" Total de Entradas: %d\n", totalTransacoes);
printf(" Soma Total: %d\n", somaTotal);
if (totalTransacoes > 0) {
printf(" Media: %.2lf\n", (double)somaTotal / totalTransacoes);
printf(" Maior Valor: %d\n", maior);
}
printf("====================================================\n");
return 0;
}
🧭 Navegação Rápida
| 📖 Teoria | 📊 Slides | 🧠 Quiz | 💻 Exemplos | 🧩 Exercícios | | :— | :— | :— | :— | :— | | Ler Teoria | Ver Slides | Fazer Quiz | Ver Exemplos | Praticar Exercícios |
🧭 Navegação do Capítulo: ⬅️ Capítulo Anterior · 📚 Sumário do Módulo · ➡️ Próximo Capítulo