Uma proposição é qualquer sentença que pode ser valorada com o valor verdadeiro ou falso. Traduzindo essa definição para a linguagem C, uma proposição é qualquer sentença que pode ser valorada com um valor inteiro. Com o que aprendemos até agora, uma proposição
é uma relação, uma variável do tipo inteiro ou uma constante do tipo inteiro. Uma expressão
condicional ou lógica, ou ainda booleana é formada por uma ou mais proposições. Neste
último caso, relacionamos as proposições através de operadores lógicos. Os operadores lógicos da linguagem C utilizados como conectivos nas expressões lógicas são apresentados a seguir.
Operador Descrição
&& conjunção
|| disjunção
! negação
Duas proposições p e q podem ser combinadas pelo conectivo && para formar uma única proposição denominada conjunção das proposições originais: p && q e lemos “p e q”. O resultado da avaliação da conjunção de duas proposições é verdadeiro se e somente se ambas as proposições têm valor verdadeiro, como mostra a tabela a seguir.
p q p && q
1 1 1
1 0 0
0 1 0
0 0 0
Duas proposições p e q podem ser combinadas pelo conectivo || para formar uma única proposição denominada disjunção das proposições originais: p || q e lemos “p ou q”, com sentido de e/ou. O resultado da avaliação da disjunção de duas proposições é verdadeiro se pelo menos uma das proposições tem valor verdadeiro, como mostra a tabela a seguir.
p q p || q
1 1 1
1 0 1
0 1 1
0 0 0
Dada uma proposição p, uma outra proposição, chamada negação de p, pode ser obtida através da inserção do símbolo ! antes da proposição: !p e lemos “não p”. Se a proposição p tem valor verdadeiro, então !p tem valor falso e se p tem valor falso, então a proposição !p tem valor verdadeiro, como mostra a tabela a seguir.
p !p
1 0
0 1
Exemplos de expressões lógicas são mostrados a seguir. Inicialmente, suponha que decla- ramos as variáveis do tipo inteiro a seguir:
int a, b, c, x;
7.3 EXPRESSÕES LÓGICAS 67
a = 2; b = 3; c = 4; x = 1;
então as expressões lógicas a seguir
5 a !x a == 2 && a < b + c b + c >= 5 - a || b != 3 a + b > c || 2 * x == b && 4 < x
têm valores verdadeiro, verdadeiro, falso, verdadeiro, verdadeiro e falso, respectivamente.
Observe que avaliamos as expressões lógicas em uma ordem: primeiro avaliamos as ex- pressões aritméticas, depois as expressões relacionais e, por fim, as expressões lógicas em si. Por exemplo, a == 2 && a + x > b + c 2 == 2 && 3 > 3 + 4 2 == 2 && 3 > 7 1 && 0 1
A tabela abaixo ilustra a prioridade de todos os operadores aritméticos, relacionais e lógi- cos, unários e binários, vistos até aqui.
Operador Tipo Precedência
+ - unários 1 (máxima) * / % binários 2 + - binários 3 == != >= <= > < binários 4 ! unário 5 && binário 6 || binário 7 (mínima)
Observe que o operador de negação ! é um operador unário, ou seja, necessita de apenas um operando como argumento da operação. Os outros operadores lógicos são todos binários.
Lembre-se também que para modificar a precedência de alguma expressão é necessário o uso de parênteses, como já vimos nas expressões aritméticas.
Dessa forma, se considerarmos as mesmas variáveis e atribuições acima, a expressão lógica abaixo seria avaliada da seguinte forma:
x + c >= a + b || 2 * x + x < b && a > b + x 1 + 4 >= 2 + 3 || 2 * 1 + 1 < 3 && 2 > 3 + 1 5 >= 5 || 3 < 3 && 2 > 4 1 || 0 && 0 1 || 0 1
Observe que, como o operador lógico de conjunção && tem prioridade sobre o operador lógico de disjunção ||, o resultado da expressão acima é verdadeiro. Se tivéssemos realizado a disjunção primeiramente, como poderíamos intuitivamente supor devido ao posicionamento mais à esquerda do operador de disjunção, o resultado da expressão seria diferente.
Exercícios
Alguns exercícios desta aula ensinam um importante truque de programação que é, na ver- dade, o uso de uma variável que simula um tipo lógico e que indica que algo ocorreu durante a execução do programa. Essa variável é chamada de indicadora de passagem.
7.1 Dado p inteiro, verificar se p é primo.
Programa 7.1: Solução para o exercício7.1.
#include <stdio.h>
/* Recebe um inteiro positivo p e verifica se p é primo */ int main(void) { int p, divisor; printf("Informe um número: "); scanf("%d", &p); divisor = 2; while (divisor <= p/2) { if (p % divisor == 0) divisor = p; else divisor = divisor + 1; } if (divisor == p/2 + 1) printf("%d é primo\n", p); else
printf("%d não é primo\n", p); return 0;
7.3 EXPRESSÕES LÓGICAS 69
Programa 7.2: Solução para o exercício7.1usando uma variável indicadora de passagem.
#include <stdio.h>
/* Recebe um inteiro positivo p e verifica se p é primo */ int main(void)
{
int p, divisor, primo;
printf("Informe um número: "); scanf("%d", &p);
divisor = 2; primo = 1;
while (divisor <= p/2 && primo == 1) { if (p % divisor == 0) primo = 0; else divisor = divisor + 1; } if (primo == 1) printf("%d é primo\n", p); else
printf("%d não é primo\n", p); return 0;
}
Programa 7.3: Terceira solução para o exercício7.1.
#include <stdio.h>
/* Recebe um inteiro positivo p e verifica se p é primo */ int main(void)
{
int p, divisor, primo;
printf("Informe um número: "); scanf("%d", &p);
divisor = 2; primo = 1;
while (divisor <= p/2 && primo) { if (! (p % divisor)) primo = 0; else divisor = divisor + 1; } if (primo) printf("%d é primo\n", p); else
printf("%d não é primo", p); return 0;
7.2 Dado um número inteiro positivo n e uma seqüência de n números inteiros, verificar se a seqüência está em ordem crescente.
7.3 Dados um número inteiro n > 0 e um dígito d, com 0 6 d 6 9, determinar quantas vezes o dígito d ocorre no número n.
7.4 Dado um número inteiro positivo n, verificar se este número contém dois dígitos conse- cutivos iguais.
7.5 Dado um número inteiro positivo n, verificar se o primeiro e o último dígito deste número são iguais.
7.6 Dado um número inteiro positivo n e dois números naturais não nulos i e j, imprimir em ordem crescente os n primeiros naturais que são múltiplos de i ou de j ou de ambos. Exemplo:
Para n = 6, i = 2 e j = 3 a saída deverá ser 0, 2, 3, 4, 6, 8.
7.7 Dizemos que um número natural é triangular se é produto de três números naturais consecutivos.
Exemplo:
120 é triangular, pois 4 · 5 · 6 = 120. Dado n natural, verificar se n é triangular.
7.8 Dados dois números inteiros positivos, determinar o máximo divisor comum entre eles utilizando o algoritmo de Euclides.
Exemplo:
1 1 1 2
24 15 9 6 3 = mdc(24,15)
9 6 3 0
7.9 Dados dois números inteiros positivos a e b, representando a fração a/b, escreva um pro- grama que reduz a/b para uma fração irredutível.
Exemplo:
Se a entrada é 9/12 a saída tem de ser 3/4.
7.10 Dados a quantidade de dias de um mês e o dia da semana em que o mês começa, escreva um programa que imprima os dias do mês por semana, linha a linha. Considere o dia da semana 1 como domingo, 2 como segunda-feira, e assim por diante, até o dia 7 como sábado.
Exemplo:
Se a entrada é 31 e 3 então a saída deve ser
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
7.3 EXPRESSÕES LÓGICAS 71
7.11 Dados um número inteiro n e n seqüências de números inteiros, cada qual terminada por 0, determinar a soma dos números pares de cada seqüência.
7.12 Dados um número inteiro n > 0 e uma seqüência de n números inteiros positivos deter- minar o fatorial de cada número da seqüência.
7.13 Dados n números inteiros positivos, calcular a soma dos que são primos.
7.14 Dado um número inteiro positivo n, determinar todos os inteiros entre 1 e n que são comprimento de hipotenusa de um triângulo retângulo com catetos inteiros.
7.15 Dados dois naturais m e n, determinar, entre todos os pares de números naturais (x, y) tais que x 6 m e y 6 n, um par para o qual o valor da expressão xy − x2+ yseja máximo
e calcular também esse máximo.
7.16 Sabe-se que um número da forma n3é igual à soma de n números ímpares consecutivos.
Exemplo: 13 = 1 23 = 3 + 5 33 = 7 + 9 + 11 43 = 13 + 15 + 17 + 19 ...
Dado m, determine os ímpares consecutivos cuja soma é igual a n3 para n assumindo
valores de 1 a m.
7.17 Dado um número inteiro positivo, determine a sua decomposição em fatores primos, calculando também a multiplicidade de cada fator.
Exemplo:
Se n = 600 a saída deve ser fator 2 multiplicidade 3 fator 3 multiplicidade 1 fator 5 multiplicidade 2
AULA8
O
UTRAS ESTRUTURAS DE REPETIÇÃO
Duas outras estruturas de repetição estão disponibilizadas na linguagem C. Uma delas é a estrutura de repetição for, que pode ser vista como uma outra forma de apresentação da estrutura de repetição while. Essas estruturas possuem exepressões lógicas iniciais que con- trolam o fluxo de execução de seus respectivos blocos de instruções. Uma outra estrutura apresentada aqui é a estrutura repetição do-while, cuja a expressão lógica de controle é posi- cionada no final de seu bloco de instruções.
Esta aula é baseada nas referências [16,15].
8.1 Estrutura de repetição for
Retomando o programa6.1, isto é, o primeiro exemplo com uma estrutura de repetição na linguagem C que vimos até agora, vamos refazê-lo, desta vez usando a estrutura de repetição
for. Vejamos então o programa8.1a seguir.
Programa 8.1: Primeiro exemplo.
#include <stdio.h>
/* Mostra os 100 primeiros números inteiros positivos */ int main(void)
{
int numero;
for (numero = 1; numero <= 100; numero = numero + 1) printf("%d\n", numero);
printf("\n"); return 0; }
A novidade neste programa é a estrutura de repetição for. O formato geral da estrutura de repetição for é dado a seguir:
for (inicialização; condição; passo) { instrução1; . . . instruçãon; }
A estrutura de repetição for dispõe a inicialização, a condição e o passo todos na mesma linha de instrução. O funcionamento desta estrutura é dado da seguinte forma. Sempre que a palavra-chave for é encontrada, a inicialização é executada. Em seguida, uma condi- ção/expressão é avaliada: se o resultado da avaliação é verdadeiro, então o bloco de instruções delimitado pelas chaves é executado. Ao final da execução do bloco de instruções, opasso é executado e o processo todo se repete. Se, em algum momento, o resultado da avaliação for falso, o fluxo de execução do programa é desviado para a primeira instrução após o bloco de instruções da estrutura de repetição.
No ponto onde nos encontramos talvez seja um bom momento para entrarmos em contato com outros dois operadores aritméticos da linguagem C. Os operadores unários de incremento ++ e de decremento -- têm como função adicionar ou subtrair uma unidade do valor arma- zenado em seus operandos, respectivamente. De fato, nada mais é necessário compreender sobre esses operadores simples. No entanto, infelizmente, a compreensão das formas de uso desses operadores pode ser facilmente confundida. Isso porque, além de modificar os valores de seus operandos, ++ e -- podem ser usados como operadores prefixos e também como operadores posfixos. Por exemplo, o trecho de código abaixo:
int cont; cont = 1;
printf("cont vale %d\n", ++cont); printf("cont vale %d\n", cont);
imprime cont vale 2 e cont vale 2 em duas linhas consecutivas na saída. Por outro lado, o trecho de código abaixo:
int cont; cont = 1;
printf("cont vale %d\n", cont++); printf("cont vale %d\n", cont);
imprime cont vale 1 e cont vale 2 em duas linhas consecutivas na saída.
Para ajudar em nossa compreensão, podemos pensar que a expressão ++cont significa “incremente cont imediatamente” enquanto que a expressão cont++ significa “use agora o valor de cont e depois o incremente”. O “depois” nesse caso depende de algumas questões técnicas da linguagem C que ainda não podemos entender, mas seguramente a variável cont será incrementada antes da próxima instrução/sentença ser executada.
8.2 ESTRUTURA DE REPETIÇÃO do-while 75 O operador de decremento -- tem as mesmas propriedades do operador de incremento ++, que acabamos de descrever.
É importante observar que os operadores de incremento e decremento, se usados como operadores posfixos, têm maior prioridade que os operadores unários de constante positiva + e de troca de sinal -. Se, ao contrário, são usados como operadores prefixos, então os dois operadores têm a mesma prioridade dos operadores unários de constante positiva + e de troca de sinal -.
O programa8.2é uma outra versão do programa8.1, que soluciona o problema da soma dos 100 primeiros números inteiros positivos. Desta vez, o programa usa o operador de incremento na estrutura de repetição for.
Programa 8.2: Soma os 100 primeiros números inteiros positivos.
#include <stdio.h>
/* Mostra os 100 primeiros números inteiros positivos */ int main(void)
{
int numero, soma; soma = 0;
for (numero = 1; numero <= 100; ++numero) soma = soma + numero;
printf("A soma dos 100 primeiros inteiros é %d\n", soma); return 0;
}