Universidade Federal de Minas Gerais
Instituto de Ciências Exatas
Departamento de Ciência da Computação

Algoritmos e Estruturas de Dados I

 

Nomes


Os nomes em C consistem de seqüências de caracteres iniciadas com letras. Os caracteres válidos são letras e dígitos e o sublinhado. Vários elementos da linguagem podem ter nomes. Os nomes podem ser definidos no escopo de elementos que também podem ter nomes.

No decorrer  da disciplina serão apresentados diversos espaços de nomes ou “escopos”.

Expressões


Uma expressão corresponde a um trecho de programa que calcula um certo valor e ainda pode produzir efeitos colaterais. As expressões podem ser utilizadas em vários pontos de um programa. O valor produzido por uma expressão tem associado a ele um certo tipo. As expressões mais simples correspondem a um literal (ou constante) ou uma variável e neste caso o tipo da expressão (ou tipo do valor retornado) corresponde ao tipo do literal ou ao tipo da variável. Quando as expressões envolvem operadores o tipo da expressão corresponde à uma combinação razoavelmente complexa de regras.

Exemplos:
Uma expressão pode ser usada no lado direito de um comando de atribuição: <variavel = <expressao>; O tipo da variável e o tipo da expressão têm que ser "compatíveis".
int a;
a=3; /* a expressão corresponde a uma constante representada por um literal */
double b;
b=3.1415;
double c=2.;
double d;
d=c; /* a expressão corresponde a uma variável */

Conforme dito acima uma expressão pode corresponder a um literal ou uma variável; uma expressão pode correponder ainda a uma chamada de função ou ainda a uma combinação de literais, variáveis e chamadas de funções; A combinação é feita através de "operadores". Existem ainda várias outras maneiras de definir expressões que serão vistas mais à frente na disciplina.

Uma chamada de funcão corresponde a um desvio do fluxo de execução para um trecho de código que irá calcular um valor e retorná-lo no ponto em que o fluxo de controle também retorna. Cada função tem 0, 1 ou mais argumentos (ou parâmetros) na sua definição. O compilador verifica se existe uma expressão para cada argumento do método invocado. A sintaxe para o conjunto de argumentos consiste em uma lista de expressões separadas por vírgula e delimitada por abre e fecha parênteses.

Exemplos de expressões correspondentes a chamadas de funções:
int a;
a=max(v1,v2); /* retorna v1 caso v1>=v2 ou retorna v2 caso v2>=v1 */
int b;
b=max(max(v1,v2), max(v3,v4));

Na expressão
max(max(v1,v2), max(v3,v4))
temos duas chamadas de uma função aninhadas dentro de uma outra chamada de função. A função max() definida para dois argumentos e retorna o maior destes argumentos.

(A linguagem C permite a definição de “macros” e max poderia ser uma macro:
 #define max(A, B) ((A) > (B) ? (A) : (B))

Quando o fluxo de controle atinge uma chamada de função (em algum momento o código fonte da função correspondente foi compilado e o código executável da função está disponível):

·        primeiro são avaliadas as expressões correspondentes aos argumentos da função,

·        é registrado ou salvo o ponto de retorno do fluxo de controle e feito o desvio para o código da função.

·        A execução normal de uma função termina com a função retornando o fluxo de controle para o ponto de retorno salvo juntamente com o retorno do valor calculado.

Na linguagem C as expressões correspondentes aos argumentos são calculadas da esquerda para a direita ou da direita para a esquerda?.

Descreva o valor impresso pelo seguinte trecho de programa:
int i=2;
int j=3;
printf(“%d %d\n”, i=3,i+j);

considere o seguinte trecho de programa

int i=3;
int ai[5];
ai[i]=i++;

Qual elemento do arranjo recebe a atribuição? ai[3] ou ai[4]?

ai[i]=++i;

Conforme já discutido, a sintaxe de um comando de atribuição corresponde a (i)uma variável seguida do (ii)símbolo "=" (denominado operador de atribuição), seguido de (iii)uma expressão; Quando o fluxo de controle atinge um comando de atribuição o valor da expressão é calculado e atribuído à variável, além disso o comando de atribuição tem associado a ele um valor que é exatamente o valor da expressão, é isso que permite aparecer em um programa expressões do tipo: v1=v2=3;

Operadores

Constantes, variáveis e chamadas de função podem ser combinadas através de operadores para construir expressões mais complexas. Alguns operadores são bastante intuitivos. Considere o seguinte trecho de programa:

int i=2;
int j=3;
int k;
k=i+j;
O operador "+" na expressão acima corresponde a uma soma de valores do tipo int.

Operadores aritméticos

+ - * / %

O operador  % corresponde ao resto da divisão entre os operandos correspondentes. A avaliação da expressão 11 % 3 resulta no valor 2,

Operadores de incremento e decremento

++ (incremento)  --  (decremento)

Exemplos:
int i=3;  /* é atribuido o valor 3 para a variável i,  a expressão vale 3*/
i++; /* é atribuido o valor 4 para a variável i,  a expressão vale 3 */
++i; /* é atribuido o valor 5 para a variável i, a expressão vale 5 */
i--; /* é atribuido o valor 4 para a variável i, a expressão vale 5 */
--i;  /* é atribuido o valor 3 para avariável i, a expressão vale 3 */

 

int a=0;
int b=0;
int c=a++ + b++;
printf(“%d”,c); // imprime 0

Operadores relacionais
== (igual) != (diferente) <  (menor) > (maior)   <= (menor ou igual)  >=  (maior ou igual)

 

Em alguns casos as expressões podem não ser intuitivas. Esperamos que X==X retorne verdadeiro e X!=X retorne falso, mas quando X corresponde a um double NaN, X!=X retorna verdadeiro!

Operadores Lógicos

& (e lógico)  && (e condicional) | (ou lógico)  ||  (ou condicional)  ! (negação lógica)

X & Y, X | Y -> a expressão X e a expressão Y são avaliadas
X && Y ->Se a expressão X for “false” então a expressão Y não é avaliada
X || Y ->Se a expressão X for “true” então a expressão Y não é avaliada

 

Operador condicional
?:  <exp1>?<exp2>:<exp3>

Exemplos

int i;
int v1=3, v2=4;
i=v1>v2?v1:v2; /* atribui o maior valor à variável i */
 

Operadores de atribuição
=  +=   -= *= /=  %= &=  !=  |= &&= ||=

Operadores de elencamento
()  - abre e fecha parênteses
 

Precedência

O trecho de programa abaixo deve ser evitado por um bom programador. Mas (infelizmente) tal trecho pode ser formulado. O que é impresso pelo trecho abaixo?

int i=2;
int j=(i=3)*i;
printf(“%d”, j);


Considere a tabela abaixo. Operadores na mesma linha têm igual precedência, operadores nas linhas superiores têm precedência sobre operadores nas linhas inferiores:
 
 
 

 

Existem ainda vários outros tipos de operadores que serão discutidos ao longo da disciplina. Alguns deles poderiam ser discutidos desde já, tais como os operadores de deslocamento (<<, >>, >>>), outros operadores serão discutidos em um contexto bem especializado

Um dos problemas que devem ser enfrentados com expressões envolvendo os tipos double e float são os erros de arredondamento