From aefbfe7b16d9fb41a1fb77a87156e9d4842ee181 Mon Sep 17 00:00:00 2001 From: Blau Araujo Date: Sat, 22 Mar 2025 11:40:26 -0300 Subject: [PATCH] =?UTF-8?q?conte=C3=BAdo=20da=20aula=205?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.org | 1 + aulas/05-controle/README.org | 559 +++++++++++++++++++++++++++++++++++ 2 files changed, 560 insertions(+) create mode 100644 aulas/05-controle/README.org diff --git a/README.org b/README.org index 86395b0..9ee82be 100644 --- a/README.org +++ b/README.org @@ -24,3 +24,4 @@ qualquer distribuição. - 14.03.2025 [[./aulas/02-dados-e-instrucoes/README.org][Aula 2: Dados e instruções]] ([[https://youtu.be/2KsvRJjshQ0][vídeo]]) ([[./exercicios/02/README.org][exercícios]]) - 17.03.2025 [[./aulas/03-tipos-de-dados/README.org][Aula 3: Tipos de dados]] ([[https://youtu.be/iMiRzZCU7hE][vídeo]]) ([[./exercicios/03/README.org][exercícios]]) - 19.03.2025 [[./aulas/04-variaveis/README.org][Aula 4: Variaveis e ponteiros]] ([[https://youtu.be/i7RKtMgSSrM][vídeo]]) ([[./exercicios/04/README.org][exercícios]]) +- 21.03.2025 [[./aulas/05-controle/README.org][Aula 5: Estruturas de controle de fluxo]] ([[https://youtu.be/9dvDL7FbYKY][vídeo]]) ([[./exercicios/05/README.org][exercícios]]) diff --git a/aulas/05-controle/README.org b/aulas/05-controle/README.org new file mode 100644 index 0000000..3b03e17 --- /dev/null +++ b/aulas/05-controle/README.org @@ -0,0 +1,559 @@ +#+title: Curso Básico da Linguagem C +#+subtitle: Aula 5: Estruturas de controle de fluxo +#+author: Blau Araujo +#+startup: show2levels +#+options: toc:3 + +* Estruturas de controle de fluxo + +[[https://www.youtube.com/watch?v=9dvDL7FbYKY][Vídeo desta aula]] + +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. + +#+begin_quote +*Construtos*: são os elementos fundamentais da sintaxe e da semântica de uma +linguagem. +#+end_quote + +** 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 um =switch= ou de um /loop/. +- =continue=: Salta para a próxima iteração de um /loop/. +- =goto =: Salta para um rótulo definido como =rótulo:=. + +#+begin_quote +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/! +#+end_quote + +** 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. + +#+begin_quote +*Iterar*: da álgebra, o termo significa valer-se do resultado de uma equação, +obtido através de cálculos sucessivos. +#+end_quote + +*** Sintaxe + +#+begin_example +for (INICIALIZAÇÃO; CONDIÇÂO; ALTERAÇÃO) { + BLOCO DE INSTRUÇÕES... +} +#+end_example + +Quando houver apenas uma instrução... + +#+begin_example +for (INICIALIZAÇÂO; CONDIÇÃO; ALTERAÇÃO) INSTRUÇÃO; + +for (INICIALIZAÇÂO; CONDIÇÃO; ALTERAÇÃO) + INSTRUÇÃO; +#+end_example + +Loop =for= infinito... + +#+begin_example +for (;;) { + BLOCO DE INSTRUÇÕES... +} +#+end_example + +#+begin_quote +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, o =break=. +#+end_quote + +*** Exemplo do vídeo + +#+begin_src c +#include + +int main(void) { + + for (int i = 0; i < 10; i++) { + printf("%d - %d\n", i, i * 10); + } + + return 0; +} +#+end_src + +*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 estrutura =for=. +- O operação de pós incremento =++=, na terceira expressão, avalia =var= + e soma 1 ao seu valor. +- A variável =i= poderia ser manipulada de qualquer outra forma na terceira + expressão. + +*Compilando e executando...* + +#+begin_example +:~$ 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 +#+end_example + +** 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 + +#+begin_example +while (CONDIÇÃO) { + BLOCO DE INSTRUÇÕES... +} +#+end_example + +Quando houver apenas uma instrução... + +#+begin_example +while (CONDIÇÃO) INSTRUÇÃO; + +while (CONDIÇÃO) + INSTRUÇÃO; +#+end_example + +/Loop/ =while= infinito... + +#+begin_example +while (1) { + BLOCO DE INSTRUÇÕES... +} +#+end_example + +*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: + +#+begin_src c +int c; +while ((c = getchar()) != '\n' && c != EOF); +#+end_src + +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 + +#+begin_src c +#include + +int main(void) { + + int i = 0; + while (i < 10) { + printf("%d", i); + i += 2; + } + + return 0; +} +#+end_src + +*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ável =i=. + +*Compilando e executando...* + +#+begin_example +:~$ gcc exemplo.c +:~$ ./a.out +0 +2 +4 +6 +8 +#+end_example + +** 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 + +#+begin_example +do { + BLOCO DE INSTRUÇÕES... +} while (CONDIÇÃO); +#+end_example + +Quando houver apenas uma instrução... + +#+begin_example +do INSTRUÇÃO; +while (CONDIÇÃO); + +do + INSTRUÇÃO; +while (CONDIÇÃO); +#+end_example + +/Loop/ =do..while= infinito... + +#+begin_example +do { + BLOCO DE INSTRUÇÕES... +} while (1); +#+end_example + +*** Exemplo do vídeo + +#+begin_src c +#include + +int main(void) { + + int i = 10; + do + printf("%d", i); + i--; + while (i > 0); + + return 0; +} +#+end_src + +*Notas* + +- Ainda estamos reproduzindo o comportamento do =for=. +- A operação de pós decremento =--= avalia =var= antes de subtrair 1 + de seu valor. + +*Compilando e executando...* + +#+begin_example +:~$ gcc exemplo.c +:~$ ./a.out +10 +9 +8 +7 +6 +5 +4 +3 +2 +1 +#+end_example + +** 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 + +#+begin_example +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... +} +#+end_example + +Quando houver apenas uma instrução nos blocos de instruções... + +#+begin_example +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... +#+end_example + +*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 + +#+begin_src c +#include + +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; +} +#+end_src + +*Compilando e executando...* + +#+begin_example +:~$ 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 +#+end_example + +*** 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: + +#+begin_src c +#define elif else if +#+end_src + +Por exemplo: + +#+begin_src c +#include + +#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); + } + } +} +#+end_src + +*Compilando e executando...* + +#+begin_example +:~$ gcc -Wall fizzbuzz.c +:~$ ./a.out +1 +2 +Fizz +4 +Buzz +Fizz +7 +8 +Fizz +Buzz +11 +Fizz +13 +14 +FizzBuzz +#+end_example + +** 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=. + +#+begin_quote +*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. +#+end_quote + +*** Sintaxe + +#+begin_example +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... +} +#+end_example + +*Notas* + +- A expressão =CONTROLE= deve avaliar um tipo compatível com =int=. +- 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ão =CONTROLE=. + +*** Exemplo do vídeo + +#+begin_src c +#include + + +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; +} +#+end_src + +*Compilando e executando...* + +#+begin_example +:~$ 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 +#+end_example + +*** 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): + +#+begin_example +CONDIÇÃO ? EXPRESSÃO_SE_VERDADEIRO : EXPRESSÃO_SE_FALSO +#+end_example + +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 =:=). + +