Você está na página 1de 24

FACULDADE ANHANGUERA DE CAMPINAS UNIDADE 2

CINCIA DA COMPUTAO
ESTRUTURAS DE DADOS

AULA 2
REVISO DE LINGUAGEM C
1 - ESTRUTURAS PRIMITIVAS (TIPOS DE DADOS)
So os tipos de dados ou elementos primitivos que sobre os quais so construdas outras
mais complexas. A seguir esto os tipos bsicos implementados na maioria das linguagens de
programao.
Inteiro ou integer que so os tipos de dados do conjunto de inteiros representados pelos
nmeros naturais 1, 2, 3, ... , n+1. Sobre esta classe de dados podem ser realizadas as operaes
(+ , - , / , * , mod). O mod e o resto de uma diviso.
Real (float, double) - So os nmeros do conjunto dos reais ou fracionrios representados
por 0.1, 1.2, 3.14, 12.00. Sobre esta classe de dados podemos realizar as seguintes operaes e
resultando valores fracionrios (+ , - , * , / ).
Logical (boolean) - So tipos de dados que assumem somente dois valores lgicos (V, F),
Verdadeiro ou Falso. Sobre esta classe de dados podemos realizar somente as operaes lgicas
que so (e, ou, no).
Caracter (char) - So tipos de dados que representam valores literais que pode ser uma
letra ou um nmero ou um smbolo qualquer. Esta classe de dados suporta operaes de
concatenao, substring, tamanho.
Para armazenar valores inteiros, a linguagem C oferece alguns tipos bsicos, tais como:
char, short int, long int. Estes tipos diferem entre si pelo espao de memria utilizado e
consequentemente pelo intervalo de valores que podem representar.
O tipo char, por exemplo, ocupa 1 byte, podendo representar 28 = 256 valores distintos.
Os tipos short int e long int podem ser referenciados simplesmente com short e long,
respectivamente. O tipo int transformado para o tipo inteiro natural da mquina.
O tipo char um literal e usado para representar cdigos de caracteres, podendo ser
convertido para inteiro se for um literal de 0 a 9. Para mais detalhes sobre converso (cast) de
tipos de dados, consultar a bibliografia sobre linguagem C.
Abaixo apresentamos uma tabela contendo os detalhes sobre os tipos primitivos usados na
linguagem C. O tipo boolean ou lgico no existe na linguagem C. Esta linguagem utiliza os
valores inteiros 0 para falso e qualquer outro valor para verdadeiro.
Tabela 1.1 - Faixa de valores para os tipos primitivos
Nome

tamanho em bits

char

int

16

fIoat

32

long int

32

double

64

faixa de valores
-128 a 127
-32.768 a 32.767
10-38 a 1038
-2.147.483.648 a 2.147.483.647
10-308 a 10308

Pgina 1

2 - VARIVEIS
Variveis so identificadores de dados que podem assumir vrios valores, como o prprio
nome j diz. A cada momento de execuo de um algoritmo, uma varivel pode estar com um
valor diferente.
Uma varivel representa um espao na memria do computador para armazenar um dado
qualquer. Na linguagem C, todas as variveis devem ser explicitamente declaradas. Na
declarao de uma varivel, obrigatoriamente, devem ser especificados seu tipo e seu nome. O
nome da varivel serve de referncia (endereamento relativo) ao dado armazenado no espao
de memria e o tipo do dado determina a natureza do dado que ser armazenado.
Ao utilizarmos uma linguagem como C, devemos declarar variveis seguindo a sintaxe desta
linguagem. A declarao de uma varivel reserva um espao na memria para armazenar um
dado do tipo da varivel e associa o nome da varivel a este espao de memria.
Por exemplo, nas declaraes abaixo, a e b so variveis do tipo inteiro e x uma varivel
do tipo float.
int a;
int b; float x;
Atribuies de valores s variveis podem ser diretamente ou por meio de clculo ou leitura
como mostraremos logo a seguir.
a=5;
b=4;
x = 4.5;
ou ainda;
a = b + 1;
A linguagem C permite que variveis de mesmo. tipo sejam declaradas juntas. Assim, as
duas primeiras declaraes acima poderiam ser substitudas por:
int a, b; /* -- declara duas variveis do tipo int -- */
Uma vez declarada a varivel, podemos armazenar valores nos respectivos espaos de
memria. Estes valores devem ter o mesmo tipo da varivel, conforme ilustrado acima. Em C, as
variveis podem ser inicializadas na decLarao. Podemos, por exemplo, escrever:
int a;
a=4;
/* -- a varivel armazenar o valor 4 ----*/
int a = 5, b = 10; /* declara e inicializa as variveis a e b */
float c = 5.3; /* -- atribui o valor 5.3 a varivel c --*/
Podemos usar tambm valores constantes. Quando escrevemos a atribuio seguinte
a=b+123, sendo a e b variveis supostamente j declaradas, reserva-se um espao para a
armazenar a constante 123. No caso, a constante do tipo inteiro, ento um espao de dois bytes
(em geral) reservado e o valor 123 armazenado nele.
A diferena bsica em relao s variveis, como os nomes dizem (variveis e constantes),
que o valor armazenado numa rea de constante no pode ser alterado.
As constantes tambm podem ser do tipo real. Uma constante real deve ser escrita com um
ponto decimal ou valor de expoente. Sem nenhum sufixo, uma constante real do tipo double. Se
Pgina 2

quisermos uma constante real do tipo float, devemos, a rigor, acrescentar o sufixo F ou f. Alguns
exemplos de constantes reais so:
12.45 - real do tipo double;
1245e-2 - Real do tipo double;
12.45F - real do tipo float;
Alguns compiladores exibem uma advertncia quando encontram o trecho de cdigo
seguinte.
float x;
x = 12.45;
O cdigo, a rigor, armazena um valor double (12.45) numa varivel do tipo float.
Desde que a constante seja representvel dentro de um float, no precisamos nos
preocupar com este tipo de advertncia.
Um dos erros comuns em programas de computador o uso de variveis cujos valores
ainda esto indefinidos. Por exemplo, o trecho de cdigo abaixo est errado, pois o valor
armazenado na varivel b est indefinido e tentamos us-Io na atribuio de c. Assim, a varivel b
tem "lixo" ou resqucio de dados na memria, pois a linguagem C no inicializa variveis ao serem
declaradas.
int a, b, c;
a=2;
c = a + b; /* ERRO: b tem "lixo" */
Alguns destes erros so bvios e o compilador capaz de nos reportar uma advertncia. No
entanto, muitas vezes o uso de uma varivel no definida fica difcil de ser identificado no cdigo.
Repetimos que um erro comum em programas e uma razo para alguns programas funcionarem
na parte da manh e no funcionarem na parte da tarde (ou funcionarem durante o
desenvolvimento e no funcionarem quando entram em produo). Poder funcionar uma vez e
no funcionar outra que, apesar de indefinido, o valor da varivel existe. No nosso caso acima,
pode acontecer que o valor armazenado na memria ocupada por b seja 0, fazendo com que o
programa funcione. Pode acontecer da varivel ter o valor -354332 e o programa no funcionar.
3 - OPERADORES
Os operadores so instrues que realizam transformaes e comparaes dos dados ou
operandos e podem ser divididos em trs grupos como descrito abaixo: A linguagem C oferece
uma gama variada de operadores, entre binrios e unrios. Os operadores bsicos so
apresentados a seguir.
3.1 - Operadores Aritmticos e Associatividades
Os operadores aritmticos binrios so: +, -, * , / e o operador mdulo %. A operao feita
na preciso dos operandos. Assim, a expresso 5/2 resulta no valor 2, pois a operao de diviso
feita em preciso inteira, j que os dois operandos (5 e 2) so constantes inteiras. A diviso de
inteiros trunca a parte fracionria, pois o valor resultante sempre do mesmo tipo da expresso.
Consequentemente, a expresso 5.0 / 2.0 resulta no valor real 2.5, pois a operao feita na
preciso real (double, no caso).
O operador mdulo, %, no se aplica a valores reais, seus operandos devem ser do tipo
inteiro. Este operador produz o resto da diviso do primeiro pelo segundo operando. Como
exemplo de aplicao deste operador, podemos citar o caso em que desejamos saber se o valor
armazenado numa determinada varivel inteira x par ou mpar. Para tanto, basta analisar o

Pgina 3

resultado da aplicao do operador %, aplicado varivel e ao valor dois, x % 2, se resultado for


zero.
Um nmero dito par se (x % 2) for igual a zero e mpar, caso contrrio. Os operadores *, /
e % tm precedncia maior que os operadores + e -.
Operadores com mesma precedncia so avaliados da esquerda para a direita.
Assim, na expresso: a + b * c / d executa-se primeiro a multiplicao, seguida da diviso,
seguida da soma. Podemos utilizar parnteses para alterar a ordem de avaliao de uma
expresso. Assim, se quisermos avaliar a soma primeiro, podemos escrever: (a + b) * c / d.
A linguagem C tambm permite utilizar os chamados operadores de atribuio compostos.
Comandos do tipo: i = i + 2; em que a varivel esquerda do sinal de atribuio tambm aparece
direita, podem ser escritas de forma mais compacta: i += 2; usando o operador de atribuio
composto +=. Analogamente, existem, entre outros, os operadores de atribuio: -=, *=, /=, %=.
De forma geral, comandos do tipo: var op = expr; so equivalentes a: var = var op (expr);
Salientamos a presena dos parnteses em torno de expr. Assim: x *= y + 1; equivale a x=x*(y+1)
e no a x = x * y + 1.
H dois outros operadores no convencionais, que so os de incremento e decremento que
servem para incrementar e decrementar uma unidade nos valores armazenados nas variveis.
Assim, se n uma varivel que armazena um valor, o comando: n++; incrementa em uma unidade
o valor de n. O aspecto no usual que ++ e -- podem ser usados tanto como operadores
prefixados (antes da varivel, como em ++n) ou ps-fixados (aps a varivel, como em n++). Em
ambos os casos, a varivel n incrementada. Porm, a expresso ++n incrementa n antes de
usar seu valor, enquanto n++ incrementa n aps seu valor ser usado. Isto significa que, num
contexto onde o valor de n usado, ++n e n++ so diferentes. Se n armazena o valor 5, ento: x =
n++; atribui 5 a x, mas: x = ++n; atribuiria 6 a x. Em ambos os casos, n passa a valer 6, pois seu
valor foi incrementado em uma unidade.
Os operadores de incremento e decremento podem ser aplicados somente em variveis.
Uma expresso do tipo x = (i + 1)++ incorreta. A linguagem C oferece diversas formas
compactas para escrevermos um determinado comando.
Mesmo para programadores experientes, o uso das formas compactas deve ser feito com
critrio. Por exemplo, os comandos: a = a + 1; a += 1; a++; ++a; so todos equivalentes e o
programador deve escolher o que achar mais adequado e simples.
3.2 - Operadores Relacionais
Os operadores relacionais so aqueles que estabelecem uma relao entre dois operandos
ou expresses. Na linguagem em C so os seguintes.
< menor que;
> maior que;
<= menor ou igual que;
>= maior ou igual que;
== igual a;
!= diferente de.
Estes operadores comparam dois valores. O resultado produzido por um operador relacional
0 ou 1. Em C, no existe o tipo booleano (true ou false). O valor zero interpretado como falso e
qualquer valor diferente de zero considerado verdadeiro. Assim, se o resultado de uma
comparao for falso, produz-se o valor 0, caso contrrio, produz-se o valor 1.

Pgina 4

3.3 - Operadores Lgicos


Os operadores lgicos combinam expresses booleanas. A linguagem oferece os seguintes
operadores lgicos:
&& operador binrio E (AND);
|| operador binrio OU (OR);
! operador unrio de NEGAO (NOT).
Expresses conectadas por && ou || so avaliadas da esquerda para a direita, e a avaliao
pra assim que a veracidade ou falsidade do resultado for conhecida. Recomendamos o uso de
parnteses em expresses que combinam operadores lgicos e relacionais. Os operadores
relacionais e lgicos so normalmente utilizados para tomada de decises. No entanto, podemos
utiliz-Ios para atribuir valores a variveis. Por exemplo, o trecho de cdigo abaixo vlido e
armazena o valor 1 em a e 0 em b.
int a, b;
int c=23;
int d = c + 4;
a = (c < 20) || (d > c); /* verdadeiro */
b = (c < 20) && (d > c); /* falso */
Devemos salientar que, na avaliao da expresso atribuda varivel b, a operao (d>c)
no chega a ser avaliada, pois independente do seu resultado a expresso como um todo ter
como resultado 0 (falso), uma vez que a operao (c<20) tem valor falso.
3.4 - Operador sizeof
Outro operador fornecido por C, sizeof, resulta no nmero de bytes de um determinado tipo.
Por exemplo, int a = sizeof(float). Armazena o valor 4 na varivel a, pois um float ocupa 4 bytes de
memria. Este operador pode tambm ser aplicado a uma varivel, retomando o nmero de bytes
do tipo associado varivel.
3.5 - Converso de Tipo
Existem converses automticas de valores na avaliao de uma expresso. Assim, na
expresso 3/1.5, o valor da constante 3 (tipo int) promovido (convertido) para double antes de a
expresso ser avaliada, pois o segundo operando do tipo double (1.5) e a operao feita na
preciso do tipo mais representativo.
Quando, numa atribuio, o tipo do valor atribudo diferente do tipo da varivel, tambm h
uma converso automtica de tipo. Por exemplo, se escrevermos int a = 3.5; o valor 3.5
convertido para inteiro (isto , passa a valer 3) antes de a atribuio ser efetuada. Como
resultado, o valor atribudo varivel 3 (inteiro). Alguns compiladores exibem advertncias
quando a converso de tipo pode significar uma perda de preciso ( o caso da converso real
para inteiro, por exemplo).
O programador pode explicitamente requisitar uma converso de tipo atravs do uso do
operador de molde de tipo (operador cast). Por exemplo, so vlidos os comandos abaixo.
int a, b; // declara duas variveis inteiras
char c; // declara uma varivel do tipo caractere.
C = 5; // atribuio de um caractere 5 para c.
a = (int) 3.5; // a varivel a recebe o valor 3 convertido para
inteiro
Pgina 5

b = (int) 3.5 % 2; // a varivel b recebe um valor inteiro 1.


b = c + a;

// a varivel b ficar com o valor 8 que 3 + 5.

4 - ENTRADAS E SADAS
As operaes de entrada e sada so realizadas por funes. Existe em C uma biblioteca
padro que possui as funes bsicas necessrias. Na biblioteca padro, podemos encontrar
funes matemticas do tipo raiz quadrada, seno, cosseno etc., funes para a manipulao de
cadeias de caracteres e funes de entrada e sada.
Nesta seo, sero apresentadas as duas funes bsicas de entrada e sada
disponibilizadas pela biblioteca padro. necessrio escrever: #include <stdio.h> no incio do
programa que utiliza as funes da biblioteca de entrada e sada.
4.1 - Funo printf
A funo printf possibilita a sada de valores (sejam eles constantes, variveis ou resultado
de expresses), segundo um determinado formato. Informalmente, podemos dizer que a forma da
funo : printf (formato, lista de constantes/variveis/expresses ... ).
O primeiro parmetro uma cadeia de caracteres, em geral delimitada com aspas, que
especifica o formato de sada das constantes, variveis e expresses listadas em seguida.
Para cada valor que se deseja imprimir, deve existir um especificador de formato
correspondente na cadeia de caracteres formato. Os especificadores de formato variam com o
tipo do valor e a preciso em que queremos que eles sejam impressos. Estes especificadores so
precedidos pelo caractere % e especificam os seguintes tipos:
%c - char;
%d - int;
%i - int;
%u - unsigned int;
%f - double (ou float);
%e - double (ou float) no formato cientfico;
%g - double (ou float) no formato mais apropriado (%f ou %e);
%s - cadeia de caracteres.
Com base nesses conceitos, vamos apresentar alguns exemplos como segue. A funo
printf ("%d %g\n", 33, 5.3) tem como resultado a impresso da linha: 33 5.3, ou ainda: printf
("Inteiro = %d Real = %g\n", 33, 5.3), com sada: Inteiro = 33 Real = 5.3. Isto , alm dos
especificadores de formato, podemos incluir textos no formato, que so mapeados diretamente
para a sada.
Assim, a sada formada pela cadeia de caracteres do formato onde os especificadores so
substitudos pelos valores correspondentes. Existem alguns caracteres de escape que so
frequentemente utilizados nos formatos de sada. So eles:
\n - nova linha;
\t - tabulao;
\r - de retrocesso;
\" o caractere ";
\\ o caractere \.

Pgina 6

%% o caracter %
possvel tambm especificar o tamanho dos campos, como segue:
%4d;
%7.2f;
A funo printf retorna o nmero de campos impressos. Salientamos que para cada
constante, varivel ou expresso listada devemos ter um especificador de formato apropriado.
4.2 - Funo scanf
A funo scanf permite capturarmos valores fornecidos via teclado pelo usurio do
programa. Informalmente, podemos dizer que sua forma geral : scanf (formato, lista de
endereos das variveis). O formato deve possuir especificadores de tipos similares aos
mostrados para a funo printf. Para a funo scanf, no entanto, existem especificadores
diferentes para o tipo float e double como segue:
%c char;
%d - int;
%u - unsigned int;
%f,%e,%g - float;
%If, %Ie, %Ig - double;
%s - cadeia de caracteres.
A principal diferena que o formato deve ser seguido por uma lista de endereos de
variveis (na funo printf passamos os valores de constantes, variveis e expresses). Por ora,
basta saber que, para ler um valor e atribu-Io a uma varivel, devemos passar o endereo da
varivel para a funo scanf. O operador & retoma o endereo de uma varivel. Assim, para ler
um inteiro, devemos ter:
int n;
scanf("%d", &n);
Para a funo scanf, os especificadores %f, %e e %g so equivalentes. Aqui, caracteres
diferentes dos especificadores no formato servem para restringir a entrada. Por exemplo:
scanf("%d:%d", &h, &m); obriga que os valores (inteiros) fornecidos sejam separados pelo
caractere dois pontos (:).
Um espao em branco dentro do formato faz com que sejam "pulados" eventuais brancos da
entrada. Os especificadores %d, %f, %e e %g automaticamente pulam os brancos que
precederem os valores numricos a serem capturados. A funo scanf retorna o nmero de
campos lidos com sucesso.
5 - CONTROLE DE FLUXO
5.1 - Deciso ou Seleo com if
O comando de seleo ou deciso if um comando de deciso bsico. A forma de se usar
este comando est exemplificado a seguir, onde temos exemplos de seleo simples e composta.
if (expr) {
bloco de comandos 1

}
Pgina 7

ou
if(expr){
bloco de comandos 1

}else{
bloco de comandos 2

}
Se expr produzir um valor diferente de 0 (verdadeiro), o bloco de comandos 1 ser
executado. A incluso do else requisita a execuo do bloco de comandos 2, se a expresso
produzir o valor 0 (falso). Cada bloco de comandos deve ser delimitado por uma chave aberta e
uma chave fechada. Se dentro de um bloco tivermos apenas um comando a ser executado, as
chaves podem ser omitidas, como vemos abaixo. Na verdade, deixamos de ter um bloco.
if ( expr )
comandol;
eles
comando2;
A indentao (recuo de linha) dos comandos fundamental para uma maior clareza do
cdigo. O estilo de indentao varia a gosto do programador. Podemos aninhar comandos if. Um
exemplo simples ilustrado a seguir:
#include <stdio.h>
void main (void)
{
int a, b;
printf ("Digite dois nmeros inteiros: ");
scanf("%d%d",&a,&b);
if (a%2 == 0)
if (b%2 == 0)
printf ("VoceDigitou dois numeros pares! \n");
}
Primeiramente, notamos que no foi necessrio criar blocos ( { ... } ) porque a cada if est
associado apenas um comando. Ao primeiro, associamos o segundo comando if, e ao segundo if,
o comando que chama a funo printf. Assim, o segundo if s ser avaliado se o primeiro valor
fornecido for par, e a mensagem s ser impressa se o segundo valor fornecido tambm for par.
Outra construo para o mesmo exemplo produzir resultados idnticos como escrito a seguir.
void main (void)
{
int a, b;
printf ("Digite dois numeros inteiros: ");
Pgina 8

scanf("%d%d",&a,&b);
if ((a%2 == 0) && (b%2 == 0))
printf ( "Voce digitou dois numeros pares! \n" );
}
Devemos ter cuidado com o aninhamento de comandos if-else. A indentao utilizada pode
nos levar a erros de interpretao. Para os casos em que a associao entre ife else no est
clara, recomendamos a criao explcita de blocos, mesmo contendo um nico comando.
Reescrevendo o programa, podemos obter o efeito desejado.
/* temperatura * /
#include <stdio. h>
void main (void)
{
int temp;
printf ("Digite a temperatura: ");
scanf ("%d", &temp);
if (temp < 30)
{
if (temp > 20)
printf ("Temperatura agradavel \n");
}else{
printf ("Temperatura muito quente \n");
}
}
Esta regra de associao do else propicia a construo do tipo else-if, sem que se tenha o
comando elseif explicitamente na gramtica da linguagem. Na verdade, em C, construmos
estruturas else-if com if's aninhados. O exemplo a seguir vlido e funciona como esperado.
/* - temperatura (versao 1) -- */
#include <stdio. h>
void main (void)
{
int temp;
printf ("Digite a temperatura: ");
scanf ("%d", &temp);
if (temp < 10)
printf ("Temperatura muito fria \n");
else if (temp < 20)
printf (" Temperatura fria \n");
Pgina 9

else if (temp < 30)


printf ("Temperatura agradavel \n");
else
printf ("Temperatura muito quente \n");
5.2 - Estruturas de Bloco
Uma funo composta por estruturas de blocos. Cada chave aberta e fechada em C
representa um bloco. As declaraes de variveis s podem ocorrer no incio do corpo da funo
ou no incio de um bloco, isto , devem seguir uma chave aberta. Uma varivel declarada dentro
de um bloco vlida apenas dentro do bloco ou varivel local. Aps o trmino do bloco, a varivel
deixa de existir. Por exemplo:
...
if(n>0)
{
int i;
...
}
... /* a varivel i no existe neste ponto do programa */
A varivel i, definida dentro do bloco do if, s existe dentro deste bloco. uma boa prtica
de programao declarar as varveis o mais prximo possvel dos seus usos.
5.3 - Construes com Laos
A iteratividade um dos recursos mais poderosos em programas computacionais.
So procedimentos iterativos, isto , procedimentos que devem ser executados em vrios
passos.
Para calcular o fatorial de um nmero atravs de um programa de computador, utilizamos
tipicamente um processo iterativo, em que o valor da varivel varia de 1 a n. A linguagem C
oferece diversas construes possveis para a realizao de laos iterativos. O primeiro a ser
apresentado o comando while. Sua forma geral :
while (expr)
{
bloco de comandos

}
Enquanto expr for avaliada em verdadeiro, o bloco de comandos executado
repetidamente. Se expr for avaliada como falso, o bloco de comando no executado e a
execuo do programa prossegue aps o final do bloco do lao. Uma possvel implementao do
clculo do fatorial usando while mostrada a seguir.
/* -- fatorial --- */
#include <stdio.h>
void main (void)

Pgina 10

{
int I, n;
int f = 1;
printf ("Digite um nmero inteiro:");
scanf ("%d", &n);
/* --- calcula fatorial --- */
i = 1;
whi1e (i <= n){
f *= i;
i++;
}
printf("Fatorial %d \n", f);
}
Uma segunda forma de construo de laos, mais compacta e amplamente utilizada,
atravs de laos for. A forma geral do for :
for (expr_inicial; expr_relacional; expr_de_incremento)
{
bloco de comandos
...
}
A implementao do lao for pode ser verificada no cdigo a seguir, onde ilustramos a
utilizao do comando for no programa para clculo do fatoria!'
/* -- fatorial ---) */
#include <stdio .h>
void main (void)
{
int I, int n;
int f = 1;
printf ("Digite um nmero inteiro:");
scanf("%d", &n);
/* calcula fatorial */
for (i = 1; i <= n; i++){
f *= i;
}
printf(" Fatorial %d \n", f);
}
Pgina 11

Observamos que as chaves que seguem o comando for, neste caso, so desnecessrias, j
que o corpo do bloco composto por um nico comando. Tanto a construo com while como a
construo com for avaliam a expresso booleana que caracteriza o teste de encerramento no
incio do lao. Assim, se esta expresso tiver valor igual a zero (falso), quando for avaliada pela
primeira vez, os comandos do corpo do bloco no sero executados nenhuma vez.
H um outro comando para construo de laos cujo teste de encerramento avaliado no
final. Esta construo o do-while, cuja forma geral :
do{
bloco de comandos
} while (expr_booleana);
Um exemplo do uso desta construo mostrado abaixo, onde validamos a insero do
usurio, isto , o programa repetidamente solicita a insero de um nmero enquanto o usurio
inserir um inteiro negativo.
/* f atorial ---- */
#include <stdio.h>
void main (void)
{
int I n;
int f = 1;
do{
printf (Digite um valor inteiro nao negativo: );
scanf (%d, &n);
} while (n<0);
/* calcula fatorial */
for (i = 1; i <= n; i++) {
f *= i;
}
printf("Fatorial = %d\n, f);
}
5.4 Interrupes com break e continue
O comando break, quando utilizado dentro de um lao, interrompe e termina a execuo do
mesmo. A execuo prossegue com os comandos subsequentes ao bloco. O cdigo abaixo ilustra
o efeito de sua utilizao.
#include <stdio. h>
void main (void)
{
int i;
for (i = 0; i < 10; i++)

Pgina 12

if (i == 5)
break;
printf("%d", i);
}
printf("fim\n);
}
A sada deste programa, se executado, ser: 01234 fim pois, quando i tiver o valor 5, o lao
ser interrompido e finalizado pelo comando break, passando o controle para o prximo comando
aps o lao, no caso uma chamada final de printf.
O comando continue tambm interrompe a execuo dos comandos de um lao.
A diferena bsica em relao ao comando break que o lao no automaticamente
finalizado. O comando continue interrompe a execuo de um lao passando para a prxima
iterao pulando os comandos existentes, como podemos ver no cdigo abaixo.
#include <stdio.h>
void main (void)
{
int i;
for (i = 0; i < 10; i++)
if (i == 5)
continue;
printf("%d", i);
}
printf("fim\n");
}
O resultado de sada do programa acima o seguinte conjunto. {0 1 2 3 4 6 7 8 9 fim}.
Devemos ter cuidado com a utilizao do comando continue nos laos while. Observe um
programa INCORRETO escrito logo abaixo.
/ * - Verso INCORRETA --* /
#include <stdio. h>
void main (void)
{
int i = 0;
while (i < 10){
if (i == 5)
continue;
printf("%d", i);
i++;

Pgina 13

}
printf("fim\n");
}
O programa acima est INCORRETO, pois o lao criado no tem fim. A execuo do
programa no termina. Isto porque a varivel i nunca ter valor superior a 5, e o teste ser sempre
verdadeiro. O que ocorre que o comando continue provoca um salto dos demais comandos do
lao quando i for igual a 5, inclusive o comando que incrementa a varivel i.
5.5 - Seleo
Alm da construo else-if, temos tambm o comando (switch) para selecionar um dentre
um conjunto de possveis casos. Sua forma geral est exemplificada abaixo.
int op = 1;
scanf(%d",&op);
switch (op){
case 1:
.../* comandos executados se op == 1 */
break;
case 2:
.../* comandos executados se op == 2 */
break;
case 3:
.../* comandos executados se op 3 */
break;
default:
.../* executados se op for diferente de todos */
break;
}
A varivel op deve ser um nmero inteiro ou uma constante caractere. Se op resultar no
valor op, os comandos que se seguem ao caso op so executados, at que se encontre um break.
Se o comando break for omitido, a execuo do caso continua com os comandos do caso
seguinte. O caso default (nenhum dos outros) pode aparecer em qualquer posio, mas
normalmente colocado por ltimo.
Para exemplificar, mostramos a seguir um programa que implementa uma calculadora
convencional que efetua as quatro operaes bsicas. Este programa usa constantes caracteres.
/* --- Calculadora de quatro operaes --- */
#include <stdiooh>
void main (void)
{
float num1, num2; char op;
Pgina 14

printf(Digite: numero op numero\n");


scanf ("%f%c%f", &numl, &op, &num2);
switch (op){
case '+' :
printf (" = %f\n", numl+num2);
break;
case '-':
printf (" = %f\n", numl-num2);
break;
case '*':
printf (" = %f\n", numl*num2);
break;
case'/' :
printf (" = %f\n", numl/num2);
break;
default:
printf ("Operador invalido! \n");
break;
}
}
6 - PROCEDIMENTOS E FUNES
So sub-rotinas que implementam uma determinada quantidade de cdigo que realizam
uma tarefa bem determinada. So exemplos de funes ou procedimentos: calcular raiz quadrada,
obter uma substring, calcular potncia etc. H uma diferena entre procedimento e funo.
Procedimento ou procedure uma rotina que no retoma valor e Funo uma rotina que retorn
um valor determinado. A funo s retorn um valor.
Os prximos procedimentos ilustram o uso de rotinas em pseudocdigo e em seguida a
implementao correspondente em linguagem C. O uso do pseudocdigo livre dos rigores da
sintaxe exigida pelo compilador, facilitando o entendimento do problema e a consequente soluo
atravs da lgica de programao.
A seguir esto alguns exemplos de rotinas que chamam sub-rotinas, tanto em pseudocdigo
como em linguagem C. Algumas rotinas realizam chamadas a outras funes. Observe os
exemplos seguintes de pseudocdigos que ilustram o que estamos estudando.
O fragmento de cdigo que segue apresenta um procedimento principal (void) que instancia
algumas variveis e realiza as chamadas a uma funo obtendo o retomo que ser armazenado
na varivel r e em seguida utiliza outro procedimento imprime(r) para imprimir o valor que foi
retorndo.
Aps a impresso do resultado da funo produto, temos um procedimento denominado de
soma que calcula a soma e imprime o resultado. Devemos notar que este ltimo procedimento
no retoma valor algum.

Pgina 15

/* - procedimento principal -- * /
inicio
int x,y,r;
x = 2;
y = 3;
r = produto (x, y);
parmetros

//chamada

da

funo

com

passagem

de

imprime(r);
soma (x,y) ;
fim

/* ----Rotina/funo produto -----*/


int produto (int k, int z)
inicio
return(k * z);
fim
//---- Procedimento soma ---//
procedimento soma(x, y)
inicio
var x, y: inteiro;
imprime(x + y);
fim
Aps o entendimento de como funcionam os procedimentos apresentados anteriormente em
pseudocdigo, vamos codific-Ios na linguagem C. Os prximos cdigos so implementaes em
C para os algoritmos anteriores.
/* -.- rotina principal da linguagem C ---*/
void main()
{
int x,y,r;
x=2;
y=3;
r = produto(x, y);
parmetros

//chamada

da

funo

com

passagem

de

printf ("%i" ,r);


soma(x, y);
}

Pgina 16

/* ---- funo produto ---*/


int produto (int k,int z){
return(k * z);
}
/* -- Procedimento soma ---* /
void soma (x, y){
int x,y;
printf("%d",x+y);
}
A construo de funes tem o objetivo de dividir grandes tarefas de computao em tarefas
menores. A criao de funes evita a repetio de cdigo, de modo que um procedimento que
repetido deve ser transformado numa funo que, ento, ser chamada diversas vezes.
Um programa bem estruturado deve ser planejado em termos de funes, e estas. por sua
vez, podem esconder do corpo principal do programa detalhes ou particularidades de
implementao. Nesta seo, discutiremos a codificao de nossas prprias funes.
A forma geral para definir uma funo pode ser verificada no exemplo a seguir.
tipo_retornado nome_da_funo(lista de parmetros ... ){
corpo da funo
}
Para ilustrar a criao de funes, consideraremos o clculo do fatorial de um nmero.
Podemos escrever uma funo que, dado um determinado nmero inteiro no negativo n, imprime
o valor de seu fatorial. Um programa que utiliza esta funo pode ser escrita como segue:
/* --- imprime um fatorial ---* /
#include <stdio.h>
void fat(int n); /* prottipo da funo fat() */
/ *-- funo principal-- * /
void main (void)
{
int n;
scanf ("%d", &n);
fat(n);
}
/* -- funo que imprime o fatorial-- * /
void fat(int n ){
int i;
int f = 1;

Pgina 17

for (i = 1; i <= n; i++)


f *= i;
printf ("Fatorial = %d\n", f);
}
Notamos, neste exemplo, que a funo fat recebe como parmetro o nmero cujo fatorial
deste deve ser impresso.
Os parmetros de uma funo devem ser listados, com seus respectivos tipos, entre os
parnteses que seguem o nome da funo.
Devemos notar que main() tambm uma funo. Sua nica particularidade consiste em ser
a funo automaticamente executada aps o programa ser carregado.
No exemplo do clculo do fatorial, a funo fat no tem nenhum valor de retorno, portanto
colocamos a palavra void antes do nome da funo, indicando a ausncia de um valor de retorno.
void fat (int n){
...
}
Ressaltamos que C exige que se coloque o prottipo da funo antes desta ser chamada,
se estas funes forem implementadas aps a funo main(). O prottipo de uma funo consiste
na repetio da linha de sua definio seguida do caractere (;).
A rigor, no prottipo no h necessidade de indicarmos os nomes dos parmetros, apenas
os seus tipos, portanto seria vlido escrever: void fat (int). O prottipo da funo necessrio para
que o compilador verifique os tipos dos parmetros na chamada da funo. devido a esta
necessidade que se exige a incluso do arquivo stdio.h para a utilizao das funes de entrada e
sada da biblioteca padro.
Neste arquivo, encontram-se, entre outras coisas, os prottipos das funes printf e scanf
Uma funo pode ter um valor de retorno associado. Para ilustrar a discusso, vamos reescrever
o cdigo acima, fazendo com que a funo fat retome o valor do fatorial.
#include <stdio.h>
int fat (int n);

/* prottipo */

void main (void)


{
int n, r;
scanf ("%d", &n);
r = fat(n};
printf ("Fatorial = %d\n", r);
}
/* --- funcao fatorial-- */
int fat (int n){
int i;
int f = 1;

Pgina 18

for (i = 1; i <= n; i++)


f *= i;
return(f)
}
7 - USO DE PONTEIRO
Nesta seo apresentaremos uma reviso de ponteiros em linguagem C, o que servir como
base para a implementao de listas encadeadas utilizando ponteiros.
Para cada tipo de dado existente, h um tipo ponteiro que pode armazenar endereos de
memria onde existem valores do tipo correspondente armazenados. Por exemplo, quando
escrevemos: int a; declaramos uma varivel com nome a que pode armazenar valores inteiros.
Automaticamente, reserva-se um espao na memria suficiente para armazenar valores inteiros
(geralmente 2 bytes).
Da mesma forma que declaramos variveis para armazenar inteiros, podemos declarar
variveis que, em vez de servirem para armazenar valores inteiros, servem para armazenar
valores de endereos de memria onde h variveis inteiras armazenadas.
Para declararmos um ponteiro, usamos a mesma palavra do tipo com os nomes das
variveis precedidas pelo caractere *. Assim, podemos escrever: int *p para declarar um ponteiro
do tipo int.
Neste caso, declaramos uma varivel com nome p que pode armazenar endereos de
memria onde existe um inteiro armazenado. Para atribuir e acessar endereos de memria.
Podemos usar o operador unrio & ("endereo de"), que resulta no endereo da posio da
memria reservada para a varivel. O operador unrio * ("contedo de"), aplicado a variveis do
tipo ponteiro, acessa o contedo do endereo de memria armazenado pela varivel ponteiro.
Para trabalharmos com alocao dinmica, devemos alocar pores de memria utilizando
a funo malloc() que ser mostrada a seguir.
main()
{
int *ptr, i;
ptr = (int *) malloc (sizeof(int));
*ptr = 5800;
i = *ptr;
printf ("%i", i);

/* imprimir 5800 */

i = 4200;
printf("%i",i);

/* imprimir 4200 */

}
Ao analisarmos o cdigo acima notamos que a varivel *ptr foi declarada como inteiro para
ponteiro e na linha seguinte foi reservado 2 bytes para ptr que recebe o valor 5800. A varivel i
recebe o contedo de do endereo de ptr que 5800, como podemos verificar pela impresso da
antepenltima linha.
main()
{
Pgina 19

int x;
*px;
...
px = &x;
}
O fragmento do cdigo acima atribui o endereo de x para px. O contedo de px o
endereo da varivel x. Vamos exemplificar o uso de ponteiro utilizando o fragmento de cdigo
abaixo.
main()
{
char c, *pc, x;
c = 'A';
pc = &c;
printf ("%c", *pc);
x = *pc;
}
Para compreendermos melhor o uso de ponteiros, vamos estudar o cdigo do programa
acima, observando os mapas de memrias na seqncia de quadros a seguir.
C

pc

1000

1001

1003

Lixo

lixo

Lixo

Fazemos a varivel c receber o valor 'A' como segue: c = 'A'


C

pc

1000

1001

1003

'A'

lixo

Lixo

A varivel pc recebe o endereo da varivel c que dado pela expresso seguinte: pc=&c:
C

pc

1000

1001

1003

'A'

1000

Ao imprimirmos o contedo da varivel pc, teremos como sada, o valor 'A' que est no
endereo 1000. Basta executar esta linha printf("%c ", *pc). Ao atribuirmos o contedo de pc (*pc)
a varivel x, temos x = c.
A seguir, apresentamos outros exemplos de uso de ponteiros. No cdigo abaixo,
declaramos duas variveis do tipo inteiro, a primeira um inteiro simples, a segunda um inteiro
para ponteiro. Em seguida a varivel p, que destinada a armazenar endereos, recebe o
endereo da varivel a. Ao atribuirmos 2 a *p, estamos colocando o valor 2 no endereo da
Pgina 20

varivel a. Assim, o programa ir imprimir o valor 2. Sugerimos que implemente este cdigo para
comprovar o que estamos apresentando.
int main (void)
{
int a;
int *p;
p = &a;
*p = 2;
printf ("%d", a);
return;
}
Agora que vimos como usar ponteiros, j podemos aplicar este conceito na utilizao de
estruturas para implementar listas. Abaixo apresentaremos a definio da estrutura node ou n de
uma lista encadeada. Aps a definio, usamos a funo malloc() para reservar uma poro de
memria correspondente ao tamanho do n da lista.
struct node{
int info;
struct node *prox;
};
struct node *ptr;
ptr = (struct node*) malloc (sizeof(struct node));
De maneira anloga, podemos declarar ponteiros de outros tipos: float *m; char * s, alm de
outros tipos que podemos construir na linguagem C, como vimos acima com a funo malloc() e
struct;
8 - PASSAGEM DE PONTEIROS PARA FUNES
Os ponteiros oferecem meios de alterarmos valores de variveis acessando-as
indiretamente. As funes no podem alterar diretamente valores de variveis da funo que fez a
chamada. No entanto, se passarmos para uma funo os valores dos endereos de memria
onde suas variveis esto armazenadas, a funo pode alterar. indiretamente, os valores das
variveis da funo que a chamou.
Vamos analisar o uso desta estratgia atravs de um exemplo. Consideremos uma funo
projetada para trocar os valores entre duas variveis.
O prximo cdigo no funciona como esperado (sero impressos 5 e 7), pois os valores de
a e b da funo main() no so alterados. Alterados so os valores de x e y dentro da funo
troca, mas eles no representam as variveis da funo main(), apenas so inicializados com os
valores de a e b.
/* funcao troca (versao INCORRETA) */
#include<stdio. h>
void troca (int x, int y){
int temp;

Pgina 21

temp = x;
x = y;
y = temp;
}
void main ( void )
{
int a = 5, b = 7;
troca (a, b);
printf ("%d %d \n", a, b);
}
A alternativa fazer com que a funo receba os endereos das variveis e, assim, alterar
seus valores indiretamente. Reescrevendo o programa acima, corrigindo os erros, temos:
/* funcao troca (versao CORRETA) */
#include <stdio.h>
void troca (int *px, int *py ) {
int temp;
temp = *px;
*px = *py;
*py = temp;
}
void main (void)
{
int a = 5, b = 7;
troca(&a, &b);

/* passamos os endereos das variveis */

printf ("%d %d \n", a, b);


}
O cdigo mostrado ilustra a execuo deste programa mostrando o uso da memria.
Assim, conseguimos o efeito desejado. Agora fica explicado por que passamos o endereo
das variveis para a funo scanf(), pois, caso contrrio, a funo no conseguiria devolver os
valores lidos.
Para finalizar, vamos apresentar a passagem de estruturas por parmetro. No cdigo a
seguir temos duas funes que recebem parmetros. A funo imp1() recebe um ponteiro para
variveis simples ou primitiva, a outra funo imp() recebe uma estrutura.
/ * passagem de parmetros por referncia * /
# include <stdio. h>
struct teste{

/* definio da estrutura teste * /

int m;
Pgina 22

char n[10];
};

void imp(struct teste te);

/* prottipo da funo imp. */

void imp1(int x, int y);

/* prottipo da funo imp1.*/

void main ()
{
int i, j;
struct teste te;
te.m = 5;
te.n[0] = 'T';
te.n[1] = 'e';
te.n[2] = 's';
te.n[3] = 't';
te.n[4] = 'e';
i = 10;
j = 20;
imp1(&i, &j);
imp(&te);

/* passagem da estrutura */

getch();
}
/* recebe um endereo da estrutura teste como parmetro */
void imp (struct teste *te)
{
int i;
printf ("Estrutura \n");
printf("%d\n",te->m);
for (i=0; i<5; i++)
printf ("%c" ,te->n [i]);
printf ("\n");
}
/* recebe
contedos*/

os

endereos

das

variveis

imprime

os

seus

void impl(int *x, int *y){


printf("inteiros x e y\n");

Pgina 23

printf("%d\n",*x);
printf("%d\n",*y);
}

9 - LISTA DE EXERCCIOS (ENTREGAR MANUSCRITO)


a) Declarar um conjunto de variveis inteiras, reais e char.
b) Construir um loop para realizar 10 iteraes e imprimir somente os nmeros pares das
interaes.
c) Calcular o somatrio dos quadrados dos valores de um at n.
d) Construir um procedimento para imprimir o produto de dois valores recebidos por
parmetro.
e) Construir uma funo que retorne o resto de uma diviso entre dois nmeros inteiros.
f) Construir uma funo que recebe como parmetro o endereo de uma varivel e altere o
valor para que a funo principal possa imprimir.
g) Elabore uma funo que receba uma estrutura por referncia, altere os valores dos
membros da estrutura e faa a funo principal imprimir esses valores alterados.
h) Elabore uma funo que receba uma estrutura por valor, altere os valores dos membros
da estrutura e devolva para a funo principal imprimir esses valores alterados.

10 - BIBLIOGRAFIA

SILVA, Osmar Quirino da.. Estrutura de Dados e Algoritmos Usando C: Fundamentos e


Aplicaes. 1 ed. Rio de Janeiro: Cincia Moderna, 2007.

Pgina 24