Vous êtes sur la page 1sur 102

LINGUAGEM C:

DESCOMPLICADA
Prof. Andr e R. Backes
1 COMANDOS DE CONTROLE CONDICIONAL
Os programas escritos at e o momento s ao programas sequeciais: um co-
mando e executado ap os o outro, do comeco ao mdo programa, na ordem
em que foram declarados no c odigo fonte. Nenhum comando e ignorado.
Entretanto, h a casos em que e preciso que um bloco de comandos seja
executado somente se uma determinada condic ao for verdadeira. Para
isso, precisamos de uma estrutura de selec ao, ou um comando de con-
trole condicional, que permita selecionar o conjunto de comandos a ser
executado. Isso e muito similar ao que ocorre em um uxograma, onde o
smbolo do losango permitia escolher entre diferentes caminhos com base
em uma condic ao do tipo verdadeiro/falso:
Nesta sec ao iremos ver como funcionamcada uma das estruturas de selec ao
presentes na linguagem C.
1.1 COMANDO IF
Na linguagem C, o comando if e utilizado sempre que e necess ario esco-
lher entre dois caminhos dentro do programa, ou quando se deseja execu-
tar um ou mais comandos que estejam sujeitos ao resultado de um teste.
A forma geral de um comando if e:
if (condic ao) {
seq u encia de comandos;
}
Na execuc ao do comando if a condic ao ser a avaliada e:
2
se a condic ao for diferente de zero, ela ser a considerada verdadeira
e a seq u encia de comandos ser a executada;
se a condic ao for zero, ela ser a considerada falsa e a seq u encia de
comandos n ao ser a executada.
Abaixo, tem-se um exemplo de um programa que l e um n umero inteiro
digitado pelo usu ario e informa se o mesmo e maior do que 10:
Exemplo: comando if
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt num;
5 p r i n t f ( Di gi t e um numero : ) ;
6 scanf ( %d ,&num) ;
7 i f (num > 10)
8 p r i n t f ( O numero e mai or do que 10\n ) ;
9 system( pause ) ;
10 ret urn 0;
11 }
Relembrando a id eia de uxogramas, e possvel ter uma boa representac ao
de como os comandos do exemplo anterior s ao um-a-um executados du-
rante a execuc ao do programa:
3
Por condic ao, entende-se qualquer express ao que resulte numa resposta
do tipo falso (zero) ou verdadeiro (diferente de zero). A condic ao pode ser
uma express ao que utiliza operadores dos tipos:
Matem aticos : +,-, *, /, %
Relacionais: >, <, >=, <=, ==, !=
L ogicos: &&, ||
Diferente da maioria dos comandos, n ao se usa o ponto e
vrgula (;) depois da condic ao do comando if.
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt num;
5 p r i n t f ( Di gi t e um numero : ) ;
6 scanf ( %d ,&num) ;
7 i f (num > 10) ; / / ERRO
8 p r i n t f ( O numero e mai or que 10\n ) ;
9 system( pause ) ;
10 ret urn 0;
11 }
Na linguagem C, o operador ponto e vrgula (;) e utilizado para separar as
instruc oes do programa. Coloc a-lo logo ap os o comando if, como exem-
plicado acima, faz com que o compilador entenda que o comando if j a
terminou e trate o comando seguinte (printf) como se o mesmo estivesse
fora do if. No exemplo acima, a mensagem de que o n umero e maior do
que 10 ser a exibida independente do valor do n umero.
O compilador n ao ir a acusar um erro se colocarmos o ope-
rador ponto e vrgula (;) ap os o comando if, mas a l ogica
do programa poder a estar errada.
1.1.1 USO DAS CHAVES {}
No comando if, e em diversos outros comandos da linguagem C, usa-se os
operadores de chaves { } para delimitar um bloco de instruc oes.
4
Por denic ao, comandos de condic ao (if e else) ou
repetic ao (while, for,...) atuam apenas sobre o comando
seguinte a eles.
Desse modo, se o programador deseja que mais de uma instruc ao seja
executada por aquele comando if, esse conjunto de instruc oes deve estar
contido dentro de um bloco delimitado por chaves { }.
if (condic ao) {
comando 1;
comando 2;
...
comando n;
}
As chaves podemser ignoradas se o comando contido den-
tro do if for unico.
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt num;
5 p r i n t f ( Di gi t e um numero : ) ;
6 scanf ( %d ,&num) ;
7 i f (num > 10)
8 p r i n t f ( O numero e mai or que 10\n ) ;
9
10 / OU
11 i f (num > 10) {
12 p r i n t f ( O numero e mai or que 10\n ) ;
13 }
14 /
15 system( pause ) ;
16 ret urn 0;
17 }
1.1.2 EXPRESS

AO CONDICIONAL
Uma express ao condicional e qualquer express ao que resulte numa res-
posta do tipo falso (zero) ou verdadeiro (diferente de zero).
5
Uma express ao condicional pode utilizar operadores dos
tipos: matem aticos, relacionais e/ou l ogicos.
1 / / x e mai or ou i gual a y?
2 i f ( x >= y )
3
4 / / x e mai or do que y+2?
5 i f ( x > y+2)
6
7 / / x5 e di f er ent e de y+3?
8 i f ( x5 ! = y+3)
9
10 / / x e mai or do que y e menor do que z?
11 i f ( x > y && x < z )
12 i f ( y < x < z ) / / ERRO!
Quando o compilador avalia uma condic ao, ele quer um valor de retorno
(verdadeiro ou falso) para poder tomar a decis ao. No entanto, esta ex-
press ao n ao necessita ser uma express ao no sentido convencional.
Uma vari avel sozinha pode ser uma express ao condicio-
nale retornar o seu pr oprio valor.

E importante lembrar que o computador trabalha em termos de 0s e 1s,


sendo a condic ao
falsa: quando o valor da express ao e zero;
verdadeira: quando o valor da express ao e diferente de zero.
Isto quer dizer que, dado uma vari avel inteira num, as seguintes express oes
s ao equivalentes para o compilador:
if (num!=0)//Se a vari avel e diferente de zero...
if (num)//...ela sozinha retorna uma valor que e verdadeiro.
if (num==0)//Se a vari avel e igual a zero (falso)...
e
if (!num)//...sua negac ao e um valor verdadeiro.
6
1.2 COMANDO ELSE
O comando else pode ser entendido como sendo um complemento do co-
mando if. Ele auxlia o comando if na tarefa de escolher dentre os v arios
caminhos a ser segudo dentro do programa.
A forma geral de um comando else e:
if (condic ao) {
seq u encia de comandos;
}
else{
seq u encia de comandos;
}
Se o comando if diz o que fazer quando a condic ao e ver-
dadeira, o comando else trata da condic ao quando ela e
falsa.
Isso ca bem claro quando olhamos a representac ao do comando else em
um uxograma:
Antes, na execuc ao do comando if a condic ao era avaliada e:
se a condic ao fosse verdadeira a seq u encia de comandos seria exe-
cutada;
se a condic ao fosse falsa a seq u encia de comandos n ao seria exe-
cutada e o programa seguiria o seu uxo padr ao.
7
Com o comando else, temos agora que:
se a condic ao for verdadeira, a seq u encia de comandos do bloco if
ser a executada;
se a condic ao for falsa, a seq u encia de comandos do bloco else ser a
executada.
Abaixo, tem-se um exemplo de um programa que l e um n umero inteiro
digitado pelo usu ario e informa se o mesmo e ou n ao igual a 10:
Exemplo: comando if-else
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt num;
5 p r i n t f ( Di gi t e um numero : ) ;
6 scanf ( %d , &num) ;
7 i f (num == 10) {
8 p r i n t f ( O numero e i gual a 10. \n ) ;
9 } el se{
10 p r i n t f ( O numero e di f er ent e de 10. \n ) ;
11 }
12 system( pause ) ;
13 ret urn 0;
14 }
Relembrando a id eia de uxogramas, e possvel ter uma boa representac ao
de como os comandos do exemplo anterior s ao um-a-um executados du-
rante a execuc ao do programa:
8
O comando else n ao tem condic ao. Ele e o caso contr ario
da condic ao do if.
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt num;
5 p r i n t f ( Di gi t e um numero : ) ;
6 scanf ( %d , &num) ;
7 i f (num == 10) {
8 p r i n t f ( O numero e i gual a 10. \n ) ;
9 } el se (num ! = 10) { / / ERRO
10 p r i n t f ( O numero e di f er ent e de 10. \n ) ;
11 }
12 system( pause ) ;
13 ret urn 0;
14 }
O comando else deve ser ser entendido como sendo um complemento do
comando if. Ele diz quais comandos se deve executar se a condic ao do
comando if for falsa. Portanto, n ao e necess ario estabelecer uma condic ao
para o comando else, ele e o oposto do if.
9
Como no caso do if, n ao se usa o ponto e vrgula (;) depois
do comando else.
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt num;
5 p r i n t f ( Di gi t e um numero : ) ;
6 scanf ( %d , &num) ;
7 i f (num == 10) {
8 p r i n t f ( O numero e i gual a 10. \n ) ;
9 } el se ; { / / ERRO
10 p r i n t f ( O numero e di f er ent e de 10. \n ) ;
11 }
12 system( pause ) ;
13 ret urn 0;
14 }
Como no caso do if, colocar o operador de ponto e vrgula (;) logo ap os o
comando else, faz com que o compilador entenda que o comando else j a
terminou e trate o comando seguinte (printf) como se o mesmo estivesse
fora do else. No exemplo acima, a mensagem de que o n umero e diferente
de 10 ser a exibida independente do valor do n umero.
A seq u encia de comandos do if e independente da
seq u encia de comandos do else. Cada comando tem o
seu pr oprio conjunto de chaves.
Se o comando if for executado em um programa, o seu comando else
n ao ser a executado. Portanto, n ao faz sentido usar o mesmo conjunto de
chaves {}para denir os dois conjuntos de comandos.
Uso das chaves no comando if-else
Certo Errado
1 i f ( condi cao ) {
2 seq u enci a de comandos ;
3 }
4 el se{
5 seq u enci a de comandos ;
6 }
1 i f ( condi cao ) {
2 seq u enci a de comandos ;
3 el se
4 seq u enci a de comandos ;
5 }
10
Como no caso do comando if, as chaves podem ser igno-
radas se o comando contido dentro do else for unico.
1.3 ANINHAMENTO DE IF
Um if aninhado e simplesmente um comando if utilizado dentro do bloco
de comandos de um outro if (ou else) mais externo. basicamente, e um
comando if dentro de outro.
A forma geral de um comando if aninhado e:
if(condic ao 1) {
seq u encia de comandos;
if(condic ao 2) {
seq u encia de comandos;
if...
}
else{
seq u encia de comandos;
if...
}
} else{
seq u encia de comandos;
}
Em um aninhamento de ifs, o programa comeca a testar as condic oes
comecando pela condic ao 1. Se o resultado dessa condic ao for diferente
de zero (verdadeiro), o programa executar a o bloco de comando associa-
dos a ela. Do contr ario, ir a executar o bloco de comando associados ao
comando else correspondente, se ele existir. Esse processo se repete para
cada comando if que o programa encontrar dentro do bloco de comando
que ele executar.
O aninhamento de ifs e muito util quando se tem mais do que dois cami-
nhos para executar dentro de um programa. Por exemplo, o comando if e
suciente para dizer se um n umero e maior do que outro n umero ou n ao.
Por em, ele sozinho e incapaz de dizer se esse mesmo n umero e maior,
menor ou igual ao outro como mostra o exemplo abaixo:
11
Exemplo: aninhamento de if
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt num;
5 p r i n t f ( Di gi t e um numero : ) ;
6 scanf ( %d , &num) ;
7 i f (num == 10) {
8 p r i n t f ( O numero e i gual a 10. \n ) ;
9 } el se{
10 i f (num > 10)
11 p r i n t f ( O numero e mai or que 10. \n ) ;
12 el se
13 p r i n t f ( O numero e menor que 10. \n ) ;
14 }
15 system( pause ) ;
16 ret urn 0;
17 }
Isso ca bem claro quando olhamos a representac ao do aninhamento de
ifs em um uxograma:
O unico cuidado que devemos ter no aninhamento de ifs e
o de saber exatamente a qual if um determinado else est a
ligado.
Esse cuidado ca claro no exemplo abaixo: apesar do comando else es-
tar alinhado com o primeiro comando if, ele est a na verdade associado ao
12
segundo if. Isso acontece porque o comando else e sempre associado ao
primeiro comando if encontrado antes dele dentro de um bloco de coman-
dos.
if (cond1)
if (cond2)
seq u encia de comandos;
else
seq u encia de comandos;
No exemplo anterior, para fazer com que o comando else que associado
ao primeiro comando if e necess ario denir um novo bloco de comandos
(usando os operadores de chaves { }) para isolar o comando if mais in-
terno.
if (cond1) {
if (cond2)
seq u encia de comandos;
} else
seq u encia de comandos;
N ao existe aninhamento de elses.
O comando else e o caso contr ario da condic ao do comando if. Assim,
para cada else deve existir um if anterior, por em nem todo if precisa ter um
else.
if (cond1)
seq u encia de comandos;
else
seq u encia de comandos;
else //ERRO!
seq u encia de comandos;
13
1.4 OPERADOR ?
O operador ? e tamb em conhecido como operador tern ario. Trata-se de
uma simplicac ao do comando if-else na sua forma mais simples, ou seja,
com apenas um comando e n ao blocos de comandos.
A forma geral do operador ? e:
express ao condicional ? express ao1 : express ao2;
O funcioanmento do operador ? e id entico ao do comando if-else: primei-
ramente, a express ao condicional ser a avaliada e
se essa condic ao for verdadeira, o valor da express ao1 ser a o resul-
tado da express ao condicional ;
se essa condic ao for falsa, o valor da express ao2 ser a o resultado
da express ao condicional ;
O operador ? e tipicamente utilizado para atribuic oes con-
dicionais.
O exemplo abaixo mostra como uma express ao de atribuic ao pode ser
simplicada utilizando o operador tern ario:
Usando if-else Usando o operador tern ario
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt x , y , z ;
5 p r i n t f ( Di gi t e x : ) ;
6 scanf ( %d ,&x ) ;
7 p r i n t f ( Di gi t e y : ) ;
8 scanf ( %d ,&y ) ;
9 i f ( x > y )
10 z = x ;
11 el se
12 z = y ;
13 p r i n t f ( Mai or = %d , z ) ;
14 system( pause ) ;
15 ret urn 0;
16 }
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt x , y , z ;
5 p r i n t f ( Di gi t e x : ) ;
6 scanf ( %d ,&x ) ;
7 p r i n t f ( Di gi t e y : ) ;
8 scanf ( %d ,&y ) ;
9 z = x > y ? x : y ;
10 p r i n t f ( Mai or = %d , z ) ;
11 system( pause ) ;
12 ret urn 0;
13 }
14
Ooperador ? e limitado e por isso n ao atende a uma gama muito grande de
casos que o comando if-else atenderia. Por em, ele pode ser usado para
simplicar express oes complicadas. Uma aplicac ao interessante e a do
contador circular, onde uma vari avel e incrementada at e um valor m aximo
e, sempre que atinge esse valor, a vari avel e zerada.
index = (index== 3) ? 0: ++index;
Apesar de limitado, o operador ? n ao e restrito a
atribuic oes apenas.
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt num;
5 p r i n t f ( Di gi t e um numero : ) ;
6 scanf ( %d , &num) ;
7 (num == 10) ? p r i n t f ( O numero e i gual a 10. \n
) : p r i n t f ( O numero e di f er ent e de 10. \n )
;
8 system( pause ) ;
9 ret urn 0;
10 }
1.5 COMANDO SWITCH
Al em dos comandos if e else, a linguagem C possui um comando de
selec ao m ultipla chamado switch. Esse comando e muito parecido com o
aninhamendo de comandos if-else-if.
O comando switch e muito mais limitado que o comando
if-else: enquanto o comando if pode testar express oes
l ogicas ou relacionais, o comando switch somente verica
se uma vari avel e ou n ao igual a um certo valor constante.
15
A forma geral do comando switch e:
switch (vari avel) {
case valor1:
seq u encia de comandos;
break;
case valor2:
seq u encia de comandos;
break;
...
case valorN:
seq u encia de comandos;
break;
default:
seq u encia de comandos; }
O comando switch e indicado quando se deseja testar uma
vari avel em relac ao a diversos valores pr e-estabelecidos.
Na execuc ao do comando switch, o valor da vari avel e comparado, na
ordem, com cada um dos valores denidos pelo comando case. Se um
desse valores for igual ao valor da vari avel, a seq u encia de comandos
daquele comando case e executado pelo programa.
Abaixo, tem-se um exemplo de um programa que l e um caractere digitado
pelo usu ario e informa se o mesmo e um smbolo de pontuac ao:
16
Exemplo: comando switch
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 char char i n ;
5 p r i n t f ( Di gi t e um si mbol o de pontuacao : ) ;
6 char i n = get char ( ) ;
7 switch ( char i n ) {
8 case . : p r i n t f ( Ponto . \ n ) ; break ;
9 case , : p r i n t f ( Vi r gul a . \ n ) ; break ;
10 case : : p r i n t f ( Doi s pont os . \ n ) ; break ;
11 case ; : p r i n t f ( Ponto e v i r gul a . \ n ) ; break ;
12 def aul t : p r i n t f ( Nao eh pontuacao . \ n ) ;
13 }
14 system( pause ) ;
15 ret urn 0;
16 }
No exemplo acima, ser a pedido ao usu ario que digite um caractere. O valor
desse caractere ser a comparado com um conjunto de possveis smbolos
de pontuac ao, cada qual identicado em um comando case. Note que,
se o caractere digitado pelo usu ario n ao for um smbolo de pontuac ao, a
seq u encia de comandos dentro do comando default ser a exectada.
O comando default e opcional e sua seq u encia de coman-
dos somente ser a executada se o valor da vari avel que est a
sendo testada pelo comando switch n ao for igual a nenhum
dos valores dos comandos case.
O exemplo anterior do comando switch poderia facilmente ser reescrito
com o aninhamento de comandos if-else-if como se nota abaixo:
17
Exemplo: simulando o comando switch com if-else-if
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 char char i n ;
5 p r i n t f ( Di gi t e um si mbol o de pontuacao : ) ;
6 char i n = get char ( ) ;
7 i f ( char i n == . )
8 p r i n t f ( Ponto . \ n ) ;
9 el se
10 i f ( char i n == , )
11 p r i n t f ( Vi r gul a . \ n ) ;
12 el se
13 i f ( char i n == : )
14 p r i n t f ( Doi s pont os . \ n ) ;
15 el se
16 i f ( char i n == ; )
17 p r i n t f ( Ponto e v i r gul a . \ n ) ;
18 el se
19 p r i n t f ( Nao eh pontuacao . \ n ) ;
20 system( pause ) ;
21 ret urn 0;
22 }
Como se pode notar, o comando switch apresenta uma soluc ao muito mais
elegante que o aninhamento de comandos if-else-if quando se necessita
comparar o valor de uma vari avel.
Apesar das semelhancas entre os dois comandos, o comando switch e o
aninhamento de comandos if-else-if, existe uma diferenca muito importante
entre esses dois comandos: o comando break.
18
Quando o valor associado a um comando case e igual
ao valor da vari avel do switch a respectiva seq u encia de
comandos e executada at e encontrar um comando break.
Caso o comando break n ao exista, a seq u encia de coman-
dos do case seguinte tamb em ser a executada e assim por
diante
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 char char i n ;
5 p r i n t f ( Di gi t e um si mbol o de pontuacao : ) ;
6 char i n = get char ( ) ;
7 switch ( char i n ) {
8 case . : p r i n t f ( Ponto . \ n ) ;
9 case , : p r i n t f ( Vi r gul a . \ n ) ;
10 case : : p r i n t f ( Doi s pont os . \ n ) ;
11 case ; : p r i n t f ( Ponto e v i r gul a . \ n ) ;
12 def aul t : p r i n t f ( Nao eh pontuacao . \ n ) ;
13 }
14 system( pause ) ;
15 ret urn 0;
16 }
Note, no exemplo acima, que caso o usu ario digite o smbolo de ponto (.)
todas as mensagens ser ao escritas na tela de sada.
O comando break e opcional e faz com que o comando
switch seja interrompido assim que uma das seq u encia de
comandos seja executada.
De modo geral, e quase certo que se venha a usar o comando break dentro
do switch. Por ema sua aus encia pode ser muito util emalgumas situac oes.
Por exemplo, quando queremos que uma ou mais seq u encias de coman-
dos sejam executadas a depender do valor da vari avel do switch.
19
Exemplo: comando switch sem break
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt num;
5 p r i n t f ( Di gi t e um numero i n t e i r o de 0 a 9: ) ;
6 scanf ( %d ,&num) ;
7 switch (num) {
8 case 9: p r i n t f ( Nove\n ) ;
9 case 8: p r i n t f ( Oi t o\n ) ;
10 case 7: p r i n t f ( Sete\n ) ;
11 case 6: p r i n t f ( Sei s\n ) ;
12 case 5: p r i n t f ( Ci nco\n ) ;
13 case 4: p r i n t f ( Quatro\n ) ;
14 case 3: p r i n t f ( Tres\n ) ;
15 case 2: p r i n t f ( Doi s\n ) ;
16 case 1: p r i n t f ( Um\n ) ;
17 case 0: p r i n t f ( Zero\n ) ;
18 }
19 system( pause ) ;
20 ret urn 0;
21 }
20
2 COMANDOS DE REPETIC

AO
2.1 REPETIC

AO POR CONDIC

AO
Na sec ao anterior, vimos como realizar desvios condicionais em um pro-
grama. Desse modo, criamos programas em que um bloco de comandos
e executado somente se uma determinada condic ao e verdadeira.
Entretanto, h a casos em que e preciso que um bloco de comandos seja
executado mais de uma vez se uma determinada condic ao for verdadeira:
enquanto condic ao faca
sequ encia de comandos;
m enquanto
Para isso, precisamos de uma estrutura de repetic ao que permita executar
um conjunto de comandos quantas vezes forem necess arias. Isso e muito
similar ao que ocorre em um uxograma, onde o smbolo do losango per-
mitia escolher entre diferentes caminhos com base em uma condic ao do
tipo verdadeiro/falso, com a diferenca de que agora o uxo do programa e
desviado novamente para a condic ao ao nal da sequ encia de comandos:
Exemplo: Pseudo-c odigo e uxograma
1 Lei a B;
2 Enquanto A < B
3 A recebe A + 1;
4 Impri ma A;
5 Fim Enquanto
De acordo com a condic ao, os comandos ser ao repetidos
zero (se falsa) ou mais vezes (enquanto a condic ao for ver-
dadeira). Essa estrutura normalmente e denominada laco
ou loop.
21
Note que a sequ encia de comandos a ser repetida est a subordinada a uma
condic ao. Por condic ao, entende-se qualquer express ao que resulte numa
resposta do tipo falso (zero) ou verdadeiro (diferente de zero). A condic ao
pode ser uma express ao que utiliza operadores dos tipos:
Matem aticos : +,-, *, /, %
Relacionais: >, <, >=, <=, ==, !=
L ogicos: &&, ||
Na execuc ao do comando enquanto, a condic ao ser a avaliada e:
se a condic ao for diferente de zero, ela ser a considerada verdadeira
e a seq u encia de comandos ser a executada. Ao nal da sequ encia
de comandos, o uxo do programa e desviado novamente para a
condic ao;
se a condic ao for zero, ela ser a considerada falsa e a seq u encia de
comandos n ao ser a executada.
2.2 LAC O INFINITO
Um laco innito (ou loop innito) e uma sequ encia de comandos em um
programa de computador que se repete innitamente. Isso geralmente
ocorre por algum erro de programac ao, quando
n ao denimos uma condic ao de parada;
a condic ao de parada existe, mas nunca e atingida.
Basicamente, um laco innito ocorre quando cometemos algum erro ao
especicar a condic ao l ogica que controla a repetic ao ou por esquecer de
algum comando dentro da sequ encia de comandos.
22
Exemplo: loop innito
O valor de X e sempre dimi-
nuido em uma unidade, por-
tanto nunca atinge a condic ao
de parada.
O valor de X nunca e modi-
cado, portanto a condic ao e
sempre verdadeira.
1 X recebe 4;
2 enquanto ( X < 5) f ac a
3 X recebe X 1;
4 Impri ma X;
5 f i m enquanto
1 X recebe 4;
2 enquanto ( X < 5) f ac a
3 Impri ma X;
4 f i m enquanto
2.3 COMANDO WHILE
O comando while equivale ao comando enquantoutilizado nos pseudo-
c odigos apresentados at e agora.
A forma geral de um comando while e:
while (condic ao){
seq u encia de comandos;
}
Na execuc ao do comando while, a condic ao ser a avaliada e:
se a condic ao for diferente de zero, ela ser a considerada verdadeira
e a seq u encia de comandos ser a executada. Ao nal da sequ encia
de comandos, o uxo do programa e desviado novamente para a
condic ao;
se a condic ao for zero, ela ser a considerada falsa e a seq u encia de
comandos n ao ser a executada.
Abaixo, tem-se um exemplo de um programa que l e dois n umeros inteiros
a e b digitados pelo usu ario e imprime na tela todos os n umeros inteiros
entre a e b:
23
Exemplo: comando while
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt a , b ;
5 p r i n t f ( Di gi t e o val or de a : ) ;
6 scanf ( %d ,&a) ;
7 p r i n t f ( Di gi t e o val or de b : ) ;
8 scanf ( %d ,&b) ;
9 whil e ( a < b) {
10 a = a + 1;
11 p r i n t f ( %d \n , a) ;
12 }
13 system( pause ) ;
14 ret urn 0;
15 }
Relembrando a id eia de uxogramas, e possvel ter uma boa representac ao
de como os comandos do exemplo anterior s ao um-a-um executados du-
rante a execuc ao do programa:
O comando while segue todas as recomendac oes de-
nidas para o comando if quanto ao uso das chaves e
denic ao da condic ao usada.
24
Isso signica que a condic ao pode ser qualquer express ao que resulte
numa resposta do tipo falso (zero) ou verdadeiro (diferente de zero), e que
utiliza operadores dos tipos matem aticos, relacionais e/ou l ogicos.
Como nos comandos condicionais, o comando while atua apenas sobre o
comando seguinte a ele. Se quisermos que ele execute uma sequ encia
de comandos, e preciso denir essa sequ encia de comandos dentro de
chaves {}.
Como no comando if-else, n ao se usa o ponto e vrgula (;)
depois da condic ao do comando while.
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt a , b ;
5 p r i n t f ( Di gi t e o val or de a : ) ;
6 scanf ( %d ,&a) ;
7 p r i n t f ( Di gi t e o val or de b : ) ;
8 scanf ( %d ,&b) ;
9 whi le ( a < b) ; { / / ERRO!
10 a = a + 1;
11 p r i n t f ( %d \n , a) ;
12 }
13 system( pause ) ;
14 ret urn 0;
15 }
Como no caso dos comandos condicionais, colocar o operador de ponto e
vrgula (;) logo ap os o comando while, faz com que o compilador entenda
que o comando while j a terminou e trate o comando seguinte (a = a + 1)
como se o mesmo estivesse fora do while. No exemplo acima, temos um
laco innito (o valor de a e b nunca mudam, portanto a condic ao de parada
nunca e atingida).

E responsabilidade do programador modicar o valor de


algum dos elementos usados na condic ao para evitar que
ocorra um laco innito.
2.4 COMANDO FOR
O comando for e muito similar ao comando while visto anteriormente. Ba-
sicamente, o comando for e usado para repetir um comando, ou uma
25
sequ encia de comandos, diversas vezes.
A forma geral de um comando for e:
for (inicializac ao; condic ao; incremento) {
seq u encia de comandos;
}
Na execuc ao do comando for, a seguinte sequ encia de passo e realizada:
a cla usula inicializac ao e executada: nela as vari aveis recebem uma
valor inicial para usar dentro do for.
a condic ao e testada:
se a condic ao for diferente de zero, ela ser a considerada verda-
deira e a seq u encia de comandos ser a executada. Ao nal da
sequ encia de comandos, o uxo do programa e desviado para
o incremento;
se a condic ao for zero, ela ser a considerada falsa e a seq u encia
de comandos n ao ser a executada (m do comando for).
incremento: terminada a execuc ao da seq u encia de comandos, ocorre
a etapa de incremento das vari aveis usadas no for. Ao nal dessa
etapa, o uxo do programa e novamente desviado para a condic ao.
Abaixo, tem-se um exemplo de um programa que l e dois n umeros inteiros
a e b digitados pelo usu ario e imprime na tela todos os n umeros inteiros
entre a e b (incluindo a e b):
Exemplo: comando for
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt a , b , c ;
5 p r i n t f ( Di gi t e o val or de a : ) ;
6 scanf ( %d ,&a) ;
7 p r i n t f ( Di gi t e o val or de b : ) ;
8 scanf ( %d ,&b) ;
9 f or ( c = a ; c <= b ; c++) {
10 p r i n t f ( %d \n , c ) ;
11 }
12 system( pause ) ;
13 ret urn 0;
14 }
26
No exemplo acima, a vari avel c e inicializada como valor de a (c = a). Em
seguida, o valor de c e comparado com o valor de b (c <= b). Por m,
se a sequ encia de comandos foi executada, o valor da vari avel c ser a in-
crementado em uma unidade (c++). Relembrando a id eia de uxogramas,
e possvel ter uma boa representac ao de como os comandos do exemplo
anterior s ao um-a-um executados durante a execuc ao do programa:
O comando for segue todas as recomendac oes denidas
para o comando if e while quanto ao uso das chaves e
denic ao da condic ao usada.
Isso signica que a condic ao pode ser qualquer express ao que resulte
numa resposta do tipo falso (zero) ou verdadeiro (diferente de zero), e que
utiliza operadores dos tipos matem aticos, relacionais e/ou l ogicos.
Como nos comandos condicionais, o comando while atua apenas sobre o
comando seguinte a ele. Se quisermos que ele execute uma sequ encia
de comandos, e preciso denir essa sequ encia de comandos dentro de
chaves {}.
27
Exemplo: for versus while
for while
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt i , soma = 0;
5 f or ( i = 1; i <= 10; i
++) {
6 soma = soma + i ;
7 }
8 p r i n t f ( Soma = %d \n ,
soma) ;
9 system( pause ) ;
10 ret urn 0;
11 }
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt i , soma = 0;
5 i = 1
6 whi le ( i <= 10) {
7 soma = soma + i ;
8 i ++;
9 }
10 p r i n t f ( Soma = %d \n ,
soma) ;
11 system( pause ) ;
12 ret urn 0;
13 }
Dependendo da situac ao emque o comando for e utilizado, podemos omitir
qualquer uma de suas cl ausulas:
inicializac ao;
condic ao;
incremento.
Independente de qual cl ausula e omitida, o comando for
exige que se coloque os dois operadores de ponto e vrgula
(;).
O comando for exige que se coloque os dois operadores de ponto e vrgula
(;) pois e este operador que indica a separac ao entre as cl ausulas de
inicializac ao, condic ao e incremento. Sem elas, o compilador n ao tem cer-
teza de qual cl ausula foi omitida.
Abaixo, s ao apresentados tr es exemplos de comando for onde, em cada
um deles, uma das cl ausulas e omitida.
28
Exemplo: comando for sem inicializac ao
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt a , b , c ;
5 p r i n t f ( Di gi t e o val or de a : ) ;
6 scanf ( %d ,&a) ;
7 p r i n t f ( Di gi t e o val or de b : ) ;
8 scanf ( %d ,&b) ;
9 f or ( ; a <= b ; a++) {
10 p r i n t f ( %d \n , a) ;
11 }
12 system( pause ) ;
13 ret urn 0;
14 }
No exemplo acima, a vari avel a e utilizada nas cl ausulas de condic ao e in-
cremento do comando for. Como a vari avel a teve seu valor inicial denido
atrav es de um comando de leitura do teclado (scanf), n ao e necess ario a
etapa de inicializac ao do comando for para denir o seu valor.
Ao omitir a condic ao do comando for, criamos um laco in-
nito.
Para o comando for, a aus encia da cl ausula de condc ao e considerada
como uma condic ao que e sempre verdadeira. Sendo a condic ao sempre
verdadeira, n ao existe condic ao de parada para o comando for, o qual vai
ser executado innitamente.
Exemplo: comando for sem condic ao
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt a , b , c ;
5 p r i n t f ( Di gi t e o val or de a : ) ;
6 scanf ( %d ,&a) ;
7 p r i n t f ( Di gi t e o val or de b : ) ;
8 scanf ( %d ,&b) ;
9 / / o comando f or abai xo e um l ac o i n f i n i t o
10 f or ( c = a ; ; c++) {
11 p r i n t f ( %d \n , c ) ;
12 }
13 system( pause ) ;
14 ret urn 0;
15 }
29
Por ultimo, temos um exemplo de comando for sem a cl ausula de incre-
mento. Nessa etapa do comando for, um novo valor e atribuido para uma
(ou mais) var aveis utilizadas.
Exemplo: comando for sem incremento
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt a , b , c ;
5 p r i n t f ( Di gi t e o val or de a : ) ;
6 scanf ( %d ,&a) ;
7 p r i n t f ( Di gi t e o val or de b : ) ;
8 scanf ( %d ,&b) ;
9 f or ( c = a ; c <= b ; ) {
10 p r i n t f ( %d \n , c ) ;
11 c++;
12 }
13 system( pause ) ;
14 ret urn 0;
15 }
No exemplo acima, a cl ausula de incremento foi omtida da declarac ao do
comando for. Para evitar a criac ao de uma laco innito (onde a condic ao
de parada existe, mas nunca e atingida), foi colocado um comando de in-
cremento (c++) dentro da sequ encia de comandos do for. Perceba que,
desse modo, o comando for ca mais parecido com o comando while, j a
que agora se pode denir em qual momento o incremento vai ser execu-
tado, e n ao apenas no nal.
30
A cl ausula de incremento e utilizada para atribuir um novo
valor a uma ou mais vari aveis durante o comando for. Essa
atribuic ao n ao est a restrita a apenas o operador de incre-
mento (++).
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt a , b , c ;
5 p r i n t f ( Di gi t e o val or de a : ) ;
6 scanf ( %d ,&a) ;
7 p r i n t f ( Di gi t e o val or de b : ) ;
8 scanf ( %d ,&b) ;
9
10 / / i ncrement o de duas uni dades
11 f or ( c = a ; c <= b ; c=c+2) {
12 p r i n t f ( %d \n , c ) ;
13 }
14
15 / / novo val or e l i d o do t ecl ado
16 f or ( c = a ; c <= b ; scanf ( %d ,&c ) ) {
17 p r i n t f ( %d \n , c ) ;
18 }
19 system( pause ) ;
20 ret urn 0;
21 }
Nesse exemplo, ca claro que a cl ausula de incremento pode conter qual-
quer comando que altere o valor de uma das vari aveis utilizadas pelo co-
mando for.
O operador de vrgula (,) pode ser usado em qualquer uma
das cl ausulas.
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt i , j ;
5 f or ( i = 0 , j = 100; i < j ; i ++, j ){
6 p r i n t f ( i = %d e j = %d \n , i , j ) ;
7 }
8 system( pause ) ;
9 ret urn 0;
10 }
No exemplo acima, foram denidos dois comandos para a cl ausula de
31
inicializac ao: i = 0 e j = 100. Cada comando na inicializac ao e separado
pelo operador de vrgula (,). A cl ausula de inicializac ao s o termina quando
o operador de ponto e vrgula (;) e encontrado. Na fase de incremento,
novamente o valor das duas vari aveis e modicado: o valor de i e incre-
mentado (i++) enquanto o de j e decrementado (j). Novamente, cada
comando na cl ausula de incremento e separado pelo operador de vrgula
(,).
2.5 COMANDO DO-WHILE
O comando do-while e bastante semelhante ao comando while visto ante-
riormente. Sua principal diferenca e com relac ao a avaliac ao da condic ao:
enquanto o comando while avalia a condic ao para depois executar uma
seq u encia de comandos, o comando do-while executa uma seq u encia de
comandos para depois testar a condic ao.
A forma geral de um comando do-while e:
do{
seq u encia de comandos;
} while(condic ao);
Na execuc ao do comando do-while, a seguinte ordem de passos e execu-
tada:
a seq u encia de comandos e executada;
a condic ao e avaliada:
se a condic ao for diferente de zero, ela ser a considerada ver-
dadeira e o uxo do programa e desviado novamente para o
comando do, de modo que a seq u encia de comandos seja exe-
cutada novamente;
se a condic ao for zero, ela ser a considerada falsa e o laco ter-
mina.
O comando do-while e utilizado sempre que se desejar que
a seq u encia de comandos seja executada pelo menos uma
vez.
32
No comando while, a condic ao e sempre avaliada antes da seq u encia de
comandos. Isso signica que a condic ao pode ser falsa logo na primeira
repetic ao do comando while, o que faria com que a seq u encia de coman-
dos n ao fosse executada nenhuma vez. Portanto, o comando while pode
repetir uma seq u encia de comandos zero ou mais vezes.
J a no comando do-while, a seq u encia de comandos e executada primeiro.
Mesmo que a condic ao seja falsa logo na primeira repetic ao do comando
do-while, a seq u encia de comandos ter a sido executada pelo menos uma
vez. Portanto, o comando do-while pode repetir uma seq u encia de coman-
dos uma ou mais vezes.
O comando do-while segue todas as recomendac oes de-
nidas para o comando if quanto ao uso das chaves e
denic ao da condic ao usada.
Abaixo, tem-se umexemplo de umprograma que exibe ummenu de opc oes
para o usu ario e espera que ele digite uma das suas opc oes:
Exemplo: comando do-while
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt i ;
5 do {
6 p r i n t f ( Escol ha uma opc ao : \ n ) ;
7 p r i n t f ( ( 1) Opc ao 1\n ) ;
8 p r i n t f ( ( 2) Opc ao 2\n ) ;
9 p r i n t f ( ( 3) Opc ao 3\n ) ;
10 scanf ( %d , &i ) ;
11 } whi le ( ( i < 1) | | ( i > 3) ) ;
12 p r i n t f ( Voc e escol heu a Opc ao %d. \ n , i ) ;
13 system( pause ) ;
14 ret urn 0;
15 }
Relembrando a id eia de uxogramas, e possvel ter uma boa representac ao
de como os comandos do exemplo anterior s ao um-a-um executados du-
rante a execuc ao do programa:
33
Diferente do comando if-else, e necess ario colocar um
ponto e vrgula (;) depois da condic ao do comando do-
while.
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt i = 0;
5 do{
6 p r i n t f ( Val or %d\n , i ) ;
7 i ++;
8 }whi le ( i < 10) ; / / Esse ponto e v r gul a e
necess ar i o !
9 system( pause ) ;
10 ret urn 0;
11 }
No comando do-while, a seq u encia de comandos e denida antes do teste
da condic ao, diferente dos outros comando condicionais e de repetic ao.
Isso signica que o teste da condic ao e o ultimo comando da repetic ao
do-while. Sendo assim, o compilador entende que a denic ao do comando
do-while j a terminou e exige que se coloque o operador de ponto e vrgula
(;) ap os a condic ao.

E responsabilidade do programador modicar o valor de


algum dos elementos usados na condic ao para evitar que
ocorra um laco innito.
34
2.6 COMANDO BREAK
Vimos, anteriormente, que o comando break pode ser utilizado em con-
junto com o comando switch. Basicamente, sua func ao era interromper o
comando switch assim que uma das seq u encias de comandos da cl ausula
case fosse executada. Caso o comando break n ao existisse, a seq u encia
de comandos do case seguinte tamb em seria executada e assim por di-
ante.
Na verdade, o comando break serve para quebrar a execuc ao de um co-
mando (como no caso do switch) ou interromper a execuc ao de qualquer
comando de laco (for, while ou do-while). O break faz com que a execuc ao
do programa continue na primeira linha seguinte ao laco ou bloco que est a
sendo interrompido.
O comando break e utilizado para terminar abruptamente
uma repetic ao. Por exemplo, se estivermos em uma
repetic ao e um determinado resultado ocorrer, o programa
dever a sair da iterac ao.
Abaixo, tem-se um exemplo de um programa que l e dois n umeros inteiros
a e b digitados pelo usu ario e imprime na tela todos os n umeros inteiros
entre a e b. Note que no momento em que o valor de a atige o valor de b),
o comando break e chamado e o laco terminado:
Exemplo: comando break
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt a , b ;
5 p r i n t f ( Di gi t e o val or de a : ) ;
6 scanf ( %d ,&a) ;
7 p r i n t f ( Di gi t e o val or de b : ) ;
8 scanf ( %d ,&b) ;
9 whil e ( a <= b) {
10 i f ( a == b)
11 break ;
12 a = a + 1;
13 p r i n t f ( %d \n , a) ;
14 }
15 system( pause ) ;
16 ret urn 0;
17 }
Relembrando o conceito de uxogramas, e possvel ter uma boa representac ao
35
de como os comandos do exemplo anterior s ao um-a-um executados pelo
programa:
2.7 COMANDO CONTINUE
O comando continue e muito parecido com o comando break. Tanto o co-
mando break quanto o comando continue ignoram o restante da sequ encia
de comandos da repetic ao que os sucedem. A diferenca e que, enquanto o
comando break termina o laco de repetic ao, o comando break interrompe
apenas aquela repetic ao e passa para a proxima repetic ao do laco (se ela
existir).
Por esse mesmo motivo, o comando continue s o pode ser utilizado dentro
de um laco.
Os comandos que sucedem o comando continue no bloco
n ao s ao executados.
Abaixo, tem-se um exemplo de um programa que l e, repetidamente, um
n umero inteiro do usu ario e a imprime apenas se ela for maior ou igual a
1 e menor ou igual a 5. Caso o n umero n ao esteja nesse intervalo, essa
repetic ao do laco e desconsiderada e reiniciada:
36
Exemplo: comando continue
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt opcao = 0;
5 whil e ( opcao ! = 5) {
6 p r i n t f ( Escol ha uma opcao ent r e 1 e 5: ) ;
7 scanf ( %d , &opcao ) ;
8 i f ( ( opcao > 5) | | ( opcao < 1) )
9 continue ;
10 p r i n t f ( Opcao escol hi da : %d , opcao ) ;
11 }
12 system( pause ) ;
13 ret urn 0;
14 }
Relembrando o conceito de uxogramas, e possvel ter uma boa representac ao
de como os comandos do exemplo anterior s ao um-a-um executados pelo
programa:
2.8 GOTO E LABEL
O comando goto e um salto condicional para um local especicado por
uma palavra chave no c odigo. A forma geral de um comando goto e:
destino:
goto destino;
37
Na sintaxe acima, o comando goto (do ingl es go to, literalmente ir para)
muda o uxo do programa para um local previamente especicado pela ex-
press ao destino, onde destino e uma palavra denida pelo programador.
Este local pode ser a frente ou atr as no programa, mas deve ser dentro da
mesma func ao.
O teorema da programac ao estruturada prova que a instruc ao goto n ao e
necess aria para escrever programas; alguma combinac ao das tr es construc oes
de programac ao (comandos sequenciais, condicionais e de repetic ao) s ao
sucientes para executar qualquer c alculo. Al em disso, o uso de goto pode
deixar o programa muitas vezes ilegvel.
Exemplo: goto versus for
goto for
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt i = 0;
5 i n i c i o :
6 i f ( i < 5) {
7 p r i n t f ( Numero %d\n
, i ) ;
8 i ++;
9 goto i n i c i o ;
10 }
11 system( pause ) ;
12 ret urn 0;
13 }
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt i ;
5 f or ( i = 0; i < 5; i ++)
6 p r i n t f ( Numero %d\n
, i ) ;
7
8 system( pause ) ;
9 ret urn 0;
10 }
Como se nota no exemplo acima, o mesmo programa feito com o comando
for e muito mais f acil de entender do que o mesmo programa feito com o
comando goto.
38
Apesar de banido da pr atica de programac ao, o comando
goto pode ser util em determinadas circunst ancias. Ex: sair
de dentro de lacos aninhados.
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt i , j , k ;
5 f or ( i = 0; i < 5; i ++)
6 f or ( j = 0; j < 5; j ++)
7 f or ( k = 0; k < 5; k++)
8 i f ( i == 2 && j == 3 && k == 1)
9 goto f i m ;
10 el se
11 p r i n t f ( Posi cao [%d,%d,%d] \ n
, i , j , k ) ;
12
13
14 f i m :
15 p r i n t f ( Fim do programa\n ) ;
16
17 system( pause ) ;
18 ret urn 0;
19 }
39
3 VETORES E MATRIZES - ARRAYS
3.1 EXEMPLO DE USO
Um array ou vetor e a forma mais comum de dados estruturados da lin-
guagem C. Um array e simplesmente um conjunto de vari aveis do mesmo
tipo, igualmente acessveis por um ndice.
Imagine o seguinte problema: dada uma relac ao de 5 es-
tudantes, imprimir o nome de cada estudante, cuja nota e
maior do que a m edia da classe.
Um algoritmo simples para resolver esse problema poderia ser o pseudo-
c odigo apresentado abaixo:
Leia(nome1, nome2, nome3, nome4, nome5);
Leia(nota1, nota2, nota3, nota4, nota5);
media = (nota1+nota2+nota3+nota4+nota5) / 5,0;
Se nota1 > media ent ao escreva (nome1)
Se nota2 > media ent ao escreva (nome2)
Se nota3 > media ent ao escreva (nome3)
Se nota4 > media ent ao escreva (nome4)
Se nota5 > media ent ao escreva (nome5)
O algoritmo anterior representa uma soluc ao possvel para o problema. O
grande inconveniente dessa soluc ao e a grande quantidade de vari aveis
para gerenciarmos e o uso repetido de comandos praticamente id enticos.
Essa soluc ao e invi avel para uma lista de 100 alunos.
Expandir o algoritmo anterior para trabalhar com um total de 100 alunos
signicaria, basicamente, aumentar o n umero de vari aveis para guardar
os dados de cada aluno e repetir, ainda mais, um conjunto de comandos
praticamente id enticos. Desse modo, teriamos:
40
Uma vari avel para armazenar cada nome de aluno: 100 vari aveis;
Uma vari avel para armazenar a nota de cada aluno: 100 vari aveis;
Um comando de teste e impress ao na tela para cada aluno: 100
testes.
O pseudo-c odigo abaixo representa o algoritmo anterior expandido para
poder trabalhar com 100 alunos:
Leia(nome1, nome2, ..., nome100);
Leia(nota1, nota2,..., nota100);
media = (nota1+nota2+...+nota100) / 100,0;
Se nota1 > media ent ao escreva (nome1)
Se nota2 > media ent ao escreva (nome2)
...
Se nota100 > media ent ao escreva (nome100)
Como se pode notar, temos uma soluc ao extremamente engessada para
o nosso problema. Modicar o n umero de alunos usado pelo algoritmo
implica em reescrever todo o c odigo, repetindo comandos praticamente
id enticos. Al em disso, temos uma grande quantidade de vari aveis para
gerenciar, cada uma com o seu pr oprio nome, o que torna essa tarefa
ainda mais difcil de ser realizada sem a ocorr encia de erros.
Como estes dados t em uma relac ao entre si, podemos de-
clar a-los usando um

UNICO nome para todos os 100 ele-
mentos.
Surge ent ao a necessidade de usar um array.
3.2 ARRAY COM UMA DIMENS

AO - VETOR
A id eia de um array ou vetor e bastante simples: criar um conjunto de
vari aveis do mesmo tipo utilizando apenas um nome.
Relembrando o exemplo anterior, onde as vari aveis que guardam as notas
dos 100 alunos s ao todas do mesmo tipo, essa soluc ao permitiria usar
apenas um nome (notas, por exemplo) de vari avel para representar todas
as notas dos alunos, ao inv es de um nome para cada vari avel.
41
Em linguagem C, a declarac ao de um array segue a seguinte forma geral:
tipo dado nome array[tamanho];
O comando acima dene um array de nome nome array contendo tama-
nho elementos adjacentes na mem oria. Cada elemento do array e do tipo
tipo dado. Pensando no exemplo anterior, poderamos usar uma array de
inteiros contendo 100 elementos para guardar as notas dos 100 alunos:
int notas[100];
Como cada nota do aluno possui agora o mesmo nome que as demais
notas dos outros alunos, o acesso ao valor de cada nota e feito utilizando
um ndice.
Para indicar qual ndice do array queremos acessar, utiliza-
se o operador de colchetes [ ].
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt not as [ 100] ;
5 i nt i ;
6 f or ( i = 0; i < 100; i ++) {
7 p r i n t f ( Di gi t e a not a do al uno %d , i ) ;
8 scanf ( %d ,&not as [ i ] ) ;
9 }
10 system( pause ) ;
11 ret urn 0;
12 }
No exemplo acima, percebe-se que cada posic ao do array possui todas
as caractersticas de uma vari avel. Isso signica que ela pode aparecer
em comandos de entrada e sada de dados, express oes e atribuic oes. Por
exemplo:
42
scanf(%d,&notas[5]);
notas[0] = 10;
notas[1] = notas[5] + notas[0];
O tempo para acessar qualquer uma das posic oes do array
e o mesmo.
Lembre-se, cada posic ao do array e uma vari avel. Portanto, todas as
posic oes do array s ao igualmente acessveis, isto e, o tempo e o tipo de
procedimento para acessar qualquer uma das posic oes do array s ao iguais
ao de qualquer outra vari avel.
Na linguagem C a numerac ao comeca sempre do ZERO e
termina em N-1, onde N e o n umero de elementos do array.
Isto signica que, no exemplo anterior, as notas dos alunos ser ao indexa-
das de 0 a 99:
notas[0]
notas[1]
...
notas[99]
Isso acontece pelo seguinte motivo: um array e um agrupamento de da-
dos, do mesmo tipo, adjacentes na mem oria. O nome do array indica
onde esses dados comecam na mem oria. Ondice do array indica quantas
posic oes se deve pular para acessar uma determinada posic ao. A gura
abaixo exemplica como o array est a na mem oria:
Num array de 100 elementos, ndices menores do que
0 e maiores do que 99 tamb em podem ser acessados.
Por em, isto pode resultar nos mais variados erros durante
a execuc ao do programa.
Como foi explicado, um array e um agrupamento de dados adjacentes na
mem oria e o seu ndice apenas indica quantas posic oes se deve pular para
43
acessar uma determinada posic ao. Isso signica que se tentarmos acessar
o ndice 100, o programa tentar a acessar a cent esima posic ao a partir da
posic ao inicial (que e o nome do array). O mesmo vale para a posic ao de
ndice -1. Nesse caso o programa tentar a acessar uma posic ao anterior ao
local onde o array comeca na mem oria. O problema e que, apesar dessas
posic oes existirem na mem oria e serem acessveis, elas n ao pertencer ao
array. Pior ainda, elas podem pertencer a outras vari aveis do programa, e
a alterac ao de seus valores pode resultar nos mais variados erros durante
a execuc ao do programa.

E func ao do programador garantir que os limites do array


est ao sendo respeitados.
Deve-se tomar cuidado ao se rabalhar com arrays. Prncipalmente ao se
usar a operac ao de atribuic ao (=).
44
N ao se pode fazer atribuic ao de arrays.
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt v [ 5 ] = {1 , 2 , 3 , 4 , 5};
5 i nt v1 [ 5 ] ;
6 v1 = v ; / / ERRO!
7
8 system( pause ) ;
9 ret urn 0;
10 }
Isso ocorre porque a linguagem C n ao suporta a atribuic ao de um array
para outro. Para atribuir o conte udo de um array a outro array, o correto e
copiar seus valores elemento por elemento para o outro array.
3.3 ARRAY COM DUAS DIMENS

OES - MATRIZ
Os arrays declarados at e o momento possuem apenas uma dimens ao. H a
casos, em que uma estrutura com mais de uma dimens ao e mais util. Por
exemplo, quando trabalhamos com matrizes, onde os valores s ao organi-
zados em uma estrutura de linhas e colunas.
Em linguagem C, a declarac ao de uma matriz segue a seguinte forma ge-
ral:
tipo dado nome array[nro linhas][nro colunas];
Ocomando acima dene umarray de nome nome array contendo nro linhas
nro colunas elementos adjacentes na mem oria. Cada elemento do array
e do tipo tipo dado.
Por exemplo, para criar um array de inteiros que possua 100 linhas e
50 colunas, isto e, uma matriz de inteiros de tamanho 10050, usa-se
a declarac ao abaixo:
int mat[100][50];
Como no caso dos arrays de uma unica dimens ao, cada posic ao da ma-
triz possui todas as caractersticas de uma vari avel. Isso signica que ela
45
pode aparecer em comandos de entrada e sada de dados, express oes e
atribuic oes:
scanf(%d,&mat[5][0]);
mat[0][0] = 10;
mat[1][2] = mat[5][0] + mat[0][0];
Perceba, no entanto, que o acesso ao valor de uma posic ao da matriz e
feito agora utilizando dois ndices: um para a linha e outro para a coluna.
Lembre-se, cada posic ao do array e uma vari avel. Portanto, todas as
posic oes do array s ao igualmente acessveis, isto e, o tempo e o tipo de
procedimento para acessar qualquer uma das posic oes do array s ao iguais
ao de qualquer outra vari avel.
3.4 ARRAYS MULTIDIMENSIONAIS
Vimos at e agora como criar arrays com uma ou duas dimens oes. A lingua-
gem C permite que se crie arrays com mais de duas dimens oes de maneira
f acil.
Na linguagem C, cada conjunto de colchetes [ ] representa
uma dimens ao do array.
Cada par de colchetes adicionado ao nome de uma vari avel durante a sua
declarac ao adiciona uma nova dimens ao ` aquela vari avel, independente do
seu tipo:
int vet[5]; // 1 dimens ao
46
oat mat[5][5]; // 2 dimens oes
double cub[5][5][5]; // 3 dimens oes
int X[5][5][5][5]; // 4 dimens oes
O acesso ao valor de uma posic ao de um array multidimen-
sional e feito utilizando um ndice para cada dimens ao do
array.
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt cub [ 5 ] [ 5 ] [ 5 ] ;
5 i nt i , j , k ;
6 / / preenche o ar r ay de 3 dimens oes com zeros
7 f or ( i =0; i < 5; i ++) {
8 f or ( j =0; j < 5; j ++) {
9 f or ( k=0; k < 5; k++) {
10 cub [ i ] [ j ] [ k ] = 0;
11 }
12 }
13 }
14
15 system( pause ) ;
16 ret urn 0;
17 }
Apesar de terem o comportamento de estruturas com mais de uma di-
mens ao, os dados dos arrays multidimensionais s ao armazenados line-
armente na mem oria.

E o uso dos colchetes que cria a impress ao de
estarmos trabalhando com mais de uma dimens ao.
Por esse motivo, e importante ter em mente qual a dimens ao que se move
mais rapidamente na mem oria: sempre a mais a direita, independente do
tipo ou n umero de dimens oes do array, como se pode ver abaixo marcado
em vermelho:
47
int vet[5]; // 1 dimens ao
oat mat[5][5]; // 2 dimens oes
double cub[5][5][5]; // 3 dimens oes
int X[5][5][5][5]; // 4 dimens oes
Basicamente, um array multidimensional funciona como
qualquer outro array. Basta lembrar que o ndice que va-
ria mais rapidamente e o ndice mais ` a direita.
3.5 INICIALIZAC

AO DE ARRAYS
Um array pode ser inicializado com certos valores durante sua declarac ao.
Isso pode ser feito com qualquer array independente do tipo ou n umero de
dimens oes do array.
A forma geral de inicializac ao de um array e:
tipo dado nome array[tam1][tam2]...[tamN] = {dados };
Na declarac ao acima, dados e uma lista de valores (do mesmo tipo do ar-
ray) separados por vrgula e delimitado pelo operador de chaves {}. Esses
valores devem ser colocados na mesma ordem em que ser ao colocados
dentro do array.
A inicializac ao de uma array utilizando o operador de cha-
ves {}s o pode ser feita durante sua declarac ao.
A inicializac ao de uma array consiste em atribuir um valor inicial a cada
posic ao do array. O operador de chaves apenas facilita essa tarefa, como
mostra o exemplo abaixo:
48
Exemplo: inicializando um array
Com o operador de {} Sem o operador de {}
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt vet [ 5 ] =
{15 , 12 , 91 , 35};
5
6 system( pause ) ;
7 ret urn 0;
8 }
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt vet [ 5 ] ;
5 vet [ 0 ] = 15;
6 vet [ 1 ] = 12;
7 vet [ 2 ] = 9;
8 vet [ 3 ] = 1;
9 vet [ 4 ] = 35;
10
11 system( pause ) ;
12 ret urn 0;
13 }
Abaixo s ao apresentados alguns exemplos de inicializac ao de arrays de
diferentes tipos e n umero de dimens oes:
Exemplos: inicializando um array
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt mat r i z1 [ 3 ] [ 4 ] = {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12};
5 i nt mat r i z2 [ 3 ] [ 4 ] = {{1 , 2 , 3 , 4} , {5 , 6 , 7 , 8} , {9 , 10 , 11 , 12}};
6
7 char st r 1 [ 10] = { J , o , a , o , \0 };
8 char st r 2 [ 10] = Joao ;
9
10 char s t r mat r i z [ 3 ] [ 1 0 ] = { Joao , Mari a , Jose };
11
12 system( pause ) ;
13 ret urn 0;
14 }
Note no exemplo acima que a inicializac ao de um array de 2 dimens oes
pode ser feita de duas formas distintas. Na primeira matriz (matriz1) os
valores iniciais da matriz s ao denidos utilizando um unico conjunto de
chaves {}, igual ao que e feito com vetores. Nesse caso, os valores s ao
atribudos para todas as colunas da primeira linha da matriz, para depois
passar para as colunas da segunda linha e assim por diante. Lembre-se,
a dimens ao que se move mais rapidamente na mem oria e sempre a mais
a direita, independente do tipo ou n umero de dimens oes do array. J a na
segunda matriz (matriz2) usa-se mais de um conjunto de chaves {}para
denir cada uma das dimens oes da matriz.
49
Para a inicializac ao de um array de caracteres, pode-se usar o mesmo
princpio denido na inicializac ao de vetores (str1). Percebe-se que essa
forma de inicializac ao n ao e muito pr atica. Por isso, a inicializac ao de um
array de caracteres tamb em pode ser feita por meio de aspas duplas,
como mostrado na inicializac ao de str2. O mesmo princpio e v alido para
iniciar um array de caracteres de mais de uma dimens ao.
Na inicializac ao de um array de caracteres n ao e ne-
cess ario denir todos os seus elementos.
3.5.1 INICIALIZAC

AO SEM TAMANHO
A linguagem C tamb em permite inicializar um array sem que tenhamos
denido o seu tamanho. Nesse caso, simplesmente n ao se coloca o valor
do tamanho entre os colchetes durante a declarac ao do array:
tipo dado nome array[ ] = {dados };
Nesse tipo de inicializac ao, o compilador da linguagem C vai considerar o
tamanho do dado declarado como sendo o tamanho do array. Isto ocorre
durante a compilac ao do programa. Depois disso, o tamanho do array n ao
poder a mais ser modicado durante o programa.
Abaixo s ao apresentados alguns exemplos de inicializac ao de arrays sem
tamanhos:
Exemplos: inicializando um array sem tamanho
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 / / A s t r i ng t ext o t er a tamanho 13
5 / / (12 car act er es + o car act er e \0 )
6 char t ext o [ ] = Linguagem C. ;
7
8 / / O n umero de posi c oes do vet or ser a 10.
9 i nt vet or [ ] = {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10};
10
11 / / O n umero de l i nhas de mat r i z ser a 5.
12 i nt mat r i z [ ] [ 2 ] = {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10};
13
14 system( pause ) ;
15 ret urn 0;
16 }
50
Note no exemplo acima que foram utilizados 12 caracteres para iniciar o
array de char texto. Por em, o seu tamanho nal ser a 13. Isso ocorre por
que arrays de caracteres sempre possuem o elemento seguinte ao ultimo
caractere como sendo o caractere \0. Mais detalhes sobre isso podem
ser vistos na sec ao seguinte.
Esse tipo de inicializac ao e muito util quando n ao queremos
contar quantos caracteres ser ao necess arios para iniciali-
zarmos uma string (array de caracteres).
No caso da inicializac ao de arrays de mais de uma dimens ao, e necess ario
sempre denir as demais dimens oes. Apenas a primeira dimens ao pode
car sem tamanho denido.
3.6 EXEMPLO DE USO DE ARRAYS
Nesta sec ao s ao apresentados alguns exemplos de operac oes b asicas de
manipulac ao de vetores e matrizes em C.
Somar os elementos de um vetor de 5 inteiros
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt i , l i s t a [ 5 ] = {3 , 51 , 18 , 2 , 45};
5 i nt soma = 0;
6 f or ( i =0; i < 5; i ++)
7 soma = soma + l i s t a [ i ] ;
8 p r i n t f ( Soma = %d , soma) ;
9 system( pause ) ;
10 ret urn 0;
11 }
51
Encontrar o maior valor contido em um vetor de 5 inteiros
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt i , l i s t a [ 5 ] = {3 , 18 , 2 , 51 , 45};
5 i nt Mai or = l i s t a [ 0 ] ;
6 f or ( i =1; i <5; i ++) {
7 i f ( Mai or < l i s t a [ i ] )
8 Mai or = l i s t a [ i ] ;
9 }
10 p r i n t f ( Mai or = %d , Mai or ) ;
11 system( pause ) ;
12 ret urn 0;
13 }
Calcular a m edia dos elementos de um vetor de 5 inteiros
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt i , l i s t a [ 5 ] = {3 , 51 , 18 , 2 , 45};
5 i nt soma = 0;
6 f or ( i =0; i < 5; i ++)
7 soma = soma + l i s t a [ i ] ;
8 f l oat media = soma / 5. 0;
9 p r i n t f ( Media = %f , media ) ;
10 system( pause ) ;
11 ret urn 0;
12 }
Somar os elementos de uma matriz de inteiros
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt mat [ 3 ] [ 3 ] = {{1 , 2 , 3} , {4 , 5 , 6} , {7 , 8 , 9}};
5 i nt i , j , soma = 0;
6 f or ( i =0; i < 3; i ++)
7 f or ( j =0; j < 3; j ++)
8 soma = soma + mat [ i ] [ j ] ;
9 p r i n t f ( Soma = %d , soma) ;
10 system( pause ) ;
11 ret urn 0;
12 }
52
Imprimir linha por linha uma matriz
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt mat [ 3 ] [ 3 ] = {{1 , 2 , 3} , {4 , 5 , 6} , {7 , 8 , 9}};
5 i nt i , j ;
6 f or ( i =0; i < 3; i ++) {
7 f or ( j =0; j < 3; j ++)
8 p r i n t f ( %d , mat [ i ] [ j ] ) ;
9 p r i n t f ( \n ) ;
10 }
11 system( pause ) ;
12 ret urn 0;
13 }
53
4 ARRAYS DE CARACTERES - STRINGS
4.1 DEFINIC

AO E DECLARAC

AO DE STRINGS
String e o nome que usamos para denir uma seq u encia de caracteres ad-
jacentes na mem oria do computador. Essa seq u encia de caracteres, que
pode ser uma palavra ou frase, e armazenada na mem oria do computador
na forma de um arrays do tipo char.
Sendo a string um array de caracteres, sua declarac ao segue as mesmas
regras da declarac ao de um array convecnional:
char str[6];
A declarac ao acima cria na mem oria do computador uma string (array de
caracteres) de nome str e tamanho igual a 6. No entanto, apesar de ser um
array, devemos car atentos para o fato de que as strings t em no elemento
seguinte a ultima letra da palavra/frase armazenada um caractere \0.
O caractere \0 indica o m da seq u encia de caracteres.
Isso ocorre por que podemos denir uma string com um tamanho maior
do que a palavra armazenada. Imagine uma string denida com um tama-
nho de 50 caracteres, mas utilizada apenas para armazenar a palavra oi.
Nesse caso, temos 48 posic oes n ao utilizadas e que est ao preenchidas
com lixo de mem oria (um valor qualquer). Obviamente, n ao queremos
que todo esse lixo seja considerado quando essa string for exibida na tela.
Assim, o caractere \0 indica o m da seq u encia de caracteres e o incio
das posic oes restantes da nossa string que n ao est ao sendo utilizadas
nesse momento.
Ao denir o tamanho de uma string, devemos considerar o
caractere \0.
54
Como o caractere \0 indica o nal de nossa string, isso signica que numa
string denida com um tamanho de 50 caracteres, apenas 49 estar ao dis-
ponveis para armazenar o texto digitado pelo usu ario.
Uma string pode ser lida do teclado ou j a ser denida com um valor ini-
cial. Para sua inicializac ao, pode-se usar o mesmo princpio denido na
inicializac ao de vetores e matrizes:
char str [10] = {J, o, a, o, \0 };
Percebe-se que essa forma de inicializac ao n ao e muito pr atica. Por isso, a
inicializac ao de strings tamb em pode ser feita por meio de aspas duplas:
char str [10] = Joao;
Essa forma de inicializac ao possui a vantagem de j a inserir o caractere \0
no nal da string.
Outro ponto importante na manipulac ao de strings e que, por se tratar de
umarray, cada caractere pode ser acessado individualmente por indexac ao
como em qualquer outro vetor ou matriz:
char str[6] = Teste;
str[0] = L;
Na atribuic ao de strings usa-se aspas duplas, enquanto
que na de caracteres, usa-se aspas simples.
55
4.2 TRABALHANDO COM STRINGS
O primeiro cuidado que temos que tomar ao se trabalhar com strings e na
operac ao de atribuic ao.
Strings s ao arrays. Portanto, n ao se pode fazer atribuic ao
de strings.
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 char st r 1 [ 20] = Hel l o World ;
5 char st r 2 [ 2 0 ] ;
6
7 st r 1 = st r 2 ; / / ERRO!
8
9 system( pause ) ;
10 ret urn 0;
11 }
Isso ocorre porque uma string e um array e a linguagem C n ao suporta a
atribuic ao de um array para outro. Para atribuir o conte udo de uma string a
outra, o correto e copiar a string elemento por elemento para a outra string.
Exemplo: Copiando uma string
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt count ;
5 char st r 1 [ 20] = Hel l o World , st r 2 [ 2 0 ] ;
6 f or ( count = 0; st r 1 [ count ] ! = \0 ; count ++)
7 st r 2 [ count ] = st r 1 [ count ] ;
8 st r 2 [ count ] = \0 ;
9 system( pause ) ;
10 ret urn 0;
11 }
O exemplo acima permite copiar uma string elemento por elemento para
outra string. Note que foi utilizada a mesma forma de indexac ao que seria
feita com um array de qualquer outro tipo (int, oat, etc). Infelizmente,
esse tipo de manipulac ao de arrays n ao e muito pr atica quando estamos
trabalhando com palavras.
56
Felizmente, a biblioteca padr ao da linguagem C possui
func oes especialmente desenvolvidas para a manipulac ao
de strings na bibloteca <string.h>.
A seguir, ser ao apresentadas algumas das func oes mais utilizadas para a
leitura, escrita e manipulac ao de strings.
4.2.1 LENDO UMA STRING DO TECLADO
Existem v arias maneiras de se fazer a leitura de uma sequ encia de carac-
teres do teclado. Uma delas e utilizando o j a conhecido comando scanf()
com o formato de dados %s:
char str[20];
scanf(%s,str);
Quando usamos o comando scanf() para ler uma string, o
smbolo de & antes do nome da vari avel n ao e utilizado.
Infelizmente, para muitos casos, o comando scanf() n ao e a melhor opc ao
para se ler uma string do teclado.
O comando scanf() l e apenas strings digitadas sem
espacos, ou seja palavras.
No caso de ter sido digitada uma frase (uma sequ encia de caracteres con-
tendo espacos) apenas os caracteres digitados antes do primeiro espaco
encontrado ser ao armazenados na string.
Uma alternativa mais eciente para a leitura de uma string e a func ao
gets(), a qual faz a leitura do teclado considerando todos os caracteres
digitados (incluindo os espacos) at e encontrar uma tecla enter:
char str[20];
gets(str);
57
` as vezes, podem ocorrer erros durante a leitura de caracteres ou strings
do teclado. Para resolver esse pequenos erros, podemos limpar o buffer
do teclado (entrada padr ao) usando a func ao setbuf(stdin, NULL) antes
de realizar a leitura de caracteres ou strings:
Exemplo: limpando o buffer do teclado
leitura de caracteres leitura de strings
1 char ch ;
2 set buf ( st di n , NULL) ;
3 scanf ( %c , &ch ) ;
1 char s t r [ 1 0 ] ;
2 set buf ( st di n , NULL) ;
3 get s ( s r t ) ;
Basicamente, a func ao setbuf preenche um buffer (primeiro par ametro)
com um determinado valor (segundo par ametro). No exemplo acima, o
buffer da entrada padr ao (stdin) e preenchido com o valor vazio (NULL).
Na linguagem C a palavra NULL e uma constante padr ao que signica um
valor nulo. Um buffer preenchido com NULL e considerado limpo/vazio.
Basicamente, para se ler uma string do teclado utilizamos a func ao gets().
No entanto, existe outra func ao que, utilizada de forma adequada, tamb em
permite a leitura de strings do teclado. Essa func ao e a fgets(), cujo
prot otipo e:
char *fgets (char *str, int tamanho,FILE *fp);
A func ao fgets() recebe 3 par ametros de entrada
str: a string a ser lida;
tamanho: o limite m aximo de caracteres a serem lidos;
fp: a vari avel que est a associado ao arquivo de onde a string ser a
lida.
e retorna
NULL: no caso de erro ou m do arquivo;
O ponteiro para o primeiro caractere da string recuperada em str.
Note que a func ao fgets utiliza uma vari avel FILE *fp, que est a associado
ao arquivo de onde a string ser a lida.
58
Para ler do teclado, basta substituir FILE *fp por stdin,
o qual representa o dispositivo de entrada padr ao (geral-
mente o teclado).
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 char nome[ 3 0 ] ;
5 p r i n t f ( Di gi t e um nome: ) ;
6 f get s ( nome, 30, st di n ) ;
7 p r i n t f ( O nome di gi t ado f o i : %s , nome) ;
8 system( pause ) ;
9 ret urn 0;
10 }
Como a func ao gets(), a func ao fgets() l e a string do teclado at e que um
caractere de nova linha (enter) seja lido. Apesar de parecerem iguais, a
func ao fgets possui algumas diferencas e vantagens sobre a gets
Se o caractere de nova linha (\n) for lido, ele far a parte da
string, o que n ao acontecia com gets.
A func ao gets() armazena tudo que for digitado at e o comando de enter.
J a a func ao fgets() armazena tudo que for digitado, incluindo o comando
de enter (\n).
A func ao fgets() especca o tamanho m aximo da string de
entrada.
Diferente da func ao gets(), a func ao fgets() l e a string at e que um caractere
de nova linha seja lido ou tamanho-1 caracteres tenham sido lidos. Isso
evita o estouro do buffer, que ocorre quando se tenta ler algo maior do que
pode ser armazenado na string.
4.2.2 ESCREVENDO UMA STRING NA TELA
Basicamente, para se escrever uma string na tela utilizamos a func ao
printf() com o formato de dados %s:
59
char str[20] = Hello World;
printf(%s,str);
Para escrever uma string, utilizamos o tipo de sada %s.
No entanto, existe uma outra func ao que, utilizada de forma adequada,
tamb empermite a escrita de strings. Essa func ao e a fputs(), cujo prot otipo
e:
int fputs (char *str,FILE *fp);
A func ao fputs() recebe 2 par ametros de entrada
str: a string (array de caracteres) a ser escrita na tela;
fp: a vari avel que est a associado ao arquivo onde a string ser a es-
crita.
e retorna
a constante EOF (em geral, -1), se houver erro na escrita;
um valor diferente de ZERO, se o texto for escrito com sucesso.
Note que a func ao fputs utiliza uma vari avel FILE *fp, que est a associado
ao arquivo onde a string ser a escrita.
Para escrever no monitor, basta substituir FILE *fp por st-
dout, o qual representa o dispositivo de sada padr ao (ge-
ralmente a tela do monitor).
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 \ t ex t bf {char} t ext o [ 30] = Hel l o World\n ;
5 f put s ( t ext o , st dout ) ;
6 system( pause ) ;
7 ret urn 0;
8 }
60
4.3 FUNC

OES PARA MANIPULAC

AO DE STRINGS
A biblioteca padr ao da linguagem C possui func oes especialmente desen-
volvidas para a manipulac ao de strings na bibloteca <string.h>. A seguir
s ao apresentadas algumas das mais utilizadas.
4.3.1 TAMANHO DE UMA STRING
Para se obter o tamanho de uma string, usa-se a func ao strlen():
char str[15] = teste;
printf(%d,strlen(str));
Neste caso, a func ao retornar a 5, que e o n umero de caracteres na palavra
testee n ao 15, que e o tamanho do array de caracteres.
A func ao strlen() retorna o n umero de caracteres at e o ca-
ractere \0, e n ao o tamanho do array onde a string est a
armazenada.
4.3.2 COPIANDO UMA STRING
Vimos que uma string e um array e que a linguagem C n ao suporta a
atribuic ao de um array para outro. Nesse sentido, a unica maneira de atri-
buir o conte udo de uma string a outra e a copia, elemento por elemento,
de uma string para outra. A linguagem C possui uma func ao que realiza
essa tarefa para n os: a func ao strcpy():
strcpy(char *destino, char *origem)
Basicamente, a func ao strcpy() copia a seq u encia de caracteres contida
em origem para o array de caracteres destino:
61
Exemplo: strcpy()
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 char st r 1 [ 100] , st r 2 [ 100] ;
5 p r i n t f ( Ent r e com uma s t r i ng : ) ;
6 get s ( st r 1 ) ;
7 st r cpy ( st r 2 , st r 1 ) ;
8 system( pause ) ;
9 ret urn 0;
10 }
Para evitar estouro de buffer, o tamanho do array destino
deve ser longo o suciente para conter a seq u encia de ca-
racteres contida em origem.
4.3.3 CONCATENANDO STRINGS
A operac ao de concatenac ao e outra tarefa bastante comum ao se tra-
balhar com strings. Basicamente, essa operac ao consistem em copiar
uma string para o nal de outra string. Na linguagem C, para se fazer a
concatenac ao de duas strings, usa-se a func ao strcat():
strcat(char *destino, char *origem)
Basicamente, a func ao strcat() copia a seq u encia de caracteres contida
em origem para o nal da string destino. O primeiro caractere da string
contida em origem e colocado no lugar do caractere \0 da string destino:
Exemplo: strcat()
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 char st r 1 [ 15] = bom ;
5 char st r 2 [ 15] = di a ;
6 s t r c at ( st r 1 , st r 2 ) ;
7 p r i n t f ( %s , st r 1 ) ;
8 system( pause ) ;
9 ret urn 0;
10 }
Para evitar estouro de buffer, o tamanho do array destino
deve ser longo o suciente para conter a seq u encia de ca-
racteres contida em ambas as strings: origem e destino.
62
4.3.4 COMPARANDO DUAS STRINGS
Da mesma maneira como o operador de atribuic ao n ao funciona para
strings, o mesmo ocorre com operadores relacionais usados para com-
parar duas strings. Desse modo, para saber se duas strings s ao iguais
usa-se a func ao strcmp():
int strcmp(char *str1, char *str2)
A func ao strcmp() compara posic ao a posic ao as duas strings (str1 e str2)
e retorna um valor inteiro igual a zero no caso das duas strings serem
igausi. Um valor de retorno diferente de zero signica que as strings s ao
diferentes:
Exemplo: strcmp()
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 char st r 1 [ 100] , st r 2 [ 100] ;
5 p r i n t f ( Ent r e com uma s t r i ng : ) ;
6 get s ( st r 1 ) ;
7 p r i n t f ( Ent r e com out r a s t r i ng : ) ;
8 get s ( st r 2 ) ;
9 i f ( st rcmp ( st r 1 , st r 2 ) == 0)
10 p r i n t f ( St r i ngs i guai s \n ) ;
11 el se
12 p r i n t f ( St r i ngs di f er ent es \n ) ;
13 system( pause ) ;
14 ret urn 0;
15 }
A func ao strcmp() e case-sensitive. Isso signica que le-
tras maiusculas e minusculas tornam as strings diferentes.
63
5 TIPOS DEFINIDOS PELO PROGRAMADOR
Os tipos de vari aveis vistos at e agora podem ser classicados em duas
categorias:
tipos b asicos: char, int, oat, double e void;
tipos compostos homog eneos: array.
Dependendo da situac ao que desejamos modelar em nosso programa, es-
ses tipos existentes podem n ao ser sucientes. Por esse motivo, a lingua-
gem C permite criar novos tipos de dados a partir dos tipos b asicos. Para
criar um novo tipo de dado, um dos seguintes comandos pode ser utlizado:
Estruturas: comando struct
Uni oes: comando union
Enumerac oes: comando enum
Renomear um tipo existente: comando typedef
Nas sec oes seguintes, cada um desses comandos ser a apresentado em
detalhes.
5.1 ESTRUTURAS
Uma estrutura pode ser vista como uma lista de vari aveis, sendo que cada
uma delas pode ter qualquer tipo. A id eia b asica por tr as da estrutura e
criar apenas um tipo de dado que contenha v arios membros, que nada
mais s ao do que outras vari aveis.
A forma geral da denic ao de uma nova estrutura e utilizando o comando
struct:
struct nomestruct{
tipo1 campo1;
tipo2 campo2;
...
tipon campoN;
};
64
A principal vantagem do uso de estruturas e que agora podemos agrupar
de forma organizada v arios tipos de dados diferentes dentro de uma unica
vari avel.
As estruturas podem ser declaradas em qualquer escopo
do programa (global ou local).
Apesar disso, a maioria das estruturas s ao declaradas no escopo global.
Por se tratar de um novo tipo de dado, muitas vezes e interessante que
todo o programa tenha acesso a estrutura. Da a necessidade de usar o
escopo global.
Abaixo, tem-se um exemplo de uma estrutura declarada para representar
o cadastro de uma pessoa:
Exemplo de estrutura.
1 st r uct cadast r o{
2 char nome[ 5 0 ] ;
3 i nt i dade ;
4 char rua [ 5 0 ] ;
5 i nt numero ;
6 };
Note que os campos da estrutura s ao denidos da mesma forma que
vari aveis. Como na declarac ao de vari aveis, os nomes dos membros de
uma estrutra devem ser diferentes um do outro. Por em, estrutras diferentes
podem ter membros com nomes iguais:
struct cadastro{
char nome[50];
int idade;
char rua[50];
int numero; };
65
struct aluno{
char nome[50];
int matricula
oat nota1,nota2,nota3;
};
Depois do smbolo de fecha chaves (}) da estrutura e ne-
cess ario colocar um ponto e vrgula (;).
Isso e necess ario uma vez que a estrutura pode ser tamb em declarada no
escopo local. Por quest oes de simplicac oes, e por se tratar de um novo
tipo, e possvel logo na denic ao da struct denir algumas vari aveis desse
tipo. Para isso, basta colocar os nomes das vari aveis declaradas ap os o
comando de fecha chaves (}) da estrutura e antes do ponto e vrgula (;):
struct cadastro{
char nome[50];
int idade;
char rua[50];
int numero;
} cad1, cad2;
No exemplo acima, duas vari aveis (cad1 e cad2) s ao declaradas junto com
a denic ao da estrutura.
Uma vez denida a estrutura, uma vari avel pode ser declarada de modo
similar aos tipos j a existente:
struct cadastro c;
Por ser umtipo denido pelo programador, usa-se a palavra
struct antes do tipo da nova vari avel declarada.
O uso de estruturas facilita muito a vida do programador na manipulac ao
dos dados do programa. Imagine ter que declarar 4 cadastros, para 4
pessoas diferentes:
66
char nome1[50], nome2[50], nome3[50], nome4[50];
int idade1, idade2, idade3, idade4;
char rua1[50], rua2[50], rua3[50], rua4[50];
int numero1, numero2, numero3, numero4;
Utilizando uma estrutura, o mesmo pode ser feito da seguinte maneira:
struct cadastro c1, c2, c3, c4;
Uma vez denida uma vari avel do tipo da estrutura, e preciso poder aces-
sar seus campos (ou vari aveis) para se trabalhar.
Cada campo (vari avel) da estrutura pode ser acessada
usando o operador .(ponto).
O operador de acesso aos campos da estrutura e o ponto (.). Ele e usado
para referenciar os campos de uma estrutura. O exemplo abaixo mostra
como os campos da estrutura cadastro, denida anteriormente, odem ser
facilmente acessados:
Exemplo: acessando as vari aveis de dentro da estrutura
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 st r uct cadast r o{
4 char nome[ 5 0 ] ;
5 i nt i dade ;
6 char rua [ 5 0 ] ;
7 i nt numero ;
8 };
9 i nt main ( ) {
10 st r uct cadast r o c ;
11 / / At r i b u i a s t r i ng Car l os para o campo nome
12 st r cpy ( c . nome, Car l os ) ;
13
14 / / At r i b u i o val or 18 para o campo i dade
15 c . i dade = 18;
16
17 / / At r i b u i a s t r i ng Aveni da Br as i l para o campo rua
18 st r cpy ( c . rua , Aveni da Br as i l ) ;
19
20 / / At r i b u i o val or 1082 para o campo numero
21 c . numero = 1082;
22
23 system( pause ) ;
24 ret urn 0;
25 }
67
Como se pode ver, cada campo da esrutura e tratado levando emconsiderac ao
o tipo que foi usado para declar a-la. Como os campos nome e rua s ao
strings, foi preciso usar a func ao strcpy() para copiar o valor para esses
campos.
E se quis essemos ler os valores dos campos da estrutura
do teclado?
Nesse caso, basta ler cada vari avel da estrutura independentemente, res-
peitando seus tipos, como e mostrado no exemplo abaixo:
Exemplo: lendo do teclado as vari aveis da estrutura
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 st r uct cadast r o{
4 char nome[ 5 0 ] ;
5 i nt i dade ;
6 char rua [ 5 0 ] ;
7 i nt numero ;
8 };
9 i nt main ( ) {
10 st r uct cadast r o c ;
11 / / L e do t ecl ado uma s t r i ng e armazena no campo nome
12 get s ( c . nome) ;
13
14 / / L e do t ecl ado um val or i n t e i r o e armazena no campo i dade
15 scanf ( %d ,&c . i dade ) ;
16
17 / / L e do t ecl ado uma s t r i ng e armazena no campo rua
18 get s ( c . rua ) ;
19
20 / / L e do t ecl ado um val or i n t e i r o e armazena no campo numero
21 scanf ( %d ,&c . numero) ;
22 system( pause ) ;
23 ret urn 0;
24 }
Note que cada vari avel dentro da estrutura pode ser acessada como se
apenas ela existisse, n ao sofrendo nenhuma interfer encia das outras.
Lembre-se: uma estrutura pode ser vista como um simples
agrupamento de dados.
68
Como cada campo e independente um do outro, outros operadores podem
ser aplicados a cada campo. Por exemplo, pode se comparar a idade de
dois cadastros.
5.1.1 INICIALIZAC

AO DE ESTRUTURAS
Assim como nos arrays, uma estrutura tamb em pode ser inicializada, inde-
pendente do tipo das vari aveis contidas nela. Para tanto, na declarac ao da
vari avel do tipo da estrutura, basta denir uma lista de valores separados
por vrgula e delimitado pelo operador de chaves {}.
struct cadastro c = {Carlos,18,Avenida Brasil,1082 };
Nesse caso, como nos arrays, a ordem e mantida. Isso signica que o
primeiro valor da inicializac ao ser a atribudo a primeira vari avel membro
(nome) da estrutura e assim por diante.
Elementos omitidos durante a inicializac ao s ao inicializados com 0. Se for
uma string, a mesma ser a inicializada com uma string vazia ().
struct cadastro c = {Carlos,18 };
No exemplo acima, o campo rua e inicializado com e numero com zero.
5.1.2 ARRAY DE ESTRUTURAS
Voltemos ao problema do cadastro de pessoas. Vimos que o uso de es-
truturas facilita muito a vida do programador na manipulac ao dos dados do
programa. Imagine ter que declarar 4 cadastros, para 4 pessoas diferen-
tes:
char nome1[50], nome2[50], nome3[50], nome4[50];
int idade1, idade2, idade3, idade4;
char rua1[50], rua2[50], rua3[50], rua4[50];
int numero1, numero2, numero3, numero4;
Utilizando uma estrutura, o mesmo pode ser feito da seguinte maneira:
69
struct cadastro c1, c2, c3, c4;
A representac ao desses 4 cadastros pode ser ainda mais simplicada se
utilizarmos o conceito de arrays:
struct cadastro c[4];
Desse modo, cria-se um array de estruturas, onde cada posic ao do array e
uma estrutura do tipo cadastro.
A declarac ao de uma array de estruturas e similar a
declarac ao de uma array de um tipo b asico.
A combinac ao de arrays e estruturas permite que se manipule de modo
muito mais pr atico v arias vari aveis de estrutura. Como vimos no uso de
arrays, o uso de umndice permite que usemos comando de repetic ao para
executar uma mesma tarefa para diferentes posic oes do array. Agora, os
quatro cadastros anteriores podem ser lidos com o auxlio de um comando
de repetic ao:
Exemplo: lendo um array de estruturas do teclado
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 st r uct cadast r o{
4 char nome[ 5 0 ] ;
5 i nt i dade ;
6 char rua [ 5 0 ] ;
7 i nt numero ;
8 };
9 i nt main ( ) {
10 st r uct cadast r o c [ 4 ] ;
11 i nt i ;
12 f or ( i =0; i <4; i ++) {
13 get s ( c [ i ] . nome) ;
14 scanf ( %d ,&c [ i ] . i dade ) ;
15 get s ( c [ i ] . rua ) ;
16 scanf ( %d ,&c [ i ] . numero) ;
17 }
18 system( pause ) ;
19 ret urn 0;
20 }
Em um array de estruturas, o operador de ponto (.) vem
depois dos colchetes [ ] do ndice do array.
70
Essa ordem deve ser respeitada pois o ndice do array e quem indica qual
posic ao do array queremso acessar, onde cada posic ao do array e uma
estrutura. Somente depois de denida qual das estruturas contidas dentro
do array n os queremos acessar e que podemos acessar os seus campos.
5.1.3 ATRIBUIC

AO ENTRE ESTRUTURAS
As unicas operac oes possveis em um estrutura s ao as de acesso aos
membros da estrutura, por meio do operador ponto (.), e as de c opia ou
atribuic ao (=). A atribuic ao entre duas vari aveis de estrutura faz comque os
cont eudos das vari aveis contidas dentro de uma estrutura sejam copiado
para outra estrutura.
Atribuic oes entre estruturas s o podem ser feitas quando as
estruturas s ao AS MESMAS, ou seja, possuem o mesmo
nome!
Exemplo: atribuic ao entre estruturas
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3
4 st r uct ponto {
5 i nt x ;
6 i nt y ;
7 };
8
9 st r uct novo pont o {
10 i nt x ;
11 i nt y ;
12 };
13
14 i nt main ( ) {
15 st r uct ponto p1 , p2= {1 , 2};
16 st r uct novo pont o p3= {3 , 4};
17
18 p1 = p2 ;
19 p r i n t f ( p1 = %d e %d , p1 . x , p1 . y ) ;
20
21 / / ERRO! TIPOS DIFERENTES
22 p1 = p3 ;
23 p r i n t f ( p1 = %d e %d , p1 . x , p1 . y ) ;
24
25 system( pause ) ;
26 ret urn 0;
27 }
71
No exemplo acima, p2 e atribudo a p1. Essa operac ao est a correta pois
ambas as vari aveis s ao do tipo ponto. Sendo assim, o valor de p2.x e
copiado para p1.x e o valor de p2.y e copiado para p1.y.
J a na segunda atribuic ao (p1 = p3;) ocorre um erro. Isso por que os tipos
das estruturas das vari aveis s ao diferentes: uma pertence ao tipo struct
ponto enquanto a outra pertence ao tipo struct novo ponto. Note que o
mais importante e o nome do tipo da estrutura, e n ao as vari aveis dentro
dela.
No caso de estarmos trabalhando com arrays de estru-
turas, a atribuic ao entre diferentes elementos do array
tamb em e v alida.
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 st r uct cadast r o{
4 char nome[ 5 0 ] ;
5 i nt i dade ;
6 char rua [ 5 0 ] ;
7 i nt numero ;
8 };
9 i nt main ( ) {
10 st r uct cadast r o c [ 1 0 ] ;
11 . . .
12 c [ 1 ] = c [ 2 ] ; / / CORRETO
13
14 system( pause ) ;
15 ret urn 0;
16 }
Um array ou vetor e um conjunto de vari aveis do mesmo tipo utilizando
apenas um nome. Como todos os elementos do array s ao do mesmo tipo,
a atribuic ao entre elas e possvel, mesmo que o tipo do array seja uma
estrutura.
5.1.4 ESTRUTURAS ANINHADAS
Uma estrutura pode agrupar um n umero arbitr ario de vari aveis de tipos di-
ferentes. Uma estrutura tamb em e um tipo de dado, com a diferenca de se
trata de um tipo de dado criado pelo programador. Sendo assim, podemos
declarar uma estrutura que possua uma vari avel do tipo de outra estru-
tura previamente denida. A uma estrutura que contenha outra estrutura
72
dentro dela damos o nome de estruturas aninhadas. O exemplo abaixo
exemplica bem isso:
Exemplo: struct aninhada.
1 st r uct endereco{
2 char rua [ 50]
3 i nt numero ;
4 };
5 st r uct cadast r o{
6 char nome[ 5 0 ] ;
7 i nt i dade ;
8 st r uct endereco
ender ;
9 };
No exemplo acima, temos duas estruturas: uma chamada endereco e
outra chamada de cadastro. Note que a estrutura cadastro possui uma
vari avel ender do tipo struct endereco. Trata-se de uma estrutura ani-
nhada dentro de outra.
No caso da estrutura cadastro, o acesso aos dados da
vari avel do tipo struct endereco e feito utilizando-se nova-
mente o operador .(ponto).
Lembre-se, cada campo (vari avel) da estrutura pode ser acessada usando
o operador .(ponto). Assim, para acessar a vari avel ender e preciso usar
o operador ponto (.). No entanto, a vari avel ender tamb em e uma estrutura.
Sendo assim, o operador ponto (.) e novamente utilizado para acessar as
vari aveis dentro dessa estrutura. Esse processo se repete sempre que
houver uma nova estrutura aninhada. O exemplo abaixo mostra como a
estrutura aninhada cadastro poderia ser facilmente lida do teclado:
73
Exemplo: lendo do teclado as vari aveis da estrutura
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 st r uct endereco{
4 char rua [ 50]
5 i nt numero ;
6 };
7 st r uct cadast r o{
8 char nome[ 5 0 ] ;
9 i nt i dade ;
10 st r uct endereco ender ;
11 };
12 i nt main ( ) {
13 st r uct cadast r o c ;
14 / / L e do t ecl ado uma s t r i ng e armazena no campo nome
15 get s ( c . nome) ;
16
17 / / L e do t ecl ado um val or i n t e i r o e armazena no campo i dade
18 scanf ( %d ,&c . i dade ) ;
19
20 / / L e do t ecl ado uma s t r i ng
21 / / e armazena no campo rua da v ar i av el ender
22 get s ( c . ender . rua ) ;
23
24 / / L e do t ecl ado um val or i n t e i r o
25 / / e armazena no campo numero da v ar i av el ender
26 scanf ( %d ,&c . ender . numero) ;
27
28 system( pause ) ;
29 ret urn 0;
30 }
5.2 UNI

OES: UNIONS
Em breve
5.3 ENUMARAC

OES: ENUMERATIONS
Em breve
5.4 COMANDO TYPEDEF
Em breve
74
6 FUNC

OES
Uma func oes nada mais e do que umblocos de c odigo (ou seja, declarac oes
e outros comandos) que podem ser nomeados e chamados de dentro de
um programa. Em outras palavras, uma func ao e uma seq u encia de co-
mandos que recebe um nome e pode ser chamada de qualquer parte do
programa, quantas vezes forem necess arias, durante a execuc ao do pro-
grama.
A linguagem C possui muitas func oes j a implementadas e n os temos utili-
zadas elas constantemente. Um exemplo delas s ao as func oes b asicas de
entrada e sada: scanf() e printf(). O programador n ao precisa saber qual
o c odigo contido dentro das func oes de entrada e sada para utiliz a-las.
Basta saber seu nome e como utiliz a-la.
A seguir, ser ao apresentados os conceitos e detalhes necess arios para um
programador criar suas pr oprias func oes.
6.1 DEFINIC

AO E ESTRUTURA B

ASICA
Duas s ao as principais raz oes para o uso de func oes:
estruturac ao dos programas;
reutilizac ao de c odigo.
Por estruturac ao dos programas entende-se que agora o programa ser a
construdo a partir de pequenos blocos de c odigo (isto e, func oes) cada
um deles com uma tarefa especica e bem denida. Isso facilita a compre-
ens ao do programa.
Programas grandes e complexos s ao construdos bloco a
bloco com a ajuda de func oes.
J a por reutilizac ao de c odigo entende-se que uma func ao e escrita para
realizar uma determinada tarefa. Pode-se denir, por exemplo, uma func ao
para calcular o fatorial de um determinado n umero. O c odigo para essa
func ao ir a aparecer uma unica vez em todo o programa, mas a func ao
que calcula o fatorial poder a ser utilizadas diversas vezes e em pontos
diferentes do programa.
75
O uso de func oes evita a c opia desnecess aria de trechos
de c odigo que realizam a mesma tarefa, diminuindo assim
o tamanho do programa e a ocorr encia de erros.
Em linguagem C, a declarac ao de uma func ao pelo programador segue a
seguinte forma geral:
tipo retornado nome func ao (lista de par ametros){
sequ encia de declarac oes e comandos
}
O nome func ao e como aquele recho de c odigo ser a conhecido dentro do
programa. Para denir esse nome, valem, basicamente, as mesmas regras
para se denir uma vari avel.
Com relac ao ao local de declarac ao de uma func ao, ela deve ser denida
ou declarada antes de ser utilizada, ou seja, antes da cl ausula main, como
mostra o exemplo abaixo:
Exemplo: func ao declarada antes da cl ausula main.
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3
4 i nt Square ( i nt a) {
5 ret urn ( aa) ;
6 }
7
8 i nt main ( ) {
9 i nt num;
10 p r i n t f ( Ent r e com um numero : ) ;
11 scanf ( %d , &num) ;
12 num = Square (num) ;
13 p r i n t f ( O seu quadrado val e : %d\n , num) ;
14 system( pause ) ;
15 ret urn 0;
16 }
Pode-se tamb em declarar uma func ao depois da cl ausula main. Nesse
caso, e preciso declarar antes o prot otipo da func ao:
76
tipo retornado nome func ao (lista de par ametros);
O prot otipo de uma func ao, e uma declarac ao de func ao que omite o corpo
mas especica o seu nome, tipo de retorno e lista de par ametros, como
mostra o exemplo abaixo:
Exemplo: func ao declarada depois da cl ausula main.
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 / / pr ot ot i po da f unc ao
4 i nt Square ( i nt a) ;
5
6 i nt main ( ) {
7 i nt num;
8 p r i n t f ( Ent r e com um numero : ) ;
9 scanf ( %d , &num) ;
10 num = Square (num) ;
11 p r i n t f ( O seu quadrado val e : %d\n , num) ;
12 system( pause ) ;
13 ret urn 0;
14 }
15
16 i nt Square ( i nt a) {
17 ret urn ( aa) ;
18 }
Independente de onde uma func ao seja declarada, seu funcionamento e
basicamente o mesmo:
o c odigo do programa e executado at e encontrar uma chamada de
func ao;
o programa e ent ao interrompido temporariamente, e o uxo do pro-
grama passa para a func ao chamada;
se houver par ametros na func ao, os valores da chamada da func ao
s ao copiados para os par ametros no c odigo da func ao;
os comandos da func ao s ao executados;
quando a func ao termina (seus comandos acabaram ou o comando
return foi encontrado), o programa volta ao ponto onde foi interrom-
pido para continuar sua execuc ao normal;
77
se houver um comando return, o valor dele ser a copiado para a
vari avel que foi escolhida para receber o retorno da func ao.
Na gura abaixo, e possvel ter uma boa representac ao de como uma cha-
mada de func ao ocorre:
Nas sec oes seguintes, cada um dos itens que denem uma func ao ser ao
apresentados em detalhes.
6.1.1 PAR

AMETROS DE UMA FUNC



AO
Os par ametros de uma func ao e o que o programador utiliza para passar a
informac ao de um trecho de c odigo para dentro da func ao. Basicamente,
os par ametros de uma func ao s ao uma lista de vari aveis, separadas por
vrgula, onde e especicado o tipo e o nome de cada par ametro.
Por exemplo, a func ao sqrt possui a seguinte lista de
par ametros: oat sqrt(oat x);
Em linguagem C, a declarac ao dos par ametros de uma func ao segue a
seguinte forma geral:
tipo retornado nome func ao (tipo nome1, tipo nome2, ... ,
tipo nomeN){
sequ encia de declarac oes e comandos
}
78
Diferente do que acontece na declarac ao de vari aveis,
onde muitas vari aveis podem ser declaradas com o mesmo
especicador de tipo, na declarac ao de par ametros de uma
func ao e necess ario especicar o tipo de cada vari avel.
1 / / Decl arac ao CORRETA de par amet ros
2 i nt soma( i nt x , i nt y ) {
3 ret urn x + y ;
4 }
5
6 / / Decl arac ao ERRADA de par amet ros
7 i nt soma( i nt x , y ) {
8 ret urn x + y ;
9 }
Dependendo da func ao, ela pode possuir nenhum par ametro. Nesse caso,
pode-se optar por duas soluc oes:
Deixar a lista de par ametros vazia: void imprime ();
Colocar void entre par enteses: void imprime (void).
Mesmo se n ao houver par ametros na func ao, os
par enteses ainda s ao necess arios.
Apesar das duas declarac oes estarem corretas, existe uma diferenca en-
tre elas. Na primeira declarac ao, n ao e especicado nenhum par ametro,
portanto a func ao pode ser chamada passando-se valores para ela. O o
compilador n ao ir a vericar se a func ao e realmente chamada sem argu-
mentos e a func ao n ao conseguir a ter acesso a esses par ametros. J a na
segunda declarac ao, nenhum par ametro e esperado. Nesse caso, o pro-
grama acusar a um erro se o programador tentar passar um valor para essa
func ao.
Colocar void na lista de par ametros e diferente de se colo-
car nenhum par ametro.
O exemplo abaixo ilustra bem essa situac ao:
79
Exemplo: func ao sem par ametros
Sem void Com void
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3
4 void i mpri me ( ) {
5 p r i n t f ( Teste de
f uncao\n ) ;
6 }
7
8 i nt main ( ) {
9 i mpri me ( ) ;
10 i mpri me ( 5) ;
11 i mpri me ( 5 , a ) ;
12
13 system( pause ) ;
14 ret urn 0;
15 }
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3
4 void i mpri me ( void ) {
5 p r i n t f ( Teste de
f uncao\n ) ;
6 }
7
8 i nt main ( ) {
9 i mpri me ( ) ;
10 i mpri me ( 5) ; / / ERRO
11 i mpri me ( 5 , a ) ; / / ERRO
12
13 system( pause ) ;
14 ret urn 0;
15 }
Os par ametros das func oes tamb emest ao sujeitos ao escopo das vari aveis.
O escopo e o conjunto de regras que determinam o uso e a validade de
vari aveis nas diversas partes do programa.
O par ametro de uma func ao e uma vari avel local da func ao
e portanto, s o pode ser acessado dentro da func ao.
6.1.2 CORPO DA FUNC

AO
Pode-se dizer que o corpo de uma func ao e a sua alma.

E no corpo de
uma func ao que se dene qual a tarefa que a func ao ir a realizar quando
for chamada.
Basicamente, o corpo da func ao e formado por:
sequ encia de declarac oes: vari aveis, constantes, arrays, etc;
sequ encia de comandos: comandos condicionais, de repetic ao, cha-
mada de outras func oes, etc.
Para melhor entender o corpo da func ao, considere que todo programa
possui ao menos uma func ao: a func ao main. A func ao mais e a func ao
80
principaldo programa, o corpodo programa. Note que nos exemplo usa-
dos at e agora, a func ao main e sempre do tipo int, e sempre retorna o valor
0:
int main () {
sequ encia de declarac oes e comandos
return 0;
}
Basicamente, e no corpo da func ao que as entradas (par ametros) s ao pro-
cessadas, as sadas s ao geradas ou outras ac oes s ao feitas. Al em disso,
a func ao main se encarrega de realizar a comunicac ao com o usu ario, ou
seja, e ela quem realiza as operac oes de entrada e sada de dados (co-
mandos scanf e printf). Desse modo, tudo o que temos feito dentro de
uma func ao main pode ser feito em uma func ao desenvolvida pelo progra-
mador.
Tudo o que temos feito dentro da func ao main pode ser feito
em uma func ao desenvolvida pelo programador.
Uma func ao e construda com o intuito de realizar uma tarefa especica e
bem denida. Por exemplo, uma func ao para calcular o fatorial deve ser
construda de modo a receber um determinado n umero como par ametro
e retornar (usando o comando return) o valor calculado. As operac oes de
entrada e sada de dados (comandos scanf e printf) devem ser feitas em
quem chamou a func ao (por exemplo, na main). Isso garante que a func ao
construda possa ser utilizada nas mais diversas aplicac oes, garantindo a
sua generalidade.
De modo geral, evita-se fazer operac oes de leitura e escrita
dentro de uma func ao.
Os exemplos abaixo ilustram bem essa situac ao. No primeiro exemplo
temos o c alculo do fatorial realizado dentro da func ao main:
81
Exemplo: c alculo do fatorial dentro da func ao main
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3
4 i nt main ( ) {
5 p r i n t f ( Di gi t e um numero i n t e i r o pos i t i v o : ) ;
6 i nt x ;
7 scanf ( %d ,&x ) ;
8 i nt i , f = 1;
9 f or ( i =1; i <=x ; i ++)
10 f = f i ;
11
12 p r i n t f ( O f a t o r i a l de %d eh : %d\n , x , f ) ;
13 system( pause ) ;
14 ret urn 0;
15 }
Perceba que no exemplo acima, n ao foi feito nada de diferente do que
temos feito at e o momento. J a no exemplo abaixo, uma func ao especica
para o c alculo do fatorial foi construda:
Exemplo: c alculo do fatorial em uma func ao pr opria
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3
4 i nt f a t o r i a l ( i nt n) {
5 i nt i , f = 1;
6 f or ( i =1; i <=n ; i ++)
7 f = f i ;
8
9 ret urn f ;
10 }
11
12 i nt main ( ) {
13 p r i n t f ( Di gi t e um numero i n t e i r o pos i t i v o : ) ;
14 i nt x ;
15 scanf ( %d ,&x ) ;
16 i nt f a t = f a t o r i a l ( x ) ;
17 p r i n t f ( O f a t o r i a l de %d eh : %d\n , x , f a t ) ;
18
19 system( pause ) ;
20 ret urn 0;
21 }
Note que dentro da func ao respons avel pelo c alculo do fatorial, apenas o
trecho do c odigo respons avel pelo c alculo do fatorial est a presente. As
operac oes de entrada e sada de dados (comandos scanf e printf) s ao
feitos em quem chamou a func ao fatorial, ou seja, na func ao main.
82
Operac oes de leitura e escrita n ao s ao proibidas dentro de
uma func ao. Apenas n ao devem ser usadas se esse n ao
for o foco da func ao.
Uma func ao deve conter apenas o trecho de c odigo respons avel por fazer
aquilo que e o objetivo da func ao. Isso n ao impede que operac oes de
leitura e escrita sejam utilizadas dentro da func ao. Elas s o n ao devem ser
usadas quando os valores podem ser passados para a func ao por meio
dos par ametros.
Abaixo temos um exemplo de func ao que realiza operac oes de leitura e
escrita:
Exemplo: func ao contendo operac oes de leitura e escrita.
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt menu( ) {
4 i nt i ;
5 do {
6 p r i n t f ( Escol ha uma opc ao : \ n ) ;
7 p r i n t f ( ( 1) Opcao 1\n ) ;
8 p r i n t f ( ( 2) Opcao 2\n ) ;
9 p r i n t f ( ( 3) Opcao 3\n ) ;
10 scanf ( %d , &i ) ;
11 } whi le ( ( i < 1) | | ( i > 3) ) ;
12
13 ret urn i ;
14 }
15
16 i nt main ( ) {
17 i nt op = menu( ) ;
18 p r i n t f ( Vc escol heu a Opcao %d. \ n , op) ;
19 system( pause ) ;
20 ret urn 0;
21 }
Na func ao acima, um menu de opc oes e apresentado ao usu ario que tem
de escolher dentre uma delas. A func ao se encarrega de vericar se a
opc ao digitada e v alida e, caso n ao seja, solicitar uma nova opc ao ao
usu ario.
6.1.3 RETORNO DA FUNC

AO
O retorno da func ao e a maneira como uma func ao devolve o resultado (se
ele existir) da sua execuc ao para quem a chamou. Nas sec oes anterores
vimos que uma func ao segue a seguinte forma geral:
83
tipo retornado nome func ao (lista de par ametros){
sequ encia de declarac oes e comandos
}
A express ao tipo retornado estabele o tipo de valor que a func ao ir a de-
volver para quem cham a-la. Uma func ao pode retornar qualquer tipo v alido
em na linguagem C:
tipos b asicos pr e-denidos: int, char, oat, double, void e ponteiros;
tipos denidos pelo programador: struct, array (indiretamente), etc.
Uma func ao tamb em pode N

AO retornar um valor. Para


isso, basta colocar o tipo void como valor retornado.
O tipo void e conhecido como o tipo vazio. Uma func ao declarada com o
tipo void ir a apenas executar um conjunto de comando e n ao ir a devolver
nenhum valor para quem a chamar. Veja o exemplo abaixo:
Exemplo: func ao com tipo void
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 void i mpri me ( i nt n) {
4 i nt i ;
5 f or ( i =1; i <=n ; i ++)
6 p r i n t f ( Li nha %d \n , i ) ;
7 }
8
9 i nt main ( ) {
10 i mpri me ( 5) ;
11
12 system( pause ) ;
13 ret urn 0;
14 }
No exemplo acima, a func ao imprime ir a apenas imprimir uma mensagem
na tela n vezes. N ao h a o que devolver para a func ao main. Portanto,
podemos declarar ela como void.
Para executar uma func ao do tipo void, basta colocar no
c odigo o nome da func ao e seus par ametros.
84
Se a func ao n ao for do tipo void, ent ao ela dever a retornar um valor. O
comando return e utilizado para retornar esse valor para o programa:
return express ao;
A express ao da cla usula return tem que ser compatvel
com o tipo de retorno declarado para a func ao.
A express ao do comando return consiste em qualquer constante, vari avel
ou express ao aritm etica que o programador deseje retornar para o trecho
do programa que chamou a func ao. Essa express ao pode at e mesmo ser
uma outra func ao, como a func ao sqrt():
return sqrt(x);
Para executar uma func ao que tenha o comando return,
basta atribuir a chamada da func ao (nome da func ao e
seus par ametros) a uma vari avel compatvel com o tipo do
retorno.
O exemplo abaixo mostra uma func ao que recebe dois par ametros inteiros
e retorna a sua soma para a func ao main:
Exemplo: func ao com retorno
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt soma( i nt x , i nt y ) {
4 ret urn x + y ;
5 }
6
7 i nt main ( ) {
8 i nt a , b , c ;
9 p r i n t f ( Di gi t e a : ) ;
10 scanf ( %d , &a) ;
11 p r i n t f ( Di gi t e b : ) ;
12 scanf ( %d , &b) ;
13 p r i n t f ( Soma = %d\n , soma( a , b) ) ;
14 system( pause ) ;
15 ret urn 0;
16 }
85
Note, no exemplo acima, que a chamada da func ao foi feita dentro do co-
mando printf. Isso e possvel pois a func ao retorna um valor inteiro (x+y)
e o comando printf espera imprimir um valor inteiro (%d).
Uma func ao pode ter mais de uma declarac ao return.
O uso de v arios comandos return e util quando o retorno da func ao est a
relacionado a uma determinada condic ao dentro da func ao. Veja o exemplo
abaixo:
Exemplo: func ao com v arios return
1 i nt mai or ( i nt x , i nt y ) {
2 i f ( x > y )
3 ret urn x ;
4 el se
5 ret urn y ;
6 }
No exemplo acima, a func ao ser a executada e dependendo dos valores
de x e y, uma das cl ausulas return ser a executada. No entanto, e conve-
niente limitar as func oes a usar somente um comando return. O uso de
v arios comandos return, especialmente em func ao grandes e complexas,
aumenta a diculdidade de se compreender o que realmente est a sendo
feito pela func ao. Na maioria dos casos, pode-se reescrever uma func ao
para que ela use somente um comando return, como e mostrado abaixo:
Exemplo: substituindo os v arios return da func ao
1 i nt mai or ( i nt x , i nt y ) {
2 i nt z ;
3 i f ( x > y )
4 z = x ;
5 el se
6 z = y ;
7 ret urn z ;
8 }
No exemplo acima, os v arios comando return foram substituidos por uma
vari avel que ser a retornada no nal da func ao.
Quando se chega a um comando return, a func ao e encer-
rada imediatamente.
86
O comando return e utilizado para retornar um valor para o programa. No
entanto, esse comando tamb em e usado para terminar a execuc ao de uma
func ao, similar ao comando break em um laco ou switch:
Exemplo: nalizando a func ao com return
1 i nt mai or ( i nt x , i nt y ) {
2 i f ( x > y )
3 ret urn x ;
4 el se
5 ret urn y ;
6 p r i n t f ( Fim da f uncao\n ) ;
7 }
No exemplo acima, a func ao ir a terminar quando um dos comando return
for executado. A mensagem Fim da funcaojamais ser a impressa na tela
pois seu comando se encontra depois do comando return. Nesse caso, o
comando printf ser a ignorado.
Ocomando return pode ser usado semumvalor associado
a ele para terminar uma func ao do tipo void.
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 #i ncl ude <math . h>
4 void i mpr i me l og ( f l oat x ) {
5 i f ( x <= 0)
6 ret urn ; / / t er mi na a f unc ao
7 p r i n t f ( Log = %f \n , l og ( x ) ) ;
8 }
9 i nt main ( ) {
10 f l oat x ;
11 p r i n t f ( Di gi t e x : ) ;
12 scanf ( %f , &f ) ;
13 i mpr i me l og ( x ) ;
14 system( pause ) ;
15 ret urn 0;
16 }
Na func ao contida no exemploa cima, se o valor de x e negativo ou zero,
o comando return faz com que a func ao termine antes que o comando
printf seja executado, mas nenhum valor e retornado.
O valor retornado por uma func ao n ao pode ser um array.
87
Lembre-se: a linguagemC n ao suporta a atribuic ao de umarray para outro.
Por esse motivo, n ao se pode ter como retorno de uma func ao um array.

E possvel retornar um array indiretamente, desde que ela


faca parte de uma estrutura.
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3
4 st r uct vet or {
5 i nt v [ 5 ] ;
6 };
7
8 st r uct vet or r et or na ar r ay ( ) {
9 st r uct vet or v = {1 , 2 , 3 , 4 , 5};
10 ret urn v ;
11 }
12
13 i nt main ( ) {
14 i nt i ;
15 st r uct vet or vet = r et or na ar r ay ( ) ;
16 f or ( i =0; i <5; i ++)
17 p r i n t f ( Val or es : %d \n , vet . v [ i ] ) ;
18 system( pause ) ;
19 ret urn 0;
20 }
A linguagem C n ao suporta a atribuic ao de um array para outro. Mas ela
permite a atrbuic ao entre estruturas. A atribuic ao entre duas vari aveis de
estrutura faz com que os cont eudos das vari aveis contidas dentro de uma
estrutura sejam copiado para outra estrutura. Desse modo, e possvel re-
tornar um array desde que o mesmo esteja dentro de uma estrutura.
6.2 TIPOS DE PASSAGEM DE PAR

AMETROS
J a vimos que, na linguagem C, os par ametros de uma func ao e o meca-
nismo que o programador utiliza para passar a informac ao de um trecho
de c odigo para dentro da func ao. Mas existem dois tipos de passagem de
par ametro: passagem por valor e por refer encia.
Nas sec oes seguintes, cada um dos tipos de passagem de par ametros
ser a explicado em detalhes.
88
6.2.1 PASSAGEM POR VALOR
Na linguagem C, os argumentos para uma func ao s ao sempre passados
por valor (by value), ou seja, uma c opia do dado e feita e passada para a
func ao. Esse tipo de passagem de par ametro e o padr ao para todos os ti-
pos b asicos pr e-denidos (int, char, oat e double) e estruturas denidas
pelo programador (struct).
Mesmo que o valor de uma vari avel mude dentro da func ao,
nada acontece com o valor de fora da func ao.
1 i ncl ude <st di o . h>
2 i ncl ude <s t d l i b . h>
3
4 void soma mais um( i nt n) {
5 n = n + 1;
6 p r i n t f ( Antes da f uncao : x = %d\n , n) ;
7 }
8
9 i nt main ( ) {
10 i nt x = 5;
11 p r i n t f ( Antes da f uncao : x = %d\n , x ) ;
12 soma mais um( x ) ;
13 p r i n t f ( Antes da f uncao : x = %d\n , x ) ;
14 system( pause ) ;
15 ret urn 0;
16 }
Sada Antes da funcao: x = 5
Dentro da funcao: x = 6
Depois da funcao: x = 5
No exemplo acima, no momento em que a func ao soma mais um e cha-
mada, o valor de x e copiado para o par ametro n da func ao. O par ametro
n e uma vari avel local da func ao. Ent ao, tudo o que acontecer com ele (n)
n ao se reete no valor original da vari avel x. Quando a func ao termina, a
vari avel n e destruda e seu valor e descartado. O uxo do programa e de-
volvido ao ponto onde a func ao foi inicialmente chamada, onde a vari avel
x mant em o seu valor original.
Na passagem de par ametros por valor, quaisquer
modicac oes que a func ao zer nos par ametros existem
apenas dentro da pr opria func ao.
89
6.2.2 PASSAGEM POR REFER

ENCIA
Na passagem de par ametros por valor, as func oes n ao podem modi-
car o valor original de uma vari avel passada para a func ao. Mas exis-
tem casos em que e necess ario que toda modicac ao feita nos valores
dos par ametros dentro da func ao sejam repassados para quem chamou a
func ao. Um exemplo bastante simples disso e a func ao scanf: sempre que
desejamos ler algo do teclado, passamos para a func ao scanf o nome da
vari avel onde o dado ser a armazenado. Essa vari avel tem seu valor modi-
cado dentro da func ao scanf e seu valor pode ser acessado no programa
principal.
A func ao scanf e um exemplo bastante simples de func ao
que altera o valor de uma vari avel e essa mudanca se re-
ete fora da func ao.
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3 i nt main ( ) {
4 i nt x = 5;
5 p r i n t f ( Antes do scanf : x = %d\n , x ) ;
6 p r i n t f ( Di gi t e um numero : ) ;
7 scanf ( %d ,&x ) ;
8 p r i n t f ( Depoi s do scanf : x = %d\n , x ) ;
9 system( pause ) ;
10 ret urn 0;
11 }
Quando se quer que o valor da vari avel mude dentro da func ao e essa
mudanca se reita fora da func ao, usa-se passagem de par ametros por
refer encia.
Na passagem de par ametros por refer encia n ao se passa
para a func ao os valores das vari aveis, mas sim os
enderecos das vari aveis na mem oria.
Na passagem de par ametros por refer encia o que e enviado para a func ao
e o endereco de mem oria onde a vari avel est a armazenada, e n ao uma
simples c opia de seu valor. Assim, utilizando o endereco da vari avel na
mem oria, qualquer alterac ao que a vari avel sofra dentro da func ao ser a
tamb em reetida fora da func ao.
90
Para passar um par ametro por refer encia, usa-se o ope-
rador *na frente do nome do par ametro durante a
declarac ao da func ao.
Para passar para a func ao um par ametro por refer encia, a func ao precisa
usar ponteiros. Um ponteiro e um tipo especial de vari avel que armazena
um endereco de mem oria, da mesma maneira como uma vari avel arma-
zena um valor. Mais detalhes sobre o uso de ponteiros ser ao apresentados
no captulo seguinte.
O exemplo abaixo mostra a mesma func ao declarada usando a passagem
de par ametro de valor e por refer encia:
Exemplo: passagem por valor e refer encia
Por valor Por refer encia
1 void soma mais um( i nt n)
{
2 n = n + 1;
3 }
1 void soma mais um( i nt n
) {
2 n = n + 1;
3 }
Note, no exemplo acima, que a diferenca entre os dois tipos de passagem
de par ametro e o uso do operador *na passagem por refer encia. Con-
sequentemente, toda vez que a vari avel passada por refer encia for usada
dentro da func ao, o operador *dever a ser usado na frente do nome da
vari avel.
Na chamada da func ao e necess ario utilizar o operador
&na frente do nome da vari avel que ser a passada por re-
fer encia.
Lembre-se do exemplo da func ao scanf. A func ao scanf e um exemplo
de func ao que altera o valor de uma vari avel e essa mudanca se reete
fora da func ao. Quando chamamos a func ao scanf, e necess ario colocar
o operador &na frente do nome da vari avel que ser a lida do teclado. O
mesmo vale para outra func oes que usam passagem de par ametro por
refer encia.
91
Na passagem de uma vari avel por refer encia e necess ario
usar o operador *sempre que se desejar acessar o
conte udo da vari avel dentro da func ao.
1 i ncl ude <st di o . h>
2 i ncl ude <s t d l i b . h>
3
4 void soma mais um( i nt n) {
5 n = n + 1;
6 p r i n t f ( Antes da f uncao : x = %d\n , n) ;
7 }
8
9 i nt main ( ) {
10 i nt x = 5;
11 p r i n t f ( Antes da f uncao : x = %d\n , x ) ;
12 soma mais um(&x ) ;
13 p r i n t f ( Antes da f uncao : x = %d\n , x ) ;
14 system( pause ) ;
15 ret urn 0;
16 }
Sada Antes da funcao: x = 5
Dentro da funcao: x = 6
Depois da funcao: x = 6
No exemplo acima, no momento em que a func ao soma mais um e cha-
mada, o endereco de x (&x) e copiado para o par ametro n da func ao. O
par ametro n e um ponteiro dentro da func ao que guarda o endereco de
onde o valor de x est a guardado fora da func ao. Sempre que alteramos
o valor de *n (conte udo da posic ao de mem oria guardada, ou seja, x), o
valor de x fora da func ao tamb em e modicado.
Abaixo temos outro exemplo que mostra a mesma func ao declarada usando
a passagem de par ametro de valor e por refer encia:
92
Exemplo: passagem por valor e refer encia
Por valor Por refer encia
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3
4 void Troca ( i nt a , i nt b)
{
5 i nt temp ;
6 temp = a ;
7 a = b ;
8 b = temp ;
9 p r i n t f ( Dent ro : %d e %
d\n , a , b) ;
10 }
11
12 i nt main ( ) {
13 i nt x = 2;
14 i nt y = 3;
15 p r i n t f ( Antes : %d e
%d\n , x , y ) ;
16 Troca ( x , y ) ;
17 p r i n t f ( Depoi s : %d e
%d\n , x , y ) ;
18 system( pause ) ;
19 ret urn 0;
20 }
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3
4 void Troca ( i nt a , i nt b)
{
5 i nt temp ;
6 temp = a ;
7 a = b ;
8 b = temp ;
9 p r i n t f ( Dent ro : %d e %
d\n , a, b) ;
10 }
11
12 i nt main ( ) {
13 i nt x = 2;
14 i nt y = 3;
15 p r i n t f ( Antes : %d e
%d\n , x , y ) ;
16 Troca(&x , &y ) ;
17 p r i n t f ( Depoi s : %d e
%d\n , x , y ) ;
18 system( pause ) ;
19 ret urn 0;
20 }
Sada Sada
Antes: 2 e 3 Antes: 2 e 3
Dentro: 3 e 2 Dentro: 3 e 2
Depois: 2 e 3 Depois: 3 e 2
6.2.3 PASSAGEM DE ARRAYS COMO PAR

AMETROS
Para utilizar arrays como par ametros de func oes alguns cuidados simples
s ao necess arios. Al em do par ametro do array que ser a utilizado na func ao,
e necess ario declarar um segundo par ametro (em geral uma vari avel in-
teira) para passar para a func ao o tamanho do array separadamente.
Arrays s ao sempre passados por refer encia para uma
func ao.
Quando passamos um array por par ametro, independente do seu tipo, o
que e de fato passado para a func ao e o endereco do primeiro elemento
93
do array.
A passagem de arrays por refer encia evita a c opia des-
necess aria de grandes quantidades de dados para outras
areas de mem oria durante a chamada da func ao, o que
afetaria o desempenho do programa.
Na passagem de um array como par ametro de uma func ao podemos de-
clarar a func ao de diferentes maneiras, todas equivalentes:
void imprime (int *m, int n);
void imprime (int m[], int n);
void imprime (int m[5], int n);
Mesmo especicando o tamanho de umarray no par ametro
da func ao a sem antica e a mesma das outras declarac oes,
pois n ao existe checagem dos limites do array em tempo
de compilac ao.
O exemplo abaixo mostra como um array de uma unica dimens ao pode ser
passado como par ametro para uma func ao:
Exemplo: passagem de array como par ametro
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3
4 void i mpri me ( i nt n
, i nt m) {
5 i nt i ;
6 f or ( i =0; i <m; i ++)
7 p r i n t f ( %d \n ,
n [ i ] ) ;
8 }
9
10 i nt main ( ) {
11 i nt v [ 5 ] =
{1 , 2 , 3 , 4 , 5};
12 i mpri me ( v , 5) ;
13 system( pause ) ;
14 ret urn 0;
15 }
94
Note, no exemplo acima, que apenas o nome do array e passado para a
func ao, semcolchetes. Isso signica que estamos passando o array inteiro.
Se usassemos o colchete, estariamos passando o valor de uma posic ao
do array e n ao o seu endereco, o que resultaria em um erro.
Na chamada da func ao, passamos para ela somente o
nome do array, sem os colchetes: o programa j a sabeque
um array ser a enviado, pois isso j a foi denido no prot otipo
da func ao.
Vimos que, para arrays, n ao e necess ario especicar o n umero de elemen-
tos para a func ao no par ametro do array:
void imprime (int *m, int n);
void imprime (int m[], int n);
Arrays com mais de uma dimens ao (por exemplo, matri-
zes), precisam da informac ao do tamanho das dimens oes
extras.
Para arrays com mais de uma dimens ao e necess ario o tamanho de todas
as dimens oes, exceto a primeira. Sendo assim, uma declarac ao possvel
para uma matriz de 4 linhas e 5 colunas seria a apresentada abaixo:
void imprime (int m[][5], int n);
A declarac ao de arrays comuma dimens ao e commais de uma dimens ao e
diferente porque na passagem de um array para uma func ao o compilador
precisar saber o tamanho de cada elemento, n ao o n umero de elementos.
Um array bidimensional poder ser entendido como um ar-
ray de arrays.
Para a linguagem C, um array bidimensional poder ser entendido como um
array de arrays. Sendo assim, o seguinte array
int m[4][5];
95
pode ser entendido como um array de 4 elementos, onde cada elemento
e um array de 5 posic oes inteiras. Logo, o compilador precisa saber o
tamanho de um dos elementos (por exemplo, o n umero de colunas da
matriz) no momento da declarac ao da func ao:
void imprime (int m[][5], int n);
Na notac ao acima, informamos ao compilador que estamos passando um
array, onde cada elemento dele e outro array de 5 posic oes inteiras. Nesse
caso, o array ter a sempre 5 colunas, mas poder a ter quantas linhas quiser
(par ametro n).
Isso e necess ario para que o programa saiba que o array possui mais de
uma dimens ao e mantenha a notac ao de um conjunto de colchetes por
dimens ao.
O exemplo abaixo mostra como um array de duas dimens oes pode ser
passado como par ametro para uma func ao:
Exemplo: passagem de matriz como par ametro
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3
4 void i mpr i me mat r i z ( i nt m[ ] [ 2 ] , i nt n) {
5 i nt i , j ;
6 f or ( i =0; i <n ; i ++)
7 f or ( j =0; j < 2; j ++)
8 p r i n t f ( %d \n , m[ i ] [ j ] ) ;
9 }
10
11 i nt main ( ) {
12 i nt mat [ 3 ] [ 2 ] = {{1 , 2} , {3 , 4} , {5 , 6}};
13 i mpr i me mat r i z ( mat , 3) ;
14 system( pause ) ;
15 ret urn 0;
16 }
As notac oes abaixo funcionam para arrays com mais de uma dimens ao.
Mas o array e tratado como se tivesse apenas uma dimens ao dentro da
func ao
void imprime (int *m, int n);
void imprime (int m[], int n);
O exemplo abaixo mostra como um array de duas dimens oes pode ser
passado como um array de uma unica dimens ao para uma func ao:
96
Exemplo: matriz como array de uma dimens ao
1 #i ncl ude <st di o . h>
2 #i ncl ude <s t d l i b . h>
3
4 void i mpr i me mat r i z ( i nt m, i nt n) {
5 i nt i ;
6 f or ( i =0; i <n ; i ++)
7 p r i n t f ( %d \n , m[ i ] ) ;
8 }
9
10 i nt main ( ) {
11 i nt mat [ 3 ] [ 2 ] = {{1 , 2} , {3 , 4} , {5 , 6}};
12 i mpr i me mat r i z (&mat [ 0 ] [ 0 ] , 6 ) ;
13 system( pause ) ;
14 ret urn 0;
15 }
Note que, nesse exemplo, ao inv es de passarmos o nome do array n os
passamos o endereco do primeiro elemento (&mat[0][0]). Isso faz com que
percamos a notac ao de dois colchetes para a matriz, e ela seja tratada
como se tivesse apenas uma dimens ao.
6.2.4 OPERADOR SETA
De modo geral, uma estrutura e sempre passada por valor para uma func ao.
Mas ela tamb em pode ser passada por refer encia sempre que desejarmos
alterar algum dos valores de seus campos.
Durante o estudo dos tipos denidos pelo programador, vimos que o ope-
rador .(ponto) era utilizado para acessar os campos de uma estrutura.
Se essa estrutura for passada por refer encia para uma func ao, ser a ne-
cess ario usar ambos os operadores *e .para acessar os valores origi-
nais dos campos da estrutura.
operador *: acessa o conte udo da posic ao de mem oria (valor da
vari avel fora da func ao) dentro da func ao;
operador .: acessa os campos de uma estrutura.
O operador seta ->substitui o uso conjunto dos operado-
res *e .no acesso ao campo de uma estrutura passada
por refer encia para uma func ao.
O operador seta -> e utilizado quando uma refer encia para uma estrutura
(struct) e passada para uma func ao. Ele permite acessar o valor do campo
97
da estrutura fora da func ao sem utilizar o operador *. O exemplo abaixo
mostra como os campos de uma estrutura passada por refer encia podem
ser acessado com ou sem o uso do operador seta ->:
Exemplo: passagem por valor e refer encia
Sem operador seta Com operador seta
1 st r uct ponto {
2 i nt x , y ;
3 };
4
5 void f unc ( st r uct ponto
p) {
6 ( p) . x = 10;
7 ( p) . y = 20;
8 }
1 st r uct ponto {
2 i nt x , y ;
3 };
4
5 void f unc ( st r uct ponto
p) {
6 p>x = 10;
7 p>y = 20;
8 }
6.3 RECURS

AO
Na linguagem C, uma func ao pode chamar outra func ao. Um exemplo
disso e quando chamamos qualquer uma das nossas func oes implemen-
tadas na func ao main. Uma func ao pode, inclusive, chamar a si pr opria.
Uma func ao assim e chamada de func ao recursiva.
A recurs ao tamb em e chamada de denic ao circular. Ela
ocorre quando algo e denido em termos de si mesmo.
Um exemplo cl assico de func ao que usa recurs ao e o c alculo do fatorial de
um n umero. A func ao fatorial e denida como:
0! = 1
N! = N * (N - 1)!
A id eia b asica da recurs ao e dividir um problema maior em um conjunto
de problemas menores, que s ao ent ao resolvidos de forma independente
e depois combinados para gerar a soluc ao nal: dividir e conquistar.
Isso ca evidente no c alculo do fatorial. O fatorial de um n umero N e o
produto de todos os n umeros inteiros entre 1 e N. Por exemplo, o fatorial
de 3 e igual a 1 * 2 * 3, ou seja, 6. No entanto, o fatorial desse mesmo
98
n umero 3 pode ser denido em termos do fatorial de 2, ou seja, 3! = 3 *
2!. O exemplo abaixo apresenta as func oes com e sem recurs ao para o
c alculo do fatorial:
Exemplo: fatorial
Com Recurs ao Sem Recurs ao
1 i nt f a t o r i a l ( i nt n) {
2 i f ( n == 0)
3 ret urn 1;
4 el se
5 ret urn n f a t o r i a l ( n
1) ;
6 }
1 i nt f a t o r i a l ( i nt n) {
2 i f ( n == 0)
3 ret urn 1;
4 el se {
5 i nt i , f = 1;
6 f or ( i =2; i <= n ; i
++)
7 f = f i ;
8 ret urn f ;
9 }
10 }
Em geral, as formas recursivas dos algoritmos s ao consideradas mais
enxutase mais elegantesdo que suas formas iterativas. Isso facilita a
interpretac ao do c odigo. Por em, esses algoritmos apresentam maior di-
culdade na detecc ao de erros e podem ser inecientes.
Todo cuidado e pouco ao se fazer func oes recursivas, pois
duas coisas devem car bem estabelecidas: o crit erio de
parada e o par ametro da chamada recursiva.
Durante a implementac ao de uma func ao recursiva temos que ter emmente
duas coisas: o crit erio de parada e o par ametro da chamada recursiva:
Crit erio de parada: determina quando a func ao dever a parar de
chamar a si mesma. Se ele n ao existir, a func ao ir a executar in-
nitamente. No c alculo de fatorial, o crit erio de parada ocorre quando
tentamos calcular o fatorial de zero: 0! = 1.
Par ametro da chamada recursiva: quando chamamos a func ao
dentro dela mesmo, devemos sempre mudar o valor do par ametro
passado, de forma que a recurs ao chegue a um t ermino. Se o va-
lor do par ametro for sempre o mesmo a func ao ir a executar innita-
mente. No c alculo de fatorial, a mudanca no par ametro da chamada
recursiva ocorre quando denimos o fatorial de N em termos no fato-
rial de (N-1): N! = N * (N - 1)! .
99
O exemplo abaixo deixa bem claro o crit erio de parada e o par ametro da
chamada recursiva na func ao recursiva implementada em linguagem C:
Exemplo: fatorial
1 i nt f a t o r i a l ( i nt n) {
2 i f ( n == 0) / / c r i t e r i o de parada
3 ret urn 1;
4 el se / / par amet ro do f a t o r i a l sempre muda
5 ret urn n f a t o r i a l ( n1) ;
6 }
Note que a implementac ao da func ao recursiva do fatorial em C segue
exatamente o que foi denido matem aticamente.
Algoritmos recursivos tendem a necessitar de mais tempo
e/ou espaco do que algoritmos iterativos.
Sempre que chamamos uma func ao, e necess ario um espaco de mem oria
para armazenar os par ametros, vari aveis locais e endereco de retorno da
func ao. Numa func ao recursiva, essas informac oes s ao armazenadas para
cada chamada da recurs ao, sendo, portanto a mem oria necess aria para
armazen a-las proporcional ao n umero de chamadas da recurs ao.
Al emdisso, todas essas tarefas de alocar e liberar mem oria, copiar informac oes,
etc. envolvem tempo computacional, de modo que uma func ao recursiva
gasta mais tempo que sua vers ao iterativa (sem recurs ao).
O que acontece quando chamamos a func ao fatorial com
um valor como N = 3?
Nesse caso, a func ao ser a chamada tantas vezes quantas foremnecess arias.
A cada chamada, a func ao ir a vericar se o valor de N e igual a zero. Se
n ao for, uma nova chamada da func ao ser a realizada. Esse processo,
identicado pelas setas pretas, continua at e que o valor de N seja decre-
mentado para ZERO. Ao chegar nesse ponto, a func ao comeca o processo
inverso (identicado pelas setas vermelhas): ela passa a devolver para
quem a chamou o valor do comando return. A gura abaixo mostra esse
processo para N = 3:
Outro exemplo cl assico de recurs ao e a seq u encia de Fibonacci:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, . . .
100
A sequ enciade de Fibonacci e denida como uma func ao recursiva utili-
zando a f ormula abaixo:
Oexemplo abaixo apresenta as func oes come semrecurs ao para o c alculo
da sequ encia de de Fibonacci:
Exemplo: seq u encia de Fibonacci
Com Recurs ao Sem Recurs ao
1 i nt f i bo ( i nt n) {
2 i f ( n == 0 | | n == 1)
3 ret urn n ;
4 el se
5 ret urn f i bo ( n1) +
f i bo ( n2) ;
6 }
1 i nt f i bo ( i nt n) {
2 i nt i , t , c , a=0, b=1;
3 f or ( i =0; i <n ; i ++) {
4 c = a + b ;
5 a = b ;
6 b = c ;
7 }
8 ret urn a ;
9 }
Como se nota, a soluc ao recursiva para a seq u encia de Fibonacci e muito
elegante. Infelizmente, como se verica na imagem abaixo, eleg ancia n ao
signica eci encia.
Na gura acima, as setas pretas indicam quando uma nova chamada da
func ao e realizada, enquanto as setas vermelhas indicam o processo in-
verso, ou seja, quando a func ao passa a devolver para quem a chamou
101
o valor do comando return. O maior problema da soluc ao recursiva est a
nos quadrados marcados com pontilhados verde. Neles, ca claro que
o mesmo c alculo e realizado duas vezes, um desperdcio de tempo e
espaco!
Se, ao inv es de calcularmos bo(4) quisermos calcular bo(5), teremos
um desperdcio ainda maior de tempo e espaco, como mostra a gura
abaixo:
102

Vous aimerez peut-être aussi