.. | ||
README.org |
Curso Básico da Linguagem C
- Estruturas de controle de fluxo
Estruturas de controle de fluxo
Construtos da linguagem que alteram a ordem normal da execução do programa que, em princípio, seria linha a linha de cima para baixo.
Construtos: são os elementos fundamentais da sintaxe e da semântica de uma linguagem.
Controle de fluxo
A alteração do fluxo normal de execução pode ser produzida por estruturas e alguns construtos da linguagem C.
Estruturas de repetição
- Loop
for
- Loop
while
- Loop
do..while
Estruturas de decisão
- Estrutura
if..else if..else
- Estrutura
switch..case
Construtos de desvio incondicional
return
: Finaliza a execução de uma função e retorna um valor.break
: Interrompe a execução de umswitch
ou de um loop.continue
: Salta para a próxima iteração de um loop.goto <rótulo>
: Salta para um rótulo definido comorótulo:
.
O
goto
torna o código confuso e difícil de entender e manter, levando a um estilo conhecido como "código espaguete", o que deve ser evitado a todo custo, pois isso vai contra os conceitos que definem um código como estruturado!
O loop 'for'
O loop for
uma estrutura de repetição com sintaxe compacta que combina a
inicialização de uma variável, a condição de continuidade das repetições
e a atualização do valor associado à variável em uma expressão tripla,
possibilitando a repetição controlada de um bloco de código um número
definido de vezes.
Com o loop for
, as repetições são controladas pela iterações com o valor
associado a uma variável.
Iterar: da álgebra, o termo significa valer-se do resultado de uma equação, obtido através de cálculos sucessivos.
Sintaxe
for (INICIALIZAÇÃO; CONDIÇÂO; ALTERAÇÃO) { BLOCO DE INSTRUÇÕES... }
Quando houver apenas uma instrução…
for (INICIALIZAÇÂO; CONDIÇÃO; ALTERAÇÃO) INSTRUÇÃO; for (INICIALIZAÇÂO; CONDIÇÃO; ALTERAÇÃO) INSTRUÇÃO;
Loop for
infinito…
for (;;) { BLOCO DE INSTRUÇÕES... }
Um loop infinito pressupõe a definição de uma condição de parada no
BLOCO DE INSTRUÇÕES
e o uso de um construto de desvio incondicional, geralmente, obreak
.
Exemplo do vídeo
#include <stdio.h>
int main(void) {
for (int i = 0; i < 10; i++) {
printf("%d - %d\n", i, i * 10);
}
return 0;
}
Notas
- A declaração de uma variável
i
, na primeira expressão, faz com que ela seja visível apenas no bloco de instruções. - Ao término das repetições, a variável deixa de existir.
- A variável
i
também poderia ser declarada fora da estruturafor
. - O operação de pós incremento
<var>++
, na terceira expressão, avaliavar
e soma 1 ao seu valor. - A variável
i
poderia ser manipulada de qualquer outra forma na terceira expressão.
Compilando e executando…
:~$ gcc exemplo.c :~$ ./a.out 0 - 0 1 - 10 2 - 20 3 - 30 4 - 40 5 - 50 6 - 60 7 - 70 8 - 80 9 - 90
Loop 'while'
O loop while
repete a execução de um bloco de instruções enquanto a sua
expressão de controle continuar avaliando como verdadeira ou qualquer
valor diferente de 0
. Como a continuidade dos ciclos é condicionada
à verdade da expressão de controle, o loop while
pode ser classificado
como um loop condicional.
Sintaxe
while (CONDIÇÃO) { BLOCO DE INSTRUÇÕES... }
Quando houver apenas uma instrução…
while (CONDIÇÃO) INSTRUÇÃO; while (CONDIÇÃO) INSTRUÇÃO;
Loop while
infinito…
while (1) { BLOCO DE INSTRUÇÕES... }
IMPORTANTE!
Todas as estruturas de repetição podem ser usadas sem a definição de um
bloco de instruções ou apenas uma instrução, mas isso só faz sentido em
loops onde é possível avaliar condições através de uma expressão, como
é o caso dos loops while
e do..while
.
Por exemplo, este loop é muito utilizado para limpar o conteúdo do buffer de entrada após a digitação de uma entrada do usuário:
int c;
while ((c = getchar()) != '\n' && c != EOF);
Aqui, o objetivo é apenas ler os bytes restante no buffer de entrada,
o que pode ser feito na própria expressão de controle do while
.
Exemplo do vídeo
#include <stdio.h>
int main(void) {
int i = 0;
while (i < 10) {
printf("%d", i);
i += 2;
}
return 0;
}
Nota
Este exemplo reproduz com o loop while
o mesmo comportamento de um
loop for
, mas sem tornar a variável i
local ao bloco de instruções:
int i = 0;
- Inicialização da variável que será iterada.i < 10
- Condição de continuidade.i += 2;
- Alteração da variáveli
.
Compilando e executando…
:~$ gcc exemplo.c :~$ ./a.out 0 2 4 6 8
Loop 'do..while'
Enquanto o loop while
avalia sua expressão de controle antes de executar
o bloco de instruções, o loop do..while
tem que executar o bloco de instruções
pelo menos uma vez antes de avaliar a expressão de controle: fora isso,
os funcionamentos são idênticos.
Sintaxe
do { BLOCO DE INSTRUÇÕES... } while (CONDIÇÃO);
Quando houver apenas uma instrução…
do INSTRUÇÃO; while (CONDIÇÃO); do INSTRUÇÃO; while (CONDIÇÃO);
Loop do..while
infinito…
do { BLOCO DE INSTRUÇÕES... } while (1);
Exemplo do vídeo
#include <stdio.h>
int main(void) {
int i = 10;
do
printf("%d", i);
i--;
while (i > 0);
return 0;
}
Notas
- Ainda estamos reproduzindo o comportamento do
for
. - A operação de pós decremento
<var>--
avaliavar
antes de subtrair 1 de seu valor.
Compilando e executando…
:~$ gcc exemplo.c :~$ ./a.out 10 9 8 7 6 5 4 3 2 1
Estrutura de decisão 'if..else if..else'
A estrutura if..else if..else
(ou simplesmente if
) possibilita a execução
de um bloco de instruções caso a avaliação de um expressão resulte em
verdadeira ou em um valor diferente de 0
.
Sintaxe
if (CONDIÇÃO_1) { BLOCO EXECUTADO SE CONDIÇÃO_1 FOR VERDADEIRA... } else if (CONDIÇÃO_2) { BLOCO EXECUTADO SE CONDIÇÃO_2 FOR VERDADEIRA... } else if (CONDIÇÃO_N) { BLOCO EXECUTADO SE CONDIÇÃO_N FOR VERDADEIRA... } else { BLOCO EXECUTADO SE NENHUMA DAS CONDIÇÔES FOR VERDADEIRA... }
Quando houver apenas uma instrução nos blocos de instruções…
if (CONDIÇÃO_1) INSTRUÇÃO SE CONDIÇÃO_1 FOR VERDADEIRA... else if (CONDIÇÃO_2) INSTRUÇÃO SE CONDIÇÃO_2 FOR VERDADEIRA... else if (CONDIÇÃO_N) INSTRUÇÃO SE CONDIÇÃO_N FOR VERDADEIRA... else INSTRUÇÃO SE NENHUMA DAS CONDIÇÔES FOR VERDADEIRA...
Notas
- Apenas o bloco
if
é obrigatório. - É possível escrever quantos blocos
else if
forem necessários. - Só podemos escrever um bloco
else
, se necessário. - A estrutura
if
termina assim que um dos seus blocos é executado. - Eu prefiro me referir aos blocos de instruções como consequências.
Exemplo do vídeo
#include <stdio.h>
int main(void) {
for (int i = 0; i <= 20; i++) {
if (i % 2 == 0) {
printf("%d é par\n", i);
} else if (i % 15 == 0) {
printf("%d é ímpar e divisível por 3 e 5\n", i);
} else {
printf("%d é ímpar\n", i);
}
}
return 0;
}
Compilando e executando…
:~$ gcc exemplo.c :~$ ./a.out 0 é par 1 é ímpar 2 é par 3 é ímpar 4 é par 5 é ímpar 6 é par 7 é ímpar 8 é par 9 é ímpar 10 é par 11 é ímpar 12 é par 13 é ímpar 14 é par 15 é ímpar e divisível por 3 e 5 16 é par 17 é ímpar 18 é par 19 é ímpar 20 é par
Dica: 'else if' abreviado
A escrita do bloco else if
pode ser um pouco verbosa demais para quem
escreve muitos scripts em Bash, que usa elif
. Não existe uma abreviação
nativa em C, mas nós podemos implementá-la com uma macro:
#define elif else if
Por exemplo:
#include <stdio.h>
#define elif else if
int main(void) {
for (int i = 1; i <= 15; i++) {
if (!(i % 15)) {
puts("FizzBuzz");
} elif (!(i % 3)) {
puts("Fizz");
} elif (!(i % 5)) {
puts("Buzz");
} else {
printf("%d\n", i);
}
}
}
Compilando e executando…
:~$ gcc -Wall fizzbuzz.c :~$ ./a.out 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz
Estrutura 'switch..case'
A estrutura switch..case
possibilita selecionar a execução de um ou mais
blocos de instruções diferentes com base na correspondência entre o valor de
uma expressão e os valores especificados nas cláusulas case
.
Cláusulas: seções de uma estrutura sintática que definem condições ou comportamentos específicos dentro da totalidade do comando de que fazem parte.
Sintaxe
switch (CONTROLE) { case CONST_1: BLOCO DE INSTRUÇÕES... [break;] case CONST_2: BLOCO DE INSTRUÇÕES... [break;] case CONST_N: BLOCO DE INSTRUÇÕES... [break;] default: BLOCO DE INSTRUÇÕES... }
Notas
- A expressão
CONTROLE
deve avaliar um tipo compatível comint
. - Os valores nas cláusulas
case
devem ser expressões constantes ou expressões ou valores que possam ser resolvidos em tempo de compilação. - Sejam quais forem os valores nas cláusulas
case
, eles devem ser do mesmo tipo da expressãoCONTROLE
.
Exemplo do vídeo
#include <stdio.h>
int main(void) {
int flag;
for (int i = 1; i <= 20; i++) {
flag = 0;
flag += (i % 2) ? 0 : 1;
flag += (i % 3) ? 0 : 2;
switch (flag) {
case 1:
printf("%d é divisível por 2\n", i);
break;
case 2:
printf("%d é divisível por 3\n", i);
break;
case 3:
printf("%d é divisível por 2 e 3\n", i);
break;
default:
printf("%d\n", i);
}
}
return 0;
}
Compilando e executando…
:~$ gcc exemplo.c :~$ ./a.out 1 2 é divisível por 2 3 é divisível por 3 4 é divisível por 2 5 6 é divisível por 2 e 3 7 8 é divisível por 2 9 é divisível por 3 10 é divisível por 2 11 12 é divisível por 2 e 3 13 14 é divisível por 2 15 é divisível por 3 16 é divisível por 2 17 18 é divisível por 2 e 3 19 20 é divisível por 2
Bônus: expressão condicional (ternária)
A linguagem C implementa a avaliação condicional de expressões na forma de uma expressão ternária (uma expressão com 3 termos):
CONDIÇÃO ? EXPRESSÃO_SE_VERDADEIRO : EXPRESSÃO_SE_FALSO
Aqui, se a expressão CONDIÇÃO
avaliar verdadeiro ou um valor diferente de
0
, o valor de toda a expressão ternária será o valor avaliado no seu segundo
termo (depois de ?
); se avaliar falso ou igual a 0
, a expressão ternária
terá o valor avaliado no seu terceiro termo (depois de :
).