Вы находитесь на странице: 1из 22

6/4/2011 11:09 1

Funes
Funes (tambm chamadas de rotinas ou procedimentos) so trechos de cdigo
situados fora do programa principal. As funes so identificadas por um nome. Este
nome chamado (ou invocado) toda vez que se desejar executar o cdigo da funo.
Na verdade o programa principal tambm uma funo, cujo nome main.
Motivos para usar funes
Considere o seguinte programa: para dois alunos, o programa l o valor das notas de
trs provas. A mdia calculada somente com a nota das duas melhores provas.
Deseja-se descobrir qual dos dois alunos obteve a melhor mdia.
Um abordagem simplista, em C, seria:
#include <stdlib.h>
#include <stdio.h>

int main(int argc, char argv[]) {
// Declarar notas e mdias dos alunos A e B
float notaA1, notaA2, notaA3, mediaA;
float notaB1, notaB2, notaB3, mediaB;

// Ler notas dos alunos A e B
scanf("%f %f %f", &notaA1, &notaA2, &notaA3);
scanf("%f %f %f", &notaB1, &notaB2, &notaB3);

// Calcular a mdia para o aluno A
if ((notaA1 <= notaA2) && (notaA1 <= notaA3)) {
mediaA = (notaA2 + notaA3) / 2.0f;
} else if ((notaA2 <= notaA1) && (notaA2 <= notaA3)) {
mediaA = (notaA1 + notaA3) / 2.0f;
} else {
mediaA = (notaA1 + notaA2) / 2.0f;
}

// Calcular a mdia para o aluno B
if ((notaB1 <= notaB2) && (notaB1 <= notaB3)) {
mediaB = (notaB2 + notaB3) / 2.0f;
} else if ((notaB2 <= notaB1) && (notaB2 <= notaB3)) {
mediaB = (notaB1 + notaB3) / 2.0f;
} else {
mediaB = (notaB1 + notaB2) / 2.0f;
}

// Imprimir resultado
if (mediaA > mediaB) {
printf("Aluno A obteve melhor desempenho");
} else if (mediaA < mediaB) {
printf("Aluno B obteve melhor desempenho");
} else {
printf("Os alunos A e B tem a mesma media");
}

return 0;
}
Consulte: Funcoes\otas01\otas01.vcproj
Primeiro, declara-se as variveis que armazenaro as notas e as mdias dos alunos A e
B. O programa l ento as trs notas de cada aluno e armazena-as nas variveis
notaA1, notaA2, notaA3, notaB1, notaB2, notaB3.
6/4/2011 11:09 2
Em seguida, o programa calcula a mdia das duas melhores notas para o aluno A. Se a
nota 1 for a pior entre as trs (notaA1 menor que notaA2 e menor que notaA3),
ento a mdia calculada utilizando-se somente as outras duas notas (notaA2 e
notaA3). Seno, o programa verifica outra possibilidade: notas 1 e 3 so as duas
melhores (portanto, notaA2 menor que notaA1 e menor que notaA3). Caso
contrrio, sabemos que sobra apenas uma nica alternativa: as notas 1 e 2 so as
melhores.
Para o aluno B, o programa realiza os mesmos testes, mas trocando, respectivamente,
notaA1, notaA2, notaA3 e mediaA por notaB1, notaB2, notaB3 e mediaB.
No fim, as duas mdias so comparadas e o programa imprime uma mensagem
adequada.
Inconvenincias
O cdigo apresentado possui algumas inconvenincias, que sero discutitas agora.
Primeiro, note que o cdigo repete as mesmas instrues para calcular a mdia das
duas melhores notas tanto para o aluno A como para aluno B. Observe que o cdigo,
na realidade, repete o mesmo algoritmo, mas para variveis diferentes.
Caso seja necessrio alterar uma instruo do algoritmo, o programador precisa
garantir que as duas cpias do cdigo sejam mudadas da mesma maneira, mas
difcil manter a consistncia. Facilmente algum esquecer de alterar algum detalhe
em uma das repeties do cdigo.
No obstante, o cdigo extenso, mesmo executando sempre o mesmo algoritmo. E
tambm conceitualmente confuso, pois ele mistura dois algoritmos em um nico
programa: o algoritmo para calcular a mdia das duas melhores notas e o algoritmo
para comparar mdias.
Por fim, difcil reaproveitar tanto o algoritmo do clculo de mdia como o de
comparao de notas em outro programa, a no ser copiando o cdigo.
O conceito de funes alivia esses problemas.
O que uma funo em C
O nome funo lembra as funes que conhecemos na matemtica, mas, em C, um
conceito muito mais amplo.
Em C, a palavra funo deve ser entendida como sinnimo de
algoritmo.
Uma funo implementa um algoritmo, e, portanto, apresenta os mesmos conceitos do
algoritmo: entrada, sada, cdigo finito, sempre parando ao executar com entradas
vlidas.
Uma funo um bloco de cdigo que:
Realiza uma determinada tarefa especfica. Normalmente, uma funo
implementa um algoritmo.
Pode ser executado a qualquer momento pelo programa.
Recebe dados de entrada do programa (ou do teclado, arquivo, etc).
Retorna um resultado (ou escreve algo na tela, em arquivo, etc).
Um programa pode executar uma funo diversas vezes, em momentos diferentes,
carregando valores diferentes para algumas das variveis da funo.
6/4/2011 11:09 3
Assim, quando temos uma mesma tarefa que precisamos executar em diversos pontos
diferentes do programa, podemos definir uma funo que implementa esta tarefa.
Quando necessitamos executar esta tarefa, basta chamar a funo, ao invs de repetir
todo seu cdigo. Os valores que a funo deve utilizar naquele momento so dados de
entrada que so passados como parmetros.
No exemplo anterior poderamos definir uma funo especfica para calcular a mdia
das duas melhores notas. Chamaramos a funo duas vezes, uma vez com as notas do
o aluno A e outra vez com as notas do aluno B. Desta forma, evitaramos a repetio
do cdigo, escrevendo-o apenas uma vez na definio da funo. Caso seja necessrio
alterar o algoritmo do clculo da mdia, basta alterar o cdigo que define a funo.
Chamando uma funo
Quando a execuo chega a uma instruo contendo uma chamada de funo, a
execuo do programa que chamou interrompida temporariamente e o computador
passa a executar as instrues contidas no algoritmo da funo. Veja na Figura 1 a
representao do fluxo de execuo. Terminada a execuo do algoritmo codificado
na funo, esta disponibiliza um valor de retorno, que pode ser atribudo a uma
varivel de mesmo tipo, e a execuo do programa onde ocorreu a chamada continua
na posio seguinte quela em que foi interrompido pela chamada da funo.
O cdigo que realiza a chamada de funo denominado cdigo chamador. A
funo denominada funo chamada.
Programa
principal
Funo
chamada
Instrues C
Instrues C
Programa
principal
Funo
chamada
Instrues C
Instrues C

Figura 1 Chamada de funo e desvio de execuo
Exemplo
Considere um programa que l duas coordenadas (x1, y1) e (x2, y2) de pontos no
plano Euclidiano e imprime a distncia entre os dois pontos. Este clculo exige a
extrao da raiz quadrada. A linguagem C no possui operador primitivo para extrair
a raiz quadrada. Felizmente, existe uma funo chamada sqrt que realiza este
clculo. Ela recebe como entrada um nmero (de tipo double) e aps sua execuo,
retorna a raiz quadrada deste nmero (tambem como um double ).
A chamada da funo est no cdigo a seguir:
#include <math.h>
int main(int argc, char *argv[]) {
double x1, x2, y1, y2, d;
double v;

scanf("%lf, %lf, %lf, %lf", &x1, &y1, &x2, &y2);
6/4/2011 11:09 4

v = (x1-x2)*(x1-x2) + (y1-y2)*(y12-*y2);
d = sqrt(v);

printf("Distncia: %f", d);

return 0;
}
Consulte: Funcoes\Chamada01\Chamada01.vcproj
Assim que a execuo chega linha contendo a funo sqrt, o programa principal
interrompido. O computador passa a executar o cdigo da funo sqrt, usando o
valor atual armazenado na varivel v. Aps algum processamento, esta funo retorna
a raiz quadrada do valor de v como resultado. A execuo do programa continua com
a atribuio do valor retornado varivel d.
Exemplo
Vamos supor que nosso programa dispe da funo mediaMelhoresNotas. Para
chamar a funo no programa, informamos o seu nome e entre parnteses listamos os
trs valores que desejamos que ela utilize durante os clculos. A funo calcula e
retorna um resultado, que pode ser atribudo uma varivel ou utilizado em uma
expresso aritmtica.
#include <stdlib.h>
#include <stdio.h>

int main(int argc, char argv[]) {
// Declarar notas e mdias dos alunos A e B
float notaA1, notaA2, notaA3, mediaA;
float notaB1, notaB2, notaB3, mediaB;

// Ler notas dos alunos A e B
scanf("%f %f %f", &notaA1, &notaA2, &notaA3);
scanf("%f %f %f", &notaB1, &notaB2, &notaB3);



// Calcular a mdia para o aluno A
mediaA = mediaMelhoresNotas(notaA1, notaA2, notaA3);




// Calcular a mdia para o aluno B
mediaB = mediaMelhoresNotas(notaB1, notaB2, notaB3);

// Imprimir resultado
if (mediaA > mediaB) {
printf("Aluno A obteve melhor desempenho");
} else if (mediaA < mediaB) {
printf("Aluno B obteve melhor desempenho");
} else {
printf("Os alunos A e B tem a mesma media");
}

return 0;
}
Consulte: Funcoes\otas02\otas02.vcproj
Observe em particular as duas linhas:
mediaA = mediaMelhoresNotas(notaA1, notaA2, notaA3);
mediaB = mediaMelhoresNotas(notaB1, notaB2, notaB3);
Chamada da funo mediaMelhoresNotas Resultado
Valores de entrada (parmetros)
Chamada da funo sqrt
Resultado
Valores de entrada (parmetros)
6/4/2011 11:09 5
Todo o esforo de programao est resumido em elaborar uma nica vez um
algoritmo e codific-lo numa funo denominada mediaMelhoresNotas. O programa
em si ficou bem simples.
Definio de funo
Agora, vamos aprender como definir funes em C. Como exemplo, utilizaremos a
funo mediaMelhoresNotas, que calcula a mdia das duas melhores notas entre trs
notas dadas. O exemplo ser construdo aos poucos, conforme aprendemos os
conceitos envolvidos na criao de funes. Enquanto isso, vrios trechos da
definio da funo sero omitidos e representados por trs pontos (...).
Uma funo definida da seguinte forma:
tipo nome(parmetros) {
declaraes de variveis
...
instrues;
...
return valor;
}
Nome
Tal como para variveis, as funes recebem um nome (tambm chamado de
identificador). O nome utilizado para identificar a funo no momento da chamada.
Na escolha do nome da funo valem as mesmas regras que aquelas j vistas para se
escolher nomes de variveis: o nome formado por letras maisculas, letras
minsculas, dgitos numricos ou o smbolo sublinhado (_), e sempre comeando com
uma letra.
Programadores de C costumam escolher identificadores formados por substantivos e o
smbolo de sublinhado (_) entre as palavras. Os programadores de C++ utilizam um
verbo como identificador.
Exemplo:

... mediaMelhoresNotas(...) {
...
// Corpo da funo
...
}
Parmetros
A maioria das funes recebe pelo menos um valor de entrada. Estes valores so os
parmetros. Na definio da funo, um parmetro uma varivel especial, que
existe somente dentro da funo. Tal como qualquer outra varivel, a varivel
associada a cada parmetro tambm deve ter seu tipo declarado. Os parmetros (e
seus respectivos tipos) so informados em uma lista separada por vrgulas e entre
parnteses, logo aps o nome da funo.





Nome da funo
Instrues que so executadas
pela funo
6/4/2011 11:09 6
Exemplo:

... mediaMelhoresNotas(float nota1, float nota2, float nota3) {
...
// Corpo da funo
...
}
No exemplo, indicamos que a funo vai usar trs variveis de tipo float. No corpo
da funo, essas variveis sero denominadas nota1, nota2 e nota3. Tudo se passa
como se as trs variveis fossem declaradas localmente, logo no incio do corpo da
funo. A diferena para as outras declaraes que ocorrem no corpo da funo est
no fato de que as variveis passadas como parmetros sero automaticamente
inicializadas, com aqueles valores que forem passados pelo cdigo que chamar a
funo. Essa inicializao ocorre antes do incio da execuo do cdigo da funo.
A lista de parmetros pode estar na mesma linha que o nome da funo, ou pode estar
dividida em vrias linhas. Escolha a opo de melhor legibilidade. O importante
delimitar a lista de parmetros com parnteses.
Parmetros na chamada de funo
Quando chamamos a funo, precisamos informar os valores de cada um dos
parmetros, na mesma ordem que aparecem na lista de parmetros. Os valores
precisam ter tipo compatvel com o tipo do respectivo parmetro.
Como exemplo, se a definio da funo fosse:
... potencia(float base, float expoente) {
...
// Corpo da funo
...
}
Poderamos chamar a funo como:
float resultado;
resultado = potencia(2.0f, 5.0f);
Neste caso, os valores 2.0f e 5.0f so atribudos aos parmetros na mesma ordem
em que foram declarados na definio da funo, ou seja, o parmetro base receber
o valor 2.0f, e o parmetro expoente o valor 5.0f. Assim, quando a funo
comear a executar, a varivel local base estar armazenando o valor 2.0f, e a
varivel local expoente conter o valor 5.0f. O compilador se encarrega de gerar
cdigo para que essa transferncia de valores realmente ocorra na memria do
computador, e logo antes de desviar o fluxo de execuo para as instrues da funo.
Assim, ao iniciar a execuo das instrues da funo, os valores dos parmetros j
estaro carregados nas respectivas variveis locais. Note que base e expoente
sero, implicitamente, declaradas localmente no corpo da funo pelo compilador.
Mais detalhes adiante.
O parmetro conter sempre uma cpia do valor usado na chamada da funo. Se, no
corpo da prpria funo, esta atribuir um novo valor a um de seus parmetros, ento
esta atribuio no estar refletida no cdigo chamador. Ou seja, se a funo
chamada tendo um parmetro x que recebe como valor o contedo de uma varivel t
do programa chamador e, se quando a funo executa, atribuido um outro valor
varivel x, ento o valor da varivel t no ter se alterado aps o trmino da
execuo da funo e o retorno ao programa chamador.
Lista de trs parmetros
6/4/2011 11:09 7
Funes sem parmetros
Existem casos especiais de funes que no tm parmetros. Nestas situaes, a lista
de parmetros vazia. Mas, mesmo assim, deve-ser escrever os parnteses, tanto na
definio, quanto na chamada da funo.
... funcaoSemParametros(void) {
...
// Corpo da funo
...
}
Corpo e variveis locais
O corpo da funo contm todas as instrues da linguagem C, em seqncia, que
implementam o algoritmo da funo. Cada funo pode ser entendida como um
programa independente, escrito em C.
No incio do corpo da funo, comum declarar variveis locais. Elas so conhecidas
somente dentro do corpo da funo. Em qualquer outro ponto do programa, que no
seja dentro do corpo desta funo, estas variveis no so conhecidas e ser
impossvel acessar o valor das mesmas. Como os parmetros j so entendidos como
declarados localmente, no faz sentido declarar no corpo da funo outras variveis
com nome idnticos aos nomes dos parmetros.
importante entender o que se passa na memria do cumputador quando este executa
funes com variveis locais ou parmetros. As declaraes, inclusive de parmetros,
so apenas indicativos de quanta memria ser necessria para armazenar valores das
respectivas variveis. Cada vez que uma funo entra em execuo novamente, novos
endereos de memria so alocados para as variveis locais, possivelmente diferentes
daqueles que foram alocados para essas mesmas variveis quando da ltima execuo
da funo. E o programa no tem nenhum controle sobre em que posio de memria
uma certa varivel estar alocada, em determinada ativao. Ao terminar a execuo
da funo, esses endereos de memria so liberados para uso por outros programas.
Da porque o programador no consegue recuperar valores atribudos s variveis
quando da ltima execuo da funo. Isso o que se passa usualmente na ativao,
execuo e trmino de funes, com algumas excees especficas que veremos mais
adiante.
Exemplo:
... mediaMelhoresNotas(
float nota1, float nota2, float nota3) {
float media;

if ((nota1 <= nota2) && (nota1 <= nota3)) {
media = (nota2 + nota3) / 2.0f;
} else if ((nota2 <= nota1) && (nota2 <= nota3)) {
media = (nota1 + nota3) / 2.0f;
} else {
media = (nota1 + nota2) / 2.0f;
}
...
}
Primeiro, o corpo da funo declara uma varivel (chamada media e de tipo float),
que armazena a mdia calculada dentro da funo. Alm disso, j existem outras trs
variveis locais e especiais nota1, nota2 e nota3 (todas do tipo float) que vo ser
inicializadas com valores passados como parmetros na chamada da funo.
Lista de zero parmetros
Declarao de uma varivel local
Cdigo (corpo) da
funo
Como se fosse declarao local
6/4/2011 11:09 8
Valor de Retorno
As funes (algoritmos) produzem um resultado. O comando return termina a
execuo da funo e define o valor de retorno. Na chamada da funo, o cdigo
chamador pode atribuir este valor retornado a uma varivel ou us-lo em uma
expresso.
No exemplo da chamada da funo mediaMelhoresNotas o resultado (valor de
retorno da funo) era armazenado nas variveis mediaA e mediaB:
mediaA = mediaMelhoresNotas(notaA1, notaA2, notaA3);
mediaB = mediaMelhoresNotas(notaB1, notaB2, notaB3);
Na especificao da funo, precisamos indicar o tipo do valor de retorno, antes do
nome da funo.



Exemplo:

float mediaMelhoresNotas(
float nota1, float nota2, float nota3) {

float media;
if ((nota1 <= nota2) && (nota1 <= nota3)) {
media = (nota2 + nota3) / 2.0f;
} else if ((nota2 <= nota1) && (nota2 <= nota3)) {
media = (nota1 + nota3) / 2.0f;
} else {
media = (nota1 + nota2) / 2.0f;
}

return media;
}

O comando return no necessariamente precisa ser a ltima instruo da funo. Ao
invs de salvar o resultado na varivel media para retornar o valor desta varivel
somente no final da funo, poderamos terminar a execuo da funo assim que o
resultado for calculado.
Exemplo:

float mediaMelhoresNotas(
float nota1, float nota2, float nota3) {

if ((nota1 <= nota2) && (nota1 <= nota3)) {
return (nota2 + nota3) / 2.0f;
} else if ((nota2 <= nota1) && (nota2 <= nota3)) {
return (nota1 + nota3) / 2.0f;
} else {
return (nota1 + nota2) / 2.0f;
}
}
Funes sem valor de retorno
Em casos especiais, a funo apenas executa o cdigo, mas no gera resultado que
possa ser retornado. Nesses casos, o tipo da funo ser void. O comando return
passa a ser opcional e pode ser usado sem valor de retorno, apenas para terminar a
Tipo do valor de retorno
Trmino da funo, indicando qual
valor deve ser retornado.
6/4/2011 11:09 9
execuo da funo. Estas funes costumam gerar algum outro efeito, como
imprimir um resultado na tela ou escrever algum dado em um arquivo.
Exemplo:

void comparaNotas(
float notaA, float notaB) {

if (mediaA > mediaB) {
printf("Aluno A obteve melhor desempenho");
} else if (mediaA < mediaB) {
printf("Aluno B obteve melhor desempenho");
} else {
printf("Os alunos A e B tem a mesma media");
}

}
A rigor, funes que no retornam um valor deveriam ser denominadas
procedimentos, mas a linguagem C preferiu no distinguir estes casos.
Observao: A funo ou sempre gera um resultado (e, portanto, declara um tipo
para o valor de retorno) ou ser de tipo void (nunca retorna valor). No existe uma
funo que retorna um valor somente sob determinada condio! Se sua funo
deveria retornar um valor somente em alguns casos, ento a lgica do seu programa
est confusa.
Exemplo Completo
#include <stdlib.h>
#include <stdio.h>

float mediaMelhoresNotas(float nota1, float nota2, float nota3) {
float media;
if ((nota1 <= nota2) && (nota1 <= nota3)) {
media = (nota2 + nota3) / 2.0f;
} else if ((nota2 <= nota1) && (nota2 <= nota3)) {
media = (nota1 + nota3) / 2.0f;
} else {
media = (nota1 + nota2) / 2.0f;
}
return media;
}

void comparaNotas(float notaA, float notaB) {
if (notaA > notaB) {
printf("Aluno A obteve melhor desempenho");
} else if (notaA < notaB) {
printf("Aluno B obteve melhor desempenho");
} else {
printf("Os alunos A e B tem a mesma media");
}
}

int main(int argc, char *argv[]) {
// Declarar notas e mdias dos alunos A e B
float notaA1, notaA2, notaA3, mediaA;
float notaB1, notaB2, notaB3, mediaB;

// Ler notas dos alunos A e B
scanf("%f %f %f", &notaA1, &notaA2, &notaA3);
scanf("%f %f %f", &notaB1, &notaB2, &notaB3);

// Calcular a mdia para o aluno A
mediaA = mediaMelhoresNotas(notaA1, notaA2, notaA3);

6/4/2011 11:09 10
// Calcular a mdia para o aluno B
mediaB = mediaMelhoresNotas(notaB1, notaB2, notaB3);

// Imprimir resultado
comparaNotas(mediaA, mediaB);

return 0;
}
Consulte: Funcoes\otas02\otas02.vcproj
Note como o programa principal ficou bastante simples! Ele simplesmente delega as
operaes para as funes especficas.
Funes Importantes
Funo main
Todos os programas precisam conter uma funo especial, denominada main. Ela
executada automaticamente ao iniciar o programa.
Um bom programa apresenta uma funo main curta. Ela apenas delega as tarefas
para outras funes que implementam operaes especficas. Isto deixa o programa
claro.
Escrita e leitura
Os comandos printf e scanf, utilizados para escrever e ler dados, so
implementados como funes. Note a semelhana do uso de printf com uma
chamada de funo:
printf("Resultado: %d", valor);
scanf("%d %d", &linhas, &colunas);
Nestes dois exemplos, Resultado %d e valor so os dois parmetros para a
funo printf. J para scanf, os parmetros so %d %d, &linhas, e &colunas.
A funes scanf e prinft so casos especiais de funes, pois permitem um nmero
varivel de parmetros.
Manipulao de arquivos
Toda a manipulao de arquivos realizada por comandos que tambm so funes:
fopen, fclose, fscanf, fprintf, rewind, fflush, fputc, fputs, fgetc, fgets,
ftell, fseek, entre outras. Veremos detalhes mais adiante.
Funes matemticas
Ao adicionar a diretiva #include <math.h> no comeo do programa, so
disponibilizadas novas funes matemticas especficas, tais como sqrt (raiz
quadrada), sqr e pow (potncia), sin, cos, tan e muitas outras. Para conhecer a lista
completa das funes matemticas, consulte a documentao do compilador C.
Vetores de caracteres
Ao adicionar a diretiva #include <string.h> no comeo do programa, so
disponibilizadas funes para manipular vetores de caracteres, como por exemplo:
strcmp (comparar dois vetores de caracteres), strcpy (copiar o contedo de um
vetor de caracteres para outro), strlen (obter o tamanho do texto armazenado em um
vetor de caracteres). Para conhecer a lista completa das funes de manipulao de
vetores de caracteres, consulte a documentao do compilador C.
6/4/2011 11:09 11
Gerenciamento de memria dinmica
Aprenderemos neste curso as seguintes funes para gerenciar memria dinmica:
malloc, realloc e free.
Exemplos de funes
Matemtica
Funes em C so uma forma natural para implementar funes matemticas. Por
exemplo, podemos criar a funo potncia (de expoentes inteiros no negativos)
utilizando multiplicaes:
float potencia(float base, int expoente) {
float resultado = 1.0f;
int contador;
for (contador = 0; contador < expoente; contador++) {
resultado = resultado * base;
}
return resultado;
}
Consulte: Funcoes\Protencia01/Potencia01.vcproj
A primeira linha declara o valor de retorno, o nome e os argumentos da funo:
float potencia(float base, int expoente)
Em outras palavras, o resultado (o valor de retorno) ser interpretado como um tipo
float. A funo identificada pelo nome potencia. Ela tem dois argumentos, o
primeiro (base) a base da potncia e tem tipo float. O segundo (expoente) um
nmero inteiro no negativo que indica quantas vezes devemos multiplicar a base por
si mesma. Ao chamar a funo, o cdigo chamador precisa informar estes dois
nmeros.
O corpo da funo comea declarando uma varivel auxiliar para calcular o resultado.
comum que funes utilizem variveis auxiliares com este propsito.
Em seguida, um for multiplica o resultado pela base tantas vezes quanto indicado
pelo argumento expoente. Note que essa verso simples do for no calcula
corretamente a potncia se expoente for um valor negativo.
No fim, o corpo da funo executa o comando return, que faz a funo terminar e a
execuo voltar para o cdigo chamador, alm de retornar o valor da varivel
resultado.
Um uso simples desta funo calcular a potncia de vrios nmeros.
int main(int argc, char *argv[]) {
float base, resultado;
int expoente;

printf("Base: ");
scanf("%f",&base);
printf("Expoente: ");
scanf("%d", &expoente);

resultado = potencia(base, expoente);

printf("Resultado: %f\n", resultado);

return 0;
}
Consulte: Funcoes\Protencia01/Potencia01.vcproj
Um exemplo do uso dessa funo seria em chamadas repetitivas (com diferentes
valores para o expoente) em uma mesma expresso. Como, por exemplo, para avaliar
6/4/2011 11:09 12
o valor de um polinmio. Se o polinmio fosse x
3
2x
2
+ x 3, cada chamada da
funo na forma potencia(x, i) calcularia o valor de um termo x
i
.
int main(int argc, char argv[]) {
float x, p;

printf("Valor de x: ");
scanf("%f",&x);
p = potencia(x, 3) - 2 * potencia(x, 2) + potencia(x, 1) - 3;
printf("Polinomio p = %f\n", p);

return 0;
}
Consulte: Funcoes\Protencia02/Potencia02.vcproj
Este algoritmo no eficiente, embora esteja correto. Note que as potncias de x so
recalculadas cada vez que a funo potncia chamada. Seria possvel alterar o
algoritmo para evitar essa ineficincia?
Outras funes
Nem todas as funes precisam realizar clculos matemticos. Existem casos quando
desejamos apenas criar uma funo para evitar repetir uma mesma lgica de
execuo. Suponha que necessitamos solicitar um nmero atravs de uma mensagem,
verificar o nmero digitado e repetir a solicitao at que um nmero vlido seja
digitado. Se este conjunto de operaes ocorrer vrias vezes no programa para
solicitar diversos nmeros, ento ser interessante criar uma funo para esta tarefa.
int le_numero(int minimo, int maximo) {
int leitura;

scanf("%d", &leitura);
while ((leitura < minimo) || (leitura > maximo)) {
printf("Valor fora do intervalo permitido (%d a %d)\n",
minimo, maximo);
printf("Digite novamente: ");
scanf("%d", &leitura);
}
return leitura;
}
Para chamar a funo, poderamos escrever:
int main(int argc, char *argv[]) {
int valor;

printf("("Pense em um numero de 1 a 100: ");
valor = le_numero(1, 100);

printf("Voce pensou em: %d\n", valor);

return 0;
}
Consulte: Funcoes\Entrada01\Entrada01.vcproj
Com valor de retorno, mas sem parmetros
Existem funes que no possuem parmetros e mesmo assim retornam um valor.
Neste caso, elas precisam obter alguma entrada de uma outra fonte que no sejam os
argumentos. Lembre que a funo implementa um algoritmo e todos os algoritmos
precisam de uma entrada, caso contrrio sempre vo gerar o mesmo valor.
Funes para organizao de cdigo
Um outro caso de funes sem parmetros ocorre quando desejamos organizar um
programa grande. Nestas situaes, dividimos o programa em grandes blocos, cada
6/4/2011 11:09 13
qual responsvel por uma operao. O programa principal (funo main)
encarregado apenas de chamar a funo que contm o bloco desejado.
Suponha um programa com vrias funcionalidades: calcular raizes de polinmio,
calcular o determinante de uma matriz e derivar funes. No incio, o usurio escolhe
qual opo deseja executar. Uma abordagem ruim seria:
int main(int argc, char *argv[]) {
char opcao;
printf(Que operacao deseja realizar?\n);
printf( P raiz de polinomio\n);
printf( M determinante de matriz\n);
printf( D derivar funcoes\n);
scanf(%c, &opcao);
if (opcao == P) {
// Cdigo para calcular raizes de polinmios
// ...
} else if (opcao == M) {
// Cdigo para calcular determinantes de matrizes
// ...
} else if (opcao == D) {
// Cdigo para calcular derivadas de funes
// ...
}
}
Acontece que cada uma das trs operaes exige um grande nmero de linhas de
cdigo e o programa ficar muito extenso e difcil de entender. Alm disso, confuso
localizar onde comea e termina o cdigo de uma opo.
Seria muito mais interessante dividir o programa em vrios blocos, cada qual
implementado atravs de uma funo:
void resolver_polinimio() {
// Cdigo para calcular raizes de polinmios
// ...
}

void calcular_determinante() {
// Cdigo para calcular determinantes de matrizes
// ...
}

void derivar_funcao() {
// Cdigo para calcular derivadas de funes
// ...
}
Estas funes no recebem parmetros nem geram valores de retorno pois, na
verdade, so programas totalmente independentes.
Nenhuma funo deveria ter mais de 200 linhas de cdigo. Se este
for o caso, verifique se no possvel reorganizar o cdigo.
O programa principal (funo main) ser um mero delegador de execuo.
Dependendo da opo fornecida pelo usurio, ele chama a respectiva funo.
int main(int argc, char *argv[]) {
char opcao;
printf(Que operacao deseja realizar?\n);
printf( P raiz de polinomio\n);
printf( M determinante de matriz\n);
printf( D derivar funcoes\n);
scanf(%c, &opcao);
if (opcao == P) {
resolver_polinomio();
} else if (opcao == M) {
calcular_determinante();
6/4/2011 11:09 14
} else if (opcao == D) {
derivar_funcao();
}
}
Tempo de vida de variveis
Cada funo pode declarar suas prprias variveis. Como vimos, essas variveis s
sero visveis quando a respectiva funo executar.
Alm disso, C permite declarar variveis fora do corpo de todas as funes. Essas
variveis estariam sempre disponveis, durante a execuo de qualquer funo.
Mas o que ocorre quando variveis so declaradas com o mesmo nome, mas em
funes diferentes? Uma funo consegue acessar variveis de outra funo? Para
obter as respostas, importante entender as regras de tempo de vida de variveis.
Tempo de vida
As regras para se determinar o tempo de vida de uma varivel controlam por quanto
tempo o contedo de uma varivel permanece armazenado na memria. Existem
variveis que armazenam um valor at o final da execuo do programa. Outras
mantm o valor apenas enquanto o computador est executando uma determinada
funo.
O tempo de vida da varivel est diretamente associado com as regras que associam
espao de memria a ela. Quando uma varivel passa a existir (inicia seu tempo de
vida), o computador reserva determinado espao na memria para armazenar o valor
da varivel. Enquanto a varivel estiver viva, este espao de memria estar
disponvel para leitura e escrita, ou seja, para recuperar e atribuir o valor da varivel.
Em certo momento, quando a varivel deixar de existir, i.e., termina seu tempo de
vida, este espao de memria liberado e o contedo da varivel perdido para
sempre.
O tempo de vida de uma varivel est diretamente ligado ao seu ponto de declarao
no cdigo fonte. Isso d origem a variveis globais e variveis locais.
Variveis globais
A varivel global aquela declarada fora de qualquer funo, tipicamente no incio
do arquivo do cdigo fonte. Ela permanece viva durante toda a execuo do programa
(sem restrio no tempo de vida). Antes de iniciar a execuo do programa, uma
varivel global recebe um espao na memria, o qual vai reter at o final da execuo
do programa, ou seja, a varivel armazena valores at o programa terminar.
No exemplo abaixo, a varivel v global, pois ela declarada fora do corpo de todas
as funes. Tanto a funo f1 como a funo f2 podem acessar e modificar valor de
v.

#include <stdlib.h>
#include <stdio.h>

int v = 0;

void f1() {
v++;
printf("f1: v = %d\n", v);
}
void f2() {
v+=2;
6/4/2011 11:09 15
printf("f2: v = %d\n", v);
}
int main(int argc, char *argv[]) {
f1();
f2();
f1();
}
Consulte: Funcoes\Visibilidade01\Visibilidade01.vcproj
O resultado da execuo ser:
f1: v = 1
f2: v = 3
f1: v = 4
Como a varivel v global, cada chamada (de f1 ou de f2) modifica o valor de v,
conforme indica a sada do programa.
Variveis locais
A varivel local (tambm chamada de automtica) declarada dentro do corpo de
uma funo, ou como parmetro. Ela vive enquanto esta funo estiver executando
(tempo de vida restrito funo). Aps a execuo de um comando return, que
finaliza a funo, ela deixa de existir, o espao de memria associado varivel
desmobilizado, o valor l armazenado perdido. Portanto, o tempo de vida se
restringe ao perodo de execuo da funo.
Cada vez que a funo executada, memria novamente alocada para a varivel,
possvelmente em posies diferentes na memria do computador a cada execuo da
funo. Durante esta execuo da funo, as variveis locais retm suas associaes
de memria e seus valores podem ser alterados e consultados. Toda vez que uma
funo termina sua execuo, o espao de memria associado variveis locais
demobilizado e os valores l armazenaos so perdidos. A varivel local no consegue
lembrar o valor que tinha na execuo anterior da mesma funo.
No exemplo abaixo, a varivel v local para cada uma das funes f1 e f2. Note que,
apesar de ter o mesmo nome, cada vez que f1 ou f2 iniciam, a respectiva varivel v
estabelecida em uma posio de memria (possivelmente diferentes, no importa!) e,
portanto, se comportam como variveis diferentes. Alm disso, por serem locais, a
varivel v declarada em f1 desalocada da memria antes do incio de f2 e, portanto,
f2 no pode acessar seu contedo. Quando f2 inicia, o computador vai alocar
memria para a varivel v de f2, possivelmente em outra posio diferente da
memria. Quando f2 executa, essa nova posio usada para guardar seus valores
at que esta execuo de f2 termine. Nesse ponto a memria alocada para essa
varivel local liberada. O ciclo de alocao e liberao de memria se repete
quando f1 voltar a executar novamente. Repare que as variveis de f1 e de f2, e
mesmo de diferentes execues de f1 ou de f2 estaro localizadas em posies
possivelmente diferentes da memria, sem possibiliade de comunicao entre si.
Assim, no h ambiguidade quando f1 ou f2 acessa sua respectiva varivel v, em
uma particular execuo.







6/4/2011 11:09 16
#include <stdlib.h>
#include <stdio.h>

void f1() {
int v = 0;
v++;
printf("f1: v = %d\n", v);
}

void f2() {
int v = 0;
v+=2;
printf("f2: v = %d\n", v);
}

int main(int argc, char argv[]) {
f1();
f2();
f1();
}
Consulte: Funcoes\Visibilidade02\Visibilidade02.vcproj
O resultado da execuo ser:
f1: v = 1
f2: v = 2
f1: v = 1
Observe que f1 modificou a varivel v, tal como fez f2. No entanto, cada uma das
funes modificou sua prpria varivel v e as alteraes no foram propagadas de f1
para f2. Alm disso, a varivel v perde seu valor no final da primeira execuo da
funo f1 e a segunda chamada de f1 no conhece mais o valor da primeira
chamada.
Sobreposio nomes de variveis globais e variveis locais
Em algumas situaes pode ocorrer que duas variveis de mesmo nome estejam vivas,
num dado instante. Ento, se usarmos o nome dessa varivel em uma expresso que
valor vamos obter, isto , o nome comum referencia qual das variveis? Nesta
situao, o compilador adota a seguinte poltica: a varivel declarada mais
recentemente aquela que est acessvel nesse instante, ou seja, essa varivel esconde
as outras variveis de mesmo nome que, por sua vez, ficam inacessveis. o caso
quando uma funo declara uma varivel local com um mesmo nome que uma outra
varivel global j declarada. Nesse caso, a varivel local tem prioridade sobre a
varivel global.
No prximo exemplo, enquanto a funo f executa, qualquer referncia ao nome da
varivel v local, isto , acessa a posio de memria associada cpia local da
varivel v. J na funo g, toda referncia ao nome de varivel v vai acessar a posio
de memria associada declarao global de v, fora das funes.
int v = 0;

int f(void) {
int v;
...
v = 2;
printf("f: v = %d\n", v);
}

int g(void) {
6/4/2011 11:09 17
v = 3;
printf("g: v = %d\n", v);
}

int main(int argc, char *argv[]) {
printf("main: v = %d\n", v);
f();
printf("main: v = %d\n", v);
g();
printf("main: v = %d\n", v);

}
O resultado da execuo ser:
main: v = 0
f: v = 2
main: v = 0

g: v = 3
main: v = 3

Logo no incio da execuo o programa imprime o valor zero para v. o valor que
inicializa a varivel na declarao global. Quando a funo f executa, o valor
impresso 2, correspondendo ao valor atribudo v no corpo da funo f. Porm,
quando termina a execuo de f e se retorna ao programa principal main, o valor
agora impresso o mesmo zero que foi impresso antres da chamada e execuo da
funo f. Isto porque f declara uma varivel v de mesmo nome qua aquela da
declarao global. O computador aloca uma outra posio de memria para essa
declarao de v no corpo de f, e usa essa nova posio de memria nas atribuies
f durante a execuo de f. Quando a execuo de f termina, essa nova posio e
desmobilizada e, agora, uma referncia varivel v vai acessar a posio original,
alocada quando da declarao global. Como, durante a execuo de f esta posio
ficou intocada, a segunda impresso em main reproduz o valor que a varivel global v
detinha logo antes de f iniciar sua execuo, ou seja, imprime o valor zero.
J a funo g no declara uma varivel local de nome v. Ento, a atribuio v em g
altera a mesma posio de memria que foi associada varivel global v. Logo, o
valor atribudo v em g, foi reproduzido na terceira impresso que ocorre em main,
mostrando que a atribuio de g foi mantida e se perpetuou aps o trmino da
execuo de g. Na verdade, a atribuio v em g e em main, esto acessando a
mesma posio de memria.
Arquivos de Cabealho ("headers")
J sabemos que podemos incluir arquivos especiais em um programa usando a
diretiva de compilao #include. Normalmente, usamos essa diretiva escrevendo o
nome do arquivo a incluir entre os smbolos < e >, indicando que este um arquivo
tipo "header file" padro do sistema. Nesses casos, o compilador sabe one encontrar
esse arquivo nos diretrios do sistema operacional. O efeito, como j vimos, que o
compilador vai ler o texto do arquivo includo no ponto de invocao da diretiva
#include, ou seja, tudo se passa como se o texto do arquivo includo fosse parte do
texto do nosso programa, aparecendo exatamente no ponto de invocao da diretiva.
A linguagem C tambm permite com que o programador construa seus prprios
arquivos de cabealho e os inclua no seu programa. Usualmente, o nome desses
6/4/2011 11:09 18
arquivos terminam com a extenso .h, um indicativo de que um "header file". Um
arquivo desse tipo pode conter qualquer cdigo C mas, normalmente, contm
definies comuns vrias rotinas. Assim, para ter essas definies presentes em
qualquer ponto de outro arquivo que contenha cdigo fonte C, bastar invocar o nome
do arquivo de incluso no ponto desejado do cdigo fonte, usando para isso a diretiva
#include.
No caso de arquivos de incluso definidos pelo programador, na diretiva #include
o nome do arquivo deve estar entre aspas duplas. E devemos tambm indicar em que
diretrio o arquivo de incluso se encontra, uma vez que o compilador no saber
localiz-lo. Se o nome do diretrio no for indicado, o compilador vai procurar o
arquivo de incluso no diretrio corrente.
No exemplo seguinte, criamos um arquivo de incluso chamado consts.h, que
contm outras incluses e algumas definies.
// includes padrao do sistema
#include <stdio.h>

// definicao de algumas constantes
#define BRANCO ' ' // char para o espaco em branco
#define FIM_DE_LINHA '\n' // char para o return
#define TAB '\t' // char para o tab

Como pode ser visto, o primeiro #include j tradicional, e faz com que o
contedo do arqruivo stdio.h seja expandido no ponto da sua invocao. Tudo se
passa como se o texto do arquivo consts.h fosse aumentado, incluindo todo o texto
do arquivo stdio.h naquele ponto. Da forma da invocao, fica claro que esse
ltimo arquivo faz parte do sistema. As linhas restantes no arquivo consts.h
contm a definio de trs nomes, BRANCO, FIM_DE_LINHA e TAB. O primeiro
corresponde ao caracter "espao em branco", o segundo ao caracter de "nova linha" e
o terceiro ao caracter de tabulao.
O programa a seguir inclui o texto do arquivo consts.h.
#include "consts.h" // meu arquivo de includes
char c; // variavel global
// funcao para pular brancos
char limpabrancos(void) { /* assume 1o. char ja carregado em c */
. . . .
}
// funcao para imprimir a palavra
void imppal(void) { /* assume 1o. char ja em c */
. . . .
}
// rotina principal
int main(void) {
. . .
}
Logo na primeira linha o arquivo consts.h incluido. Teramos um efeito
totalmente equivalente se tivssemos transcrito todo o contedo do arquivo naquele
ponto. Note como a diretiva #include presente no arquivo consts.h tambm
includa no texto do programa, trazendo para o cdigo do programa todo o contedo
do arquivo stdio.h. Ou seja, uma diretiva #include pode conter outras diretivas
#include aninhadas.
Na segunda linha, a varivel global c declarada.
6/4/2011 11:09 19
O restante do cdigo apresenta duas funes e a rotina principal. A primeira funo
est transcrita abaixo.
char limpabrancos(void) { /* assume 1o. char ja carregado em c */
while ( (c!=FIM_DE_LINHA) && ((c==TAB) || (c==BRANCO)) ) c=getchar();
return c;
}
Essa funo no usa parmetros e retorna um valor tipo char. O efeito dessa funo
deve ser retornar o primeiro caracter da entrada antes do "fim de linha", e que tambm
no seja uma pontuao. Note que, ao chamarmos essa funo, assumimos que a
varivel c j contm o primeiro caracter da entrada (veja os comentrios na definio
da funo). Assim, se o primeiro caracter no for FIM_DE_LINHA, mas for
BRANCO ou TAB, o corpo do while executado e o programa vai ignorar todos os
caracteres BRANCO ou TAB, at que encontre um FIM_DE_LINHA, ou um caracter
que no seja nem BRANCO nem TAB. Caso contrrio, se o primeiro caracter for
FIM_DE_LINHA, ou no for BRANCO nem TAB, o while no executado e esse
primeiro caracter retornado imediatamente.
O comando while formado apenas pelo comando
c=getchar( );
que faz todo o trabalho. A rotina getchar(), tambm invocada sem parmetros,
retorna o prximo caracter da entrada. Esse valor atribudo varivel c. Em
seguida, o fluxo de controle retorna para o teste do while. A expresso ser
verdadeira sempre que a varivel c no contiver o caracter de "fim de linha", mas
contiver ou o caracter de tabulao ou o caracter de "espao em branco". Ou seja, se
ainda no esgotamos a linha de entrada e o ltimo caracter lido for um "espao em
branco" ou uma tabulao, vamos pegar o prximo caracter da entrada. O efetio
lquido, ento, ser ler os prximos caracteres de entrada at encontrar um que no
seja nem o "espao em branco" nem uma tabulao (asumindo que no encontramos
ainda o "fim de linha"). Quando esse caracter for encontrado, o while termina e a
rotina retorna o valor desse caracter. Note que esse algoritmo s funciona
corretamente se o primeiro caracter a ser impresso j est armazenado em c antes da
rotina limpabrancos iniciar. Para isso, optamos por definir c como uma varivel
global. Mesmo porque a prxima rotina tambm vai utilizar a varivel c.
A segunda funo aparece abaixo.
void imppal(void) { /* assume 1o. char ja em c */
while ( (c != FIM_DE_LINHA) && (c != BRANCO) && (c != TAB) ) {
putchar(c);
c=getchar( );
}
putchar(FIM_DE_LINHA);
return;
}
O efeito da funo imprimir uma palavra que lida da entrada. A palavra formada
por todos os caracteres que esto na entrada, at que se encontre um "espao em
branco", uma tabulao ou o "fim de linha". A expresso que controla o while
continua verdadeira enquanto essa condio no acontece. A cada passo, o ltimo
caracter lido da entrada e colocado na sada, pela chamada putchar(c), e o prximo
caracter lido e atribudo varivel c. Note que essa rotina faz todo o seu trabalho
sem precisar de parmetros de entrada, e mesmo sem precisar retornar nada ao
programa que a chama.
A rotina principal poderia ser codificada como segue.
6/4/2011 11:09 20
int main(void) {
printf("Entre com uma frase: ");
c=getchar();
do {
if ( limpabrancos() == FIM_DE_LINHA ) break;
imppal( );
} while (1);

system("PAUSE");
return 0;
}
O cdigo simples. Inicialmente, o primeiro caracter amazenado na varivel c. Em
seguida, entramos em um lao onde a funo limpabrancos acionada para
desconsiderarmos os prximos "espaos em branco" e tabulaes. A funo
limpabrancos retorna o prximo caracter que no um "espao em branco" ou
uma tabulao. Esse caracter ento testado para ver se um "fim de linha". Se j
encontramos o "fim de linha", o programa termina. Caso contrrio, encontramos o
incio de uma palavra a ser impressa. Nesse caso, a funo imppal acionada para
imprimir essa palavra, e o ciclo se repete. Note que o do...while se repete
eternamente, pois a condio 1 no while ser sempre verdadeira, obviamente. A
nica forma de sair do lao atravs do comando break.
Consulte: Funcoes\Pegapal\PegaPal.vcproj


Pragmas de Funes
Quando um programa usa funes, podemos escrever o cdigo das funes antes do
cdigo da rotina principal. Um exemplo tpico de trecho de cdigo seria
#include <stdio.h>
// funcao para calcular o MDC; entrada sao os numeros; retorna o MDC
int mdc(int i, int j) {
while (i != j) {
if (i>j) i -=j;
else j -=i;
}
return i;
}
// rotina principal
int main(void) {
int n, m; /* inteiros dados */
printf("Entre com dois inteiros positivos: ");
scanf("%d %d",&n,&m);
while ( (n<=0) || (m<=0) ) {
printf("Os dois valores devem ser inteiros positivos. Tente de
novo: ");
scanf("%d %d",&n,&m);
}
printf("O mdc entre %1d e %1d vale %1d\n",n,m,mdc(m,n));
system("PAUSE");
return 0;
}
Ocorre que, com freqncia, o programa ficaria mais bem organizado se pudssemos
escrever o cdigo da rotina princial antes do cdigo da funo auxiliar. Assim, quem
examinasse o cdigo logo se depararia com o programa principal, podedo se inteirar
do que o pragma faz. Em seguida listaramos os cdigos das rotinas auxiliares.
O problema com esta abordagem que o compilador, ao analisar o cdigo da rotina
principal, vai se deparar com chamadas das rotinas auxiliares e, nestes instantes, o
6/4/2011 11:09 21
compilador no saberia reconhecer os nomes das rotinas auxiliares, pois estas no
teriam sido declaradas at ento. Nesse caso, o compilador anunciaria que os nomes
das rotinas seriam identificadores desconhecidos (ou no declarados) e anunciaria um
erro de compilao! Note que os nomes de rotinas de entrada e sada, tais como
printf ou scanf, no se enquadram nesse problema justamente porque o arquivo
stdio.h, que deve ter sido includo logo no incio do programa, contm a descrio
de comochamar essas rotinas.
Para resolver esse dilema, a linguagem C permite com que simplesmente declaremos
as funes logo de incio, incluindo seus tipos de retorno e parmetros, porm sem
listar os cdigos das rotimas propriamente ditos. Estes cdigos podem ser escritos
mais adiante, em pontos que o programador julgar mais apropriado. Assim, logo de
incio, o compilador j teria cadastrado os nomes das rotinas auxiliares, junto com
seus tipos de retorno e parmetros. Ao analisar o cdigo da rotina principal se
encontrar uma linha com uma chamada uma das rotinas auxiliares, o compilador
poderia ento determinar se o identificador do nome da rotina conhecido e poderia
verificar se os parmetros de chamada, e seus tipos de retorno, esto sendo usados de
forma coerente pelo programador. No caso anterior, o cdigo poderia ser colocado na
forma

/* calcular o maximo divisor comum */
#include <stdio.h>
int mdc(int n, int m); // so a definicao da funcao e seus
// parametros
int main(void) {
int n, m; /* inteiros dados */
printf("Entre com dois inteiros positivos: ");
scanf("%d %d",&n,&m);
while ( (n<=0) || (m<=0) ) {
printf("Os dois valores devem ser inteiros positivos. Tente de
novo: ");
scanf("%d %d",&n,&m);
}
// chamada da rotina mdc
printf("O mdc entre %1d e %1d vale %1d\n",n,m,mdc(m,n));
system("PAUSE");
return 0;
}
// corpo completo da rotina mdc
int mdc(int i, int j) {
while (i != j) {
if (i>j) i -=j;
else j -=i;
}
return i;
}
Na terceira linha temos apenas a declarao
int mdc(int n, int m);
Essa declarao apenas anuncia que o identificador mdc corresponde a uma funo
que recebe dois parmetros de tipo int e retorna um valor tambm de tipo int. A
partir desse ponto, o compilador saber reconhecer toda ocorrncia de mdc como uma
chamada a uma tal funo. Note que quando encontra uma dessas chamadas, o
compilador no precisa conhecer em detalhe o cdigo da rotina; precisa apenas saber
que nesse ponto deve gerar um desvio para algum lugar da memria onde estar essse
cdigo. Alm disso, o compilador poder verificar se a chamada est sendo feita
corretamente, isto , e se os tipos e quantidades de parmetros de entrada tambm
6/4/2011 11:09 22
esto sendo usados de forma correta. Mas estas verificaes todas j podem ser feitas
conhecendo apenas as declaraes das funes, na forma como ilustrado acima.
Essas declaraes de funes so tambm conhecidas como pragmas.
Note que o nome da rotina se torna conhecido logo aps o compilador passar pelo
ponto onde est o seu pragma. Em qualquer ponto mais adiante no cdigo, o
programador est livre para invocar a rotina pelo seu nome, desde que o faa de forma
coerente com os parmetros que precisam ser passados e desde que utilize o valor de
retorno tambm de forma coerente com o seu tipo declarado no pragma. o que
acontece na rotina principal, quando esta invoca a rotina mdc.
Tambm, dada impede que o programador crie um arquivo tipo cabealho ("header
file") onde pode reunir todas os pragmas de funes. Esse arquivo pode ser includo
em qualquer ponto para tornar as declaraes dessas rotinas conhecidas. Desta forma,
o programador pode melhor organizar seu cdigo.