C break e continue
Até aqui, um laço só terminava quando a condição ficava falsa, e cada volta rodava o corpo inteiro, do começo ao fim. Às vezes você quer mais controle: parar no meio, porque já achou o que procurava, ou pular o resto de uma volta, porque aquele item não interessa. Para isso existem duas palavras: break ("quebrar", sair do laço) e continue ("continuar", ir direto para a próxima volta).
- Como usar
breakpara procurar e parar assim que achar. - O laço infinito de propósito,
while (1), com a saída no meio. - Como saber, depois do laço, por que ele parou (com uma variável "bandeira").
- Como usar
continuepara pular uma volta (os números pares, um valor inválido). - Por que o
breaksai de um laço só, mesmo quando há um laço dentro de outro. - Os erros reais:
breakfora de laço e ocontinueque trava owhile.
Todos os programas foram compilados com o gcc 15 na máquina fictícia da Ana, na pasta ~/c, com o comando padrão do guia: gcc -std=c23 -Wall -Wextra arquivo.c -o programa.
A ideia: procurar as chaves e separar a roupa
Duas situações do dia a dia:
- Procurando as chaves nas gavetas, uma por uma. Achou na terceira? Você para de procurar: não abre a quarta, a quinta… Isso é o
break: sai do laço na hora. - Separando a roupa para lavar, peça por peça. Uma peça é de lã e não vai na máquina? Você a pula e passa para a próxima, mas continua separando as outras. Isso é o
continue: abandona só a volta atual.
| Palavra | O que faz | Para onde o programa vai |
|---|---|---|
break | Termina o laço inteiro | Para a primeira linha depois da } do laço |
continue | Termina só a volta atual | Para o teste da condição (no for, primeiro roda o passo) |
1. break: procurar e parar
A Ana quer o primeiro número, a partir de 50, que seja divisível por 7. Ela não sabe qual é, mas sabe que, ao achar, não precisa testar mais nada:
#include <stdio.h>
int main(void) {
for (int n = 50; n <= 100; n++) {
printf("Testando %d\n", n);
if (n % 7 == 0) {
printf("Achei: %d\n", n);
break;
}
}
printf("Fim da busca.\n");
return 0;
}
$ gcc -std=c23 -Wall -Wextra procurar.c -o procurar $ ./procurar Testando 50 Testando 51 Testando 52 Testando 53 Testando 54 Testando 55 Testando 56 Achei: 56 Fim da busca.
- for (int n = 50; n <= 100; n++)
- O laço poderia ir até 100 (51 voltas).
- n % 7 == 0
- "O resto da divisão por 7 é zero", ou seja,
né divisível por 7 (o%está em Operadores Aritméticos). - break;
- Sai do
forna hora. O passon++não roda, a condição não é testada de novo e o programa pula paraFim da busca..
Foram só 7 voltas em vez de 51. Repare que o break está dentro de um if, mas sai do laço: o break não liga para o if, ele procura o laço (ou switch) mais próximo em volta dele.
Missão: mude a busca para achar o primeiro número a partir de 100 que seja divisível por 13 (e aumente o fim do laço para 200). A saída deve terminar com Achei: 104.
#include <stdio.h>
int main(void) {
for (int n = 50; n <= 100; n++) {
printf("Testando %d\n", n);
if (n % 7 == 0) {
printf("Achei: %d\n", n);
break;
}
}
printf("Fim da busca.\n");
return 0;
}
#include <stdio.h>
int main(void) {
for (int n = 100; n <= 200; n++) {
printf("Testando %d\n", n);
if (n % 13 == 0) {
printf("Achei: %d\n", n);
break;
}
}
printf("Fim da busca.\n");
return 0;
}
2. while (1) com break: a saída no meio
Na aula do while, o programa que soma até o 0 precisava ler o número antes do laço e de novo no fim do corpo. Com um laço infinito de propósito e um break, a leitura aparece uma vez só, no lugar natural: no começo de cada volta.
#include <stdio.h>
int main(void) {
int numero = 0;
int soma = 0;
while (1) {
printf("Digite um número (0 para parar): ");
if (scanf("%d", &numero) != 1 || numero == 0) {
break;
}
soma += numero;
}
printf("Soma: %d\n", soma);
return 0;
}
$ gcc -std=c23 -Wall -Wextra soma_break.c -o soma_break $ ./soma_break Digite um número (0 para parar): 10 Digite um número (0 para parar): 25 Digite um número (0 para parar): 7 Digite um número (0 para parar): 0 Soma: 42
- while (1)
- Em C, qualquer número diferente de 0 é verdadeiro: a condição nunca fica falsa. No C23 também dá para escrever
while (true)C23, e outra forma clássica éfor (;;). - scanf(…) != 1 || numero == 0
- "A leitura falhou ou o número é 0". Qualquer um dos dois encerra a soma.
- break;
- A única saída do laço. Todo
while (1)precisa de pelo menos umbreakalcançável, senão é um laço infinito de verdade.
while (1) com break é ótimo quando a decisão de parar fica no meio da volta (depois de ler, antes de processar). Quando dá para escrever a condição no topo de forma clara, prefira o while (condição) comum: quem lê entende o laço sem procurar o break.
3. Por que o laço parou? A variável bandeira
Um laço com break pode terminar de dois jeitos: pelo break ou porque a condição ficou falsa. Muitas vezes você precisa saber qual foi. No caixa eletrônico, a Ana tem 3 tentativas para acertar a senha:
#include <stdio.h>
int main(void) {
int senha = 0;
int acertou = 0;
for (int tentativa = 1; tentativa <= 3; tentativa++) {
printf("Senha (tentativa %d de 3): ", tentativa);
if (scanf("%d", &senha) != 1) {
break;
}
if (senha == 1234) {
acertou = 1;
break;
}
printf("Senha errada.\n");
}
if (acertou) {
printf("Acesso liberado!\n");
} else {
printf("Cartão bloqueado.\n");
}
return 0;
}
$ gcc -std=c23 -Wall -Wextra senha.c -o senha $ ./senha Senha (tentativa 1 de 3): 1111 Senha errada. Senha (tentativa 2 de 3): 1234 Acesso liberado! $ ./senha Senha (tentativa 1 de 3): 1 Senha errada. Senha (tentativa 2 de 3): 2 Senha errada. Senha (tentativa 3 de 3): 3 Senha errada. Cartão bloqueado.
- int acertou = 0;
- Uma bandeira (em inglês, flag): uma variável que começa "abaixada" (0) e é "levantada" (1) quando algo acontece. Com C23 você pode usar
bool acertou = false;(veja Booleanos). - acertou = 1; break;
- Levanta a bandeira antes de sair. Depois do laço, ela conta a história.
- printf("Senha errada.\n");
- Só roda quando a senha não bateu: se bateu, o
breaksaiu antes de chegar aqui. - if (acertou)
- Depois do laço, a bandeira diz se saímos pelo
break(acertou) ou porque as 3 tentativas acabaram.
4. continue: pular uma volta
O continue abandona o resto do corpo só nesta volta e vai para a próxima. Para mostrar só os ímpares de 1 a 10, pule os pares:
#include <stdio.h>
int main(void) {
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue;
}
printf("%d ", i);
}
printf("\n");
return 0;
}
$ gcc -std=c23 -Wall -Wextra impares.c -o impares $ ./impares 1 3 5 7 9
- if (i % 2 == 0)
- "
ié par" (resto da divisão por 2 é zero). - continue;
- Pula o
printfdesta volta. Numfor, o programa vai para o passo (i++) e depois testa a condição, como numa volta normal.
Claro, aqui daria para usar i += 2 começando do 1. O continue brilha quando o "pular" depende de algo que só se sabe durante a volta, como o valor que a pessoa digitou. A Ana lança as 5 vendas do dia; um valor negativo foi erro de digitação e deve ser ignorado:
#include <stdio.h>
int main(void) {
int valor = 0;
int soma = 0;
for (int i = 1; i <= 5; i++) {
printf("Venda %d: ", i);
if (scanf("%d", &valor) != 1) {
break;
}
if (valor < 0) {
printf(" (valor negativo ignorado)\n");
continue;
}
soma += valor;
}
printf("Total das vendas: %d\n", soma);
return 0;
}
$ gcc -std=c23 -Wall -Wextra positivos.c -o positivos $ ./positivos Venda 1: 30 Venda 2: -5 (valor negativo ignorado) Venda 3: 20 Venda 4: 15 Venda 5: -1 (valor negativo ignorado) Total das vendas: 65
Os dois negativos não entraram na soma (30 + 20 + 15 = 65), mas o laço continuou até a venda 5. O mesmo programa usa os dois: break quando a leitura falha (não adianta continuar) e continue quando só aquele valor é ruim.
Missão: mude o programa para mostrar os números de 1 a 20, pulando os múltiplos de 3 (3, 6, 9…) com continue. A saída deve ser 1 2 4 5 7 8 10 11 13 14 16 17 19 20.
#include <stdio.h>
int main(void) {
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue;
}
printf("%d ", i);
}
printf("\n");
return 0;
}
#include <stdio.h>
int main(void) {
for (int i = 1; i <= 20; i++) {
if (i % 3 == 0) {
continue;
}
printf("%d ", i);
}
printf("\n");
return 0;
}
5. O break só sai de um laço
Quando há um laço dentro de outro (assunto da próxima aula, Laços Aninhados), o break sai só do laço mais de dentro, aquele que o envolve diretamente. O de fora continua:
#include <stdio.h>
int main(void) {
for (int linha = 1; linha <= 3; linha++) {
for (int coluna = 1; coluna <= 5; coluna++) {
if (coluna == 3) {
break;
}
printf("(%d,%d) ", linha, coluna);
}
printf("<- fim da linha %d\n", linha);
}
return 0;
}
$ gcc -std=c23 -Wall -Wextra umlaco.c -o umlaco $ ./umlaco (1,1) (1,2) <- fim da linha 1 (2,1) (2,2) <- fim da linha 2 (3,1) (3,2) <- fim da linha 3
Em cada linha, o break interrompeu as colunas na 3, mas o laço das linhas seguiu: as três linhas apareceram. Para sair dos dois laços de uma vez, use uma bandeira ou, em casos especiais, um goto; os dois jeitos estão em Laços Aninhados. O continue segue a mesma regra: ele pula a volta do laço mais de dentro.
break dentro de switch
O break também sai de um switch. Por isso, num menu com switch dentro de um laço (como o da aula do while), o break de cada case sai só do switch: o laço continua e o menu aparece de novo. Já o continue não tem nada a ver com switch: dentro dele, vale para o laço em volta.
Formas diferentes de escrever
O mesmo laço com e sem break
A busca do começo da aula poderia colocar o "achei" na própria condição, usando uma bandeira:
int achou = 0;
for (int n = 50; n <= 100 && !achou; n++) {
if (n % 7 == 0) {
printf("Achei: %d\n", n);
achou = 1;
}
}
Funciona, mas a condição ficou mais difícil de ler. Com break, a regra de parada fica bem onde a coisa acontece. Os dois estilos são corretos; use o que deixar o código mais claro.
continue ou if ao contrário?
Todo continue pode virar um if com a condição invertida:
for (int i = 1; i <= 10; i++) {
if (i % 2 != 0) {
printf("%d ", i);
}
}
Com um teste só, o if invertido é mais simples. O continue ganha quando há vários motivos para pular no começo da volta ("se for negativo, pula; se for maior que 1000, pula…"): cada um vira uma linha, e o código "bom" não fica enterrado dentro de vários if.
Quando dá errado
#include <stdio.h>
int main(void) {
int idade = 15;
if (idade < 18) {
printf("Menor de idade.\n");
break;
}
printf("Fim\n");
return 0;
}
$ gcc -std=c23 -Wall -Wextra foraloop.c -o foraloop
foraloop.c: In function ‘main’:
foraloop.c:7:9: error: break statement not within loop or switch
7 | break;
| ^~~~~
O que significa: "instrução break fora de um laço ou switch". O break não serve para sair de um if. O Clang do editor diz error: 'break' statement not in loop or switch statement.
Como consertar: se a ideia era parar o resto do if, use else (veja if e else). Se era encerrar o programa, use return 0; (dentro do main).
$ gcc -std=c23 -Wall -Wextra foraloop2.c -o foraloop2
foraloop2.c: In function ‘main’:
foraloop2.c:6:9: error: continue statement not within a loop
6 | continue;
| ^~~~~~~~
O que significa: "instrução continue fora de um laço". Mesmo caso: o continue estava num if sem laço em volta. Repare que a mensagem não cita o switch: o continue só existe para laços. No Clang: error: 'continue' statement not in loop statement.
continue trava o while
#include <stdio.h>
int main(void) {
int i = 1;
while (i <= 10) {
if (i % 2 == 0) {
continue;
}
printf("%d\n", i);
i++;
}
printf("Fim\n");
return 0;
}
$ gcc -std=c23 -Wall -Wextra continue_while.c -o continue_while $ timeout 3 ./continue_while 1 $ echo $? 124
O que aconteceu: mostrou 1, somou 1 (i vira 2) e travou. Com i valendo 2, o continue pula o resto do corpo, inclusive o i++. No while não existe "passo" separado: o i fica em 2 para sempre. Num for isso não acontece, porque o continue do for sempre roda o passo.
Como consertar: troque por um for (int i = 1; i <= 10; i++), ou faça o i++ antes do continue (por exemplo, logo no começo do corpo, ajustando o resto).
O que aconteceu: o break estava no laço de dentro e o de fora continuou rodando, como no exemplo umlaco.c. O compilador não avisa: é o comportamento normal do C.
Como consertar: use uma bandeira testada no laço de fora (ou um goto), como em Laços Aninhados.
Referência
| Forma | O que faz |
|---|---|
break; | Sai do laço (for, while, do while) ou switch mais próximo. Vai para a linha depois da }. |
continue; | Pula o resto da volta. No for, roda o passo e testa; no while/do while, vai direto ao teste. |
while (1) { … if (…) break; … } | Laço com a saída no meio. Também: for (;;) e, no C23, while (true). |
int achou = 0; … achou = 1; break; | Bandeira: diz depois do laço se ele parou pelo break. |
if (ruim) continue; | Ignorar um item e seguir com os outros. |
Exercícios
1. Sair do laço
Complete para o laço parar quando i chegar a 5:
2. Quantos números aparecem?
No laço do exercício 1, quantos números são mostrados?
3. Pular uma volta
Complete para não mostrar o número 3:
4. Há um for dentro de outro for, e um break no de dentro. O que acontece quando ele roda?
5. Por que while (i <= 10) { if (i % 2 == 0) continue; printf(…); i++; } trava?
6. O gcc deu error: break statement not within loop or switch. O que isso quer dizer?
Missão final: a senha com 3 tentativas
Missão: este programa lê as 3 tentativas, mas nunca libera o acesso. Quando a senha for 1234, mostre Acesso liberado na tentativa N! (com o número da tentativa) e saia do laço com break. A entrada já traz 1111, 4321 e 1234.
#include <stdio.h>
int main(void) {
int senha = 0;
for (int tentativa = 1; tentativa <= 3; tentativa++) {
printf("Senha (tentativa %d de 3): ", tentativa);
if (scanf("%d", &senha) != 1) {
break;
}
printf("Senha errada.\n");
}
return 0;
}
#include <stdio.h>
int main(void) {
int senha = 0;
for (int tentativa = 1; tentativa <= 3; tentativa++) {
printf("Senha (tentativa %d de 3): ", tentativa);
if (scanf("%d", &senha) != 1) {
break;
}
if (senha == 1234) {
printf("Acesso liberado na tentativa %d!\n", tentativa);
break;
}
printf("Senha errada.\n");
}
return 0;
}
Resumo
breaksai do laço (ouswitch) na hora; o programa segue depois da}.continuepula o resto da volta atual; nofor, o passo ainda roda.while (1)(oufor (;;), ouwhile (true)no C23) combreakserve quando a decisão de parar fica no meio da volta.- Uma bandeira (
int achou = 0;) conta, depois do laço, se ele parou pelobreak. - Os dois agem só sobre o laço mais de dentro.
continuenumwhilepode pular o passo e travar o laço;break/continuefora de laço é erro de compilação.