Aula 3 – Comandos de Controle do Programa

Verdadeiro e Falso em C

Uma expressão condicional chega a um valor verdadeiro ou falso. Em C, diferentemente de muitas linguagens, qualquer coisa diferente de 0, incluindo números negativos, é verdadeiro. Um valor falso é 0.

Comandos de seleção

C suporta dois tipos de comandos de seleção: if e switch. Também temos o operador ternário (?) que é uma alternativa ao if-else.

if

Sentença: if (expressão) comando;

else comando;

Comando pode ser um único comando ou um bloco de comandos. O uso da cláusula else é opcional. Se a expressão é verdadeira (qualquer coisa diferente de 0), o comando ou bloco de comandos depois do if é executado. Do contrário, se existir, será executado o comando ou bloco de comandos depois do else.

if (se), else (senão). Logo apenas um deles é executado.

A expressão deve sempre retornar um valor escalar, ou seja, um inteiro, caractere ou um tipo de ponto flutuante.

Vamos à um exemplo:

unsigned char age = 75;
if (age >= 60) {
    printf("Diga oi, e dê preferência\n");
} else {
    printf("Diga oi\n");
}

O programa acima, lê-se: Defina uma variável do tipo char sem sinal (0 à 255) com nome age e armazene o valor 75 nela. Se o valor da variável age for maior que, ou igual, à 60, então imprima na tela “Diga oi, e dê preferência” e vá para a próxima linha. Senão imprima na tela “Diga oi” e vá para a próxima linha.

O comando else sempre está associado a um comando if, e sempre o mais próximo. Podemos também aninhar vários ifs, por exemplo:

if (1 == 1) {
    if (1 == 2) {

    }
    if (2 == 3) {

    } else {

    }
}

Para facilitar a legibilidade sempre identamos o código, assim fica fácil saber que o else está ligado a terceira condição (2 == 3).

Dica de boa prática de programação. O código abaixo foi mal escrito, pois é redundante e potenciamente ineficiente:

if (b != 0) printf (“%d\n”, b);

pois qualquer valor diferente de 0, retorna verdadeiro, então o correto seria:

if (b) printf(“%d\n”, b);

O ? Alternativo (operador ternário)

Podemos usar o operador ternário para substituir comandos if-else:

if (condição )

expressão

else

expressão

Porém as expressões devem ser simples, nunca um comando em C. O operador ternário é chamado desta maneira pos possui 3 operandos:

Exp1 ? Exp2 : Exp3

A expressão Exp1 é avaliada, se for verdadeira, então avalia a Exp2 e retorna seu valor. Do contrário, se a Exp1 for falsa (senão), avalia a Exp3 e retorna seu valor. Por exemplo:

x = 10;
y = x > 9 ? 100 : 200;

O fragmento de código acima, lê-se: x recebe 10. Se x for maior que nove então y recebe 100, senão y recebe 200.

switch

C, assim como muitas outras linguagens, tem um comando interno de seleção múltipla, o switch. Sua forma geral é:


switch (expressão) {

case constante1:

sequência de comandos

break;

case constante2:

sequência de comandos

break;

.

.

default:

sequência de comandos

}

A expressão é comparada com a sequência de constantes, se uma delas considir, então executa a sequência de comandos em seguida, até que um comando break for encontrado. Se nenhuma constante for igual ao valor da expressão, a sequência de códigos em default é executada.

O comando break é um dos comandos de desvio em C. Ele termina a execução de um laço.
Sobre o switch precisamos saber 3 coisas:

Ele difere-se do comando if, pois só pode testar igualdade e não avaliar expressões lógicas ou relacionais.
Duas constantes case no mesmo switch não podem ter valores idênticos.
Se constantes de caractere são usadas em um comando switch, elas são automaticamente convertidas para seus valores inteiros.
O uso do switch se dá bastante em processamento de entradas via teclado ou menus. Nada impede você de usar vários if – else para fazer a mesma coisa, porém a legibilidade do código muda muito. Recomendo o uso do switch sempre que possível.

O uso do comando break não é obrigatório, neste caso o programa irá continuar a sequência de testes, veja o exemplo:

void verifica_entrada(int i) {
    int flag;
    flag -= 1;
    switch (i) {
        case 1:
        case 2:
        case 3:
            flag = 0;
            break;
        case 4:
            flag = 1;
        default:
            procces(flag);
    }
}

Podemos ler o switch acima, como: “Analise o valor da variável i. Se for 1, 2 ou 3, então defina o valor da variável flag para 0 e saia do laço. Se o valor for igual 4 defina o valor de flag para 1 e continue o laço. Se não sair do laço, execute a função process passando como argumento a variável flag”.Por se tratar de uma sequência de códigos e não um bloco de códigos, não podemos declarar uma variável dentro de um case, o fragmento de código abaixo está errado:

// Isto está errado
switch ( c ){
case 1:
int t;
.
.

Mas poderíamos adicionar uma variáve local, como mostrado a seguir:

// Isto está correto
switch ( c ) {
int t;
case 1:
.
.

Agora, nada impede você de criar um bloco de códigos e dentro dele definir variáveis:

// Isto está correto
switch ( c ) {
case 1:
if (1) { // Sempre verdadeiro, usado para criar um bloco
int t;
}
.
.

Comandos de Iteração

Comandos de iteração permitem que um conjunto de instruções seja executado até que ocorra uma certa condição.

O laço for

Forma geral:

for (inicialização; condição; incremento) comando;

Ele permite muitas variações, mas no geral, a inicialização é um comando de atribuição usado para colocar um valor na variável de controle do laço. A condição é uma expressão que determina quando o laço acaba. Por fim o incremento define como a variável de controle do laço varia cada vez que o laço é repetido. As trê seções principais devem ser separadas por ponto-e-vírgula e podem ser omitidas.
O programa abaixo imprime na tela, números de 1 a 100:


#include <stdio.h>

main() {
    int x;
    for (x = 1; x <= 100; x++) printf("%d ", x);
}

o laço for, lê-se: “Para x igual a 1, x menor que ou igual a 100, x++” ou
“x recebe 1, enquanto x for menor que ou igual a 100, incrementa x e executa”

Nos laços for, o teste condicional sempre é executado no topo do laço. Ou seja, o código dentro do laço não será executado se todas as condições forem falsas. Por exemplo:

x = 10;
for ( y = 10; y != x; ++y) printf( "%d", y);
printf( "%d", y);

O laço nunca executará, pois logo de início x e y são iguais, então nem o comando dentro do laço, nem o incrementador (++y) serão executados. Neste caso o programa imprimirá somente uma vez o valor de y.

O laço for permite diversas variações. Podemos usar por exemplo, duas variáveis para o controle, através do uso do operador vírgula (faça isso e isso), por exemplo:


for (x = 0, y = 0; x+y < 10; ++x){
y = getchar();
// Subtrai o código ASCII do caractere 0 (48) de y
y = y - '0';
.
.
}

Lembrando: Cada uma das trê seções pode ter qualquer expressão válida em C. Por exemplo:

#include <stdio.h>
// Assinaturas de métodos
int sqrnum(int num);
int readnum(void);
int prompt(void);

main() {
    int t;
    for (prompt(); t = readnum(); prompt())
        sqrnum(t);
}

prompt(void) {
    printf("entre um número : ");
    return 0;
}

readnum(void) {
    int t;
    scanf(" % d", &t);
    return t;
}

sqrnum(int num) {
    printf(" % d\n", num * num);
    return num*num;
}

Muitas vezes a inicialização da variável é feita fora do laço, por alguma função específica, por exemplo:

// Lê uma string para s
gets(s);
// x conterá o comprimento da string
if (*s) x = strlen(s);
for (; x < 10;) {
    printf(" % d", x);
    ++x;
}

A sessão de inicialização foi deixada em branco e x é inicializado antes que o laço comece a ser executado.

O laço Infinito (looping infinito)

O for muitas vezes é utilizado para laços infinitos, por exemplo:

for ( ; ; ) printf ( “Esse laço será executado para sempre.\n”);

Porém, podemos usar o break dentro de qualquer laço parar provocar um término imediato:


ch = '\0';
for ( ; ; ){
// Obtém um caractere
ch = getchar();
// Se for igual ao 'A', sai do laço
if (ch == 'A') break;
}
printf("Você digitou um A");

}

Laços for sem Corpos

Um programa de banco de dados, por exemplo, reconhece o comando “show”, mas não reconhece o comando “ show”. O laço abaixo, remove os primeiros espaços da stream apontada por ptr:

for ( ; *str==’ ‘; str++);

Podemos também criar um laço de atraso de tempo:

for ( t = 0; t < ALBUM_VALOR; t++);

O laço while

Forma geral:

while(condição) comando;

A condição pode ser qualquer expressão e verdadeiro é valor não-zero. O comando pode ser vazio, um comando simples, ou um bloco de comandos. O programa abaixo é executado até que o usuário digite A:

wait_for_char(void)
{
	char ch;
	// Inicializa ch como nulo
	ch = '\0';
	/** Testa ch e lê do teclado. Cada vez que o usuário pressiona a tecla, executa a
         * verificação e caso não seja ‘A’, continua a executar o laço
         */
	while (ch != 'A')
            ch = getchar();
	return ch;
}

Assim como os laços for, os laços while executam a verificação no início, o que significa que o código dentro do laço pode não ser executado. Não é necessário haver comandos no corpo do laço while, por exemplo:

while((ch = getchar()) != ‘A’);

A linha acima fará com que o programa não continue enquanto o usuário não pressionar a tecla A.

O laço do-while

Ao contrário dos laços for e while, o laço do-while testa a condição no final do laço. Isso significa que ele sempre será executado ao menos uma vez.

Forma geral:

do{ comando; } while(condição);

O laço abaixo irá ler números do teclado até que encontre um valor menor ou igual a 100. do

{
    scanf("%d", &num);

}
while (num > 100);

Apesar de não ser necessário as chaves, quando apenas um comando, é interessante usá-las para facilitar a legibilidade do código. Provavelmente o uso mais comum do laço do-while é quando o usuário entra com uma resposta e ela precisa ser verificada, se errada, o laço é executado novamente, se certa, então encerra o laço e segue a execução do programa.

Exemplo:

void menu(void) {
    char ch;
    printf(" 1. Verificar Ortografia\n");
    printf(" 2. Corrigir Erros de Ortografia\n");
    do {
        ch = getchar();
        switch (ch) {
            case '1':
                check_spelling();
                break;
            case '2':
                correct_errors();
                break;
        }
    } while (ch! = '1' && ch != '2');
}

Comandos de Desvios

C tem quatro comandos que realizam um desvio incondicional: return, goto, break e continue. return e goto podem ser utilizados em qualquer local do programa. Já break e continue são usados em laços.

O comando return

É usado para retornar de uma função. Ele é um comando de desvio, pois faz com que a execução retorne (salte de volta) ao ponto em que a chamada da função foi feita.

Forma geral:
return expressão;

Apesar da expressão não ser obrigatória, é interessante usá-la, senão o retorno será lixo para a maioria dos compiladores. Uma função declarada como void, não pode ter nenhum comando return.

O comando goto

Existe uma grande preocupação com o uso do goto, em relação a deixar o programa ilegível. Uma vez que C tenha os controles break e continue, é pouco provável que você precise do goto.

Forma geral:

goto rótulo;
.
.
label:

Onde rótulo é qualquer rótulo válido existente antes ou depois do goto. Por exemplo:


x = 1;
loop1:
x++;
if (x < 100) goto loop1;

O código acima irá incrementar x até que seja igual a 100, e então sair do laço.

O comando break

Ele tem dois usos, no case de um switch ou para terminar imediatamente um laço. Por exemplo:

#include <stdio.h>

void main(void) {
    int t;
    for (t = 0; t < 100; t++) {
        printf("%d ", t);
        if (t == 10) break;
    }
}

O programa acima escreve na tela os números de 1 à 10. O laço termina, pois o break provoca uma saída imediata, desrespeitando o teste condicional t < 100.
Ele gera a saída apenas do laço mais interno, por exemplo:

</pre>
for (t = 0; t < 100; ++t) {
    count = 1;
    for (;;) {
        printf("%d ", count);
        count++;
        if (count == 10) break;
    }
}

O programa acima escreve na tela, números de 1 à 10, 100 vezes.

A função exit()

Esta função provoca o término imediato do programa inteiro.

Forma geral:

void exit(int código_de_retorno);

O valor de código_de_retorno é retornado ao processo chamador, normalmente o sistema operacional. Zero é geralmente usado como um código de retorno que indica que o programa acabou normalmente. Outros argumentos são usados para indicar algum tipo de erro.

Em um jogo, por exemplo, ele poderia verificar se a placa gráfica é colorida, do contrário não iniciaria:


main()
{
     if (!color_car()) exit(1);
     play();
}

O comando continue

Muito semelhante ao break, porém ele apenas faz com que uma iteração de um laço seja cancelada. O programa abaixo conta o número de espaços contidas em uma string inserida pelo usuário:

#include <stdio.h>

main() {
    char s[80], *str;
    int space;
    printf("digite uma string : ");
    gets(s);
    str = s;
    for (space = 0; *str; str++) {
        if (*str != ' ') continue;
        space++;
    }
    printf(" % d espaços\n", space);
}

Cada caractere é testado, se não for o espaço, o continue é chamado, fazendo com que o space++ não seja executado.

Comandos de Expressões

Um comando de expressão é qualquer expressão válida em C, seguida por um ponto-e-vírgula. Exemplos:

func(); // Uma chamada a uma função
a = b+c; // Um comando de atribuição
b + f(); // Um comando válido, porém não faz nada
; // Um comando vazio, também conhecido como comando nulo

Blocos de Comandos

São vários comandos juntos (logicamente conectados) que são tratados como uma unidade. Um bloco começa com { e termina com }. Podemos por blocos de comandos em qualquer lugar queseja possível a colocação de outro comando, por exemplo:

#include <stdio.h>

void main(void) {
    int i;
    { // Um bloco de comandos
        i = 120;
        printf(" % d", i);
    }
}

Minha reflexão

C é viciante, só continue a participar das aulas, se tiver certeza de que é isto que quer para sua vida.

Leave a Reply

%d