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

Modularizao: Funes em C

Notas de Aula
Prof. Francisco Rapchan www.geocities.com/chicorapchan rapchan@terra.com.br

Muitas vezes um problema grande pode ser resolvido mais facilmente se for dividido em pequenas partes. Tratar partes menores e mais simples em separado muito mais fcil do que tratar o problema grande e difcil de uma vez. O que vimos da linguagem C at agora adequado para escrevermos pequenos programas. Entretanto, se for necessrio desenvolver e testar programas mais sofisticados (que envolvam mais funcionalidades) deveremos usar tcnicas que nos permitam, de alguma forma, organizar o cdigo fonte. Alguns aspectos devem ser levados em considerao: Programas complexos so compostos por um conjunto de segmentos de cdigo no to complexos. Muitas vezes usamos em um programa trechos que j desenvolvemos em outros programas.

comum em programao decompor programas complexos em programas menores e depois junt-los para compor o programa final. Essa tcnica de programao denominada programao modular. A programao modular facilita a construo de programas grandes e complexos, atravs de sua diviso em pequenos mdulos, ou subprogramas, mais simples. Estes subprogramas alem de serem mais simples de serem construdos, so tambm mais simples de serem testados. Esta tcnica tambm possibilita o reaproveitamento de cdigo, pois podemos utilizar um mdulo quantas vezes for necessrio eliminando a necessidade de escrev-lo repetidamente. Outro aspecto importante da modularizao a possibilidade de vrios programadores trabalhem simultaneamente na soluo de um mesmo problema, atravs da codificao separada dos mdulos. Assim, cada equipe pode trabalhar em um certo conjunto de mdulos ou subprogramas. Posteriormente estes mdulos so integrados formando o programa final. Em outras palavras, quando for necessrio construir um programa grande, devemos dividi-lo em partes e ento desenvolver e testar cada parte separadamente. Mais tarde, tais partes sero acopladas para formar o programa completo. A modularizao, em C comea atravs do uso adequado de funes (functions). Funes so algumas das formas usadas para agruparmos cdigo de forma organizada e modularizada. Tipicamente, usamos funes para realizar tarefas que se repetem vrias vezes na execuo de um mesmo programa. Isso feito associando-se um nome a uma seqncia de comandos atravs do que chamamos de Declarao da Funo. Pode-se ento usar o nome do procedimento ou da funo dentro do corpo do programa, sempre que desejarmos que o seu bloco de comandos seja executado, isso o que chamamos de Chamada do Procedimento ou da Funo.

Funes bsicas Na matemtica fazemos uso intenso de funes. Por exemplo, podemos definir as funes: Funo quadrado: f (x) = x2 Funo reverso: Funo dobro: f (x) = 1/x f (x) = x * 2 Exemplo: f(2) = 4 Exemplo: f(2) = 0,5 Exemplo: f(3) = 6

Estas funes possuem apenas um parmetro. Podemos tambm definir funes com mais de um parmetro: Funo soma dois nmeros: f (x, y) = x + y Funo hipotenusa: f ( x, y ) =

x +y

O resultado desta funo para x = 3 e y = 4 5. Portanto, f(3,4) da funo hipotenusa retorna 5. Dizemos tambm que x e y so os parmetros da funo. Os valores 3 e 4 so os argumentos da funo hipotenusa. Nas linguagens de programao tambm temos funes e elas so bem parecidas com as funes da matemtica. Uma funo um tipo especial de sub-rotina que retorna um resultado de volta ao ponto onde foi chamada.

Algoritmos e Programao

Francisco Rapchan rapchan@terra.com.br

Exemplo 1. Construa uma funo para somar dois nmeros conforme definida acima. Neste programa definimos uma funo chamada soma. Embora chamar uma funo de f ou g seja prtica comum na matemtica, na informtica normalmente so usados nomes mais expressivos ou significativos. Uma dica: os nomes usados devem fazer meno ao uso ou ao comportamento da funo. Observe que definimos a funo soma fora da funo main. Em C, main ( ) tambm uma funo. a primeira funo que executada. Nesse programa, os parmetros da funo soma so x (do tipo int) e y (tambm do tipo int) e o tipo de retorno da funo, coincidentemente, tambm int. No corpo da funo os parmetros so usados como variveis comuns. Outro elemento importante o return. Ele serve para indicar qual o valor que a funo ir retornar. No corpo do programa, chamamos a funo soma, passando como argumento os valores 3 e 5.

#include <stdio.h> // Declara a funo int soma (int x, int y) { int s; s = x + y; return (s); } int main(void) { int c; // Usa a funo soma c = soma (3 , 5); // Mostra o resultado printf ("Resultado: %i\n",c); // Retorno da funo principal return 0; }

Observe que a partir desse exemplo, colocamos a funo main como sendo do tipo int. Na verdade esse fato est apenas sendo explicitado, pois quando no damos um tipo para a funo main, o compilador assume o tipo int. A mesma coisa acontece com o return da funo main: se no o declaramos, o compilador inclui um return 0. Como estamos usando a funo main sem nenhum argumento, colocamos main (void). Isso explicita que main no ter nenhum argumento. Declarar apenas main ( ) indica que a funo main pode ter um nmero qualquer de argumentos. A funo main obrigatoriamente deve ter um valor inteiro como retorno. Esse valor pode ser usado pelo sistema operacional para testar a execuo do programa. A conveno geralmente utilizada faz com que a funo main retorne zero no caso da execuo ser bem sucedida ou diferente de zero no caso de problemas durante a execuo.

Exemplo 2. O programa abaixo mostra o valor do fatorial dos nmeros 1 at 10. Note que temos duas variveis com nome i definidas neste programa. Uma definida para o programa principal e outra para a funo. O compilador trata ambas separadamente. Dizemos que o escopo das duas variveis diferente. Uma tem como escopo o programa principal e outra tem como escopo apenas a funo, ou seja, ela enxergada apenas dentro da funo. A sada deste programa ser:
1! = 1 2! = 2 3! = 6 4! = 24 5! = 120 6! = 720 7! = 5040 8! = 40320 9! = 362880 10! = 3628800

#include <stdio.h> long int fatorial (int n) { int i; long int fat; fat = 1; for (i=1; i <= n; i++) fat = fat * i; return fat; } main(void) { int i; for (i = 1; i <= 100; i++) printf("%i! = %li\n",i,fatorial(i)); }

Observe tambm que declaramos o retorno da funo fatorial e a varivel fat como long int. A linguagem C oferece uma srie de tipos que permite trabalhar com nmeros de diferentes precises. Veja a tabela abaixo:

Algoritmos e Programao

Francisco Rapchan rapchan@terra.com.br

Tipo char unsigned char int unsigned int long int unsigned long int float double long double

Bytes 1 1 2 2 4 4 4 8 10

Formato %c %c %i %u %li %lu %f %lf %Lf

Inicio -128 0 -32.768 0 -2.147.483.648 0 3,4E-38 1,7E-308 3,4E-4932

Fim 127 255 32.767 65.535 2.147.483.647 4.294.967.295 3.4E+38 1,7E+308 3,4E+4932

Escopo de variveis Escopo de uma varivel refere-se ao mbito em que ela pode ser usada. Uma varivel definida dentro de uma funo s pode ser usada dentro desta funo (no pode ser usada fora do escopo da funo). Portanto, podemos definir variveis com o mesmo nome em funes diferentes sem nenhum problema. Dizemos que as variveis que so definidas dentro de uma funo so locais a essa funo, ou seja, elas s existem enquanto a funo est sendo executada (elas passam a existir quando ocorre a entrada da funo e so destrudas ao sair). Um aspecto importante que em C no possvel definir uma funo dentro de uma outra funo. Exemplo 3. Observe o programa abaixo. Neste programa, a funo soma usa 3 varivies: // Variveis globais int s, a; int soma (int i) { int v; v = s + i; s = v; return (v); } int main(void) { s = 1; a = soma (5); printf ("A: %i return 0; }

#include <stdio.h>

i: definida como parmetro da funo. v: definida como varivel da funo. s: definida como varivel global do programa.

Observa que as variveis s e a tambm so enxergadas de dentro da funo soma. Desta forma, os vares das variveis globais (definidas para todo o programa) podem ser usadas ou alteradas de dentro de uma funo. Por outro lado, vemos que h duas variveis locais na funo soma: i e v. Estas duas variveis s so enxergadas pelo cdigo da prpria funo soma. No possvel outras funes acessar o valor destas variveis.
S: %i\n",a,s);

Dizemos que as variveis definidas para o programa todo so globais (possuem escopo ou mbito global) em relao s funes e que as variveis definidas dentro das funes (inclusive os parmetros) so locais (possuem escopo ou mbito local) funo. Uma pergunta comum com relao a variveis globais e locais a seguinte: e se for definida uma varivel local com o mesmo nome de uma varivel global? Neste caso teremos duas variveis completamente diferentes. Localmente no ser possvel acessar a varivel global e viceversa. Observao: De forma geral deve-se evitar o uso de variveis globais. O uso de variveis globais considerada m prtica de programao pois torna o cdigo muito dependente, aumentando o acoplamento da funo e tornando-a difcil de ser usada em outro programa, diminuindo assim sua portabilidade.

Algoritmos e Programao

Francisco Rapchan rapchan@terra.com.br

Procedimentos (funes que retornam void vazio) Chamamos de procedimentos as funes que no retornam nenhum valor.

Exemplo 4. O programa abaixo incrementa o valor da varivel global s. Este um programa muito simples que serve apenas para mostrar como usar procedimentos. Observe que foi definida a funo soma como retornando void. O termo void significa vazio ou sem valor. Assim, chamamos funes desse tipo com sendo procedimentos. Como qualquer procedimento, este no retorna nenhum valor. Neste caso o procedimento soma chamado com o argumento 5 e altera o valor da varivel global s. O programa se comporta como se na linha em que o procedimento chamado, o fluxo de execuo fosse desviado para o procedimento e depois retornasse para a instruo imediatamente seguinte ao procedimento. O procedimento funciona como uma sub-rotina. Ateno: a funo main uma funo especial. No possvel declarar main como void. Assim, a definio abaixo est conceitualmente errada (embora em alguns compiladores possa passar desapercebido):
void main ( ) // Errado !!!

#include <stdio.h> int s; void soma (int i) { s = s + i; } int main(void) { s = 1; soma (5); printf ("S: %i\n",s); return 0; }

Na verdade, o nico tipo vlido para a funo main int.


int main (void) // Certo!!!

Exemplo 5. No possvel fazer as operaes abaixo: Observe que um procedimento no retorna valor. Portanto, no podemos fazer atribuio de um procedimento a uma varivel nem pass-lo como argumento.

#include <stdio.h> int s,a; void soma (int i) { s = s + i; } int main(void) { s = 1; a = soma (5); // Errado!!! printf ("A: %i\n",a); return 0; }

Algoritmos e Programao

Francisco Rapchan rapchan@terra.com.br

Passagem de Parmetro por Referncia (ponteiros) H duas formas de passagem de parmetros: Passagem de parmetros por valor. Passagem de parmetros por referncia.

A passagem de parmetros por valor a forma que temos usado em todos os exemplos at agora. Dizemos que parmetros passados por valor so parmetros de entrada. O valor do argumento passado para dentro da funo atravs dos parmetros. Assim, os parmetros recebem os valores dos argumentos.

Exemplo 6. O cdigo apresentado abaixo usa o procedimento soma para incrementar o valor de s em i unidades.

#include<stdio.h> int a,s; void soma (int i) { s = s + i; } int main (void) { s = 1; a = 1; soma (5); printf ("%i %i\n",a,s); }

No procedimento soma, o parmetro i passado por valor. Dizemos que i um parmetro de entrada. Quando o programa executa o procedimento soma(5) o argumento 5 passado para o parmetro i que ir armazenar este valor. O parmetro i uma varivel que ocupa um espao em memria e, neste caso, coloca o valor 5 neste espao. Observe que o procedimento soma muito pouco verstil. Ele s pode incrementar o valor de s. Caso quisssemos alterar o valor de a teramos que criar um outro procedimento soma para a.

Seria interessante um procedimento em que tivssemos dois parmetros: um indicando a varivel que desejamos alterar e outro o valor que queremos somar! Mas no seria to fcil. O cdigo abaixo, por exemplo, no funcionaria adequadamente:
#include<stdio.h> int a,s; // Variveis globais

void soma (int n, int i) { n = n + i; } int main (void) { s = 1; a = 1; soma (s,5); soma (a,3); printf ("%i %i\n",a,s); system ("PAUSE"); }

Neste caso, o procedimento soma chamado duas vezes. Na primeira o parmetro n recebe o argumento s que vale 1. Ento n passa a valer 1 e somado com 5 dando 6 como resultado. Mas n no altera o valor de s. O parmetro n existe apenas durante o breve tempo em que o procedimento soma executado. Assim que o procedimento termina sua execuo a rea de memria ocupada por n liberada (apagada). Desta forma, o resultado impresso ser 1 1.

Algoritmos e Programao

Francisco Rapchan rapchan@terra.com.br

Na passagem de parmetro por referncia no criado um novo espao de memria para o parmetro. O que acontece que o parmetro vai usar o mesmo espao de memria usado pelo argumento. Nesse caso passado como argumento um ponteiro para a varivel e no o seu valor. Para indicar que um parmetro passado por valor e no por referncia, colocamos a expresso * na frente dele na declarao da funo ou do procedimento. Assim, corrigindo o exemplo dado acima: #include<stdio.h> int a,s; void soma (int * n, int i) { *n = *n + i; } int main (void) { s = 1; a = 1; soma (&s,5); soma (&a,3); printf ("%i %i\n",a,s); } Neste caso o procedimento soma tem o parmetro n passado por referncia e o parmetro i passado por valor. Dizemos que n um ponteiro para um inteiro qualquer. Na chamada do procedimento soma(&s, 5) o parmetro n ir compartilhar a mesma rea de memria da varivel s, ou seja, ser passado o endereo de s para o parmetro n. Assim, alterar n equivale a alterar s. Na chamada seguinte, soma(&a, 3) o parmetro n ir compartilhar a mesma rea de memria da varivel a (o endereo de a passado como argumento). Assim, alterar n equivale a alterar a. O resultado impresso ser 4 6.

Exemplo 7. Faa um procedimento que execute um swap, ou seja, que troque os valores de dois argumentos.
#include<stdio.h> // Procedimento troca (swap) void troca (int *a, int *b) { int aux; aux = *a; *a = *b; *b = aux; } int main (void) { // Cria as variveis e inicia seus valores int x = 2, y = 5; // Executa o prcedimento troca() troca (&x,&y); // Mostra os valores invertidos por troca() printf ("%i %i\n",x,y); }

O procedimento troca possui dois parmetros: a e b. Ambos so do tipo inteiro e ambos so ponteiros para inteiros (ou seja, so parmetros por referncia). Isso significa que o procedimento dever receber os ponteiros para as variveis passados como argumento. No programa principal, troca chamado passando como argumento as variveis x e y. Lembre-se que, na verdade, so passados para troca os ponteiros para x e y! Assim, qualquer alterao que troca fizer em a ou b ser como se estivesse alterando diretamente x e y.

Vamos descrever, passo a passo, o que est sendo feito na funo troca:
aux = *a; //aux est recebendo o valor apontado por a *a = *b; //o valor apontado por a est sendo substitudo pelo o valor apontado por b *b = aux; //o valor apontado por b est sendo substitudo pelo valor de aux

Algoritmos e Programao

Francisco Rapchan rapchan@terra.com.br

Funes recursivas Podemos chamar uma funo de dentro da prpria funo. Essa tcnica chamada de recursividade. Se uma funo F chama a prpria funo F, dizemos que ocorre uma recurso. A implementao de alguns algoritmos fica muito mais fcil usando recursividade. Quando uma funo chamada recursivamente, cria-se um ambiente local para cada chamada. As variveis locais de chamadas recursivas so independentes entre si, como se estivssemos chamando funes diferentes. Exemplo 8. O cdigo apresentado abaixo usa o procedimento soma para incrementar o valor de s em i unidades.
#include <stdio.h> /* Calcula o long int fat { if (n==0) return else return } fatorial usando recursividade */ (int n)

1; n*fat(n-1);

main (void) { // Mostra o fatorial de 10 printf ("%i\n", fat(10) ); }

Exemplo 9. A srie de Fibonacci muito conhecida na matemtica. A srie composta assim, o primeiro e o segundo termos so 1. A partir do terceiro termo, todos os termos so a soma dos dois ltimos. Srie de Fibonacci: 1, 1, 2, 3, 5, 8, 13, 21, 34... Faa uma funo que encontre o ensimo termo da seqncia de Fibonacci. Use recursividade.
#include <stdio.h> int fib(int n) { if (n>2) return ( fib(n-1) + fib(n-2) ); else return 1; } main() { int n; printf("Digite um numero: "); scanf("%d", &n); printf("O termo %d da serie de Fibonacci e: %d\n", n, fib(n));

Algoritmos e Programao

Francisco Rapchan rapchan@terra.com.br

Passando parmetros para um programa (os argumentos argc e argv)

A funo main() uma funo especial que pode receber dois parmetros: int main (int argc, char *argv[]) argc (argument count) um inteiro e possui o nmero de argumentos com os quais o programa foi chamado na linha de comando. Ele no mnimo 1, pois o nome do programa contado como sendo o primeiro argumento. argv (argument values) um ponteiro para um vetor de strings . Cada string desse vetor um dos parmetros da linha de comando. argv[0] aponta para o nome do programa que o primeiro argumento.

Os nomes dos parmetros "argc" e "argv" podem ser mudados mas, por questo de padronizao, costuma-se no modific-los.

Exemplo 10. Faa um programa de forma que eu digite o nome do programa seguido de alguns nmeros inteiros e o programa mostre para mim a soma desses nmeros.

#include <stdio.h> #include <stdlib.h> int main ( int argc, char * argv[] ) { int i, s; s = 0; for (i = 1; i <= argc ; i++) s = s + atoi ( argv [i] ); printf ("Soma dos nmeros: %i\n",s); }

Supondo que esse programa se chame teste, ele poderia ser executado assim:
teste 2 8 5 Soma dos nmeros: 15

Em argc temos o nmero de argumentos e no vetor argv temos a lista desses argumentos. argv: Teste argc: 4 A funo atoi converte um string em um inteiro e est na biblioteca stdlib.h. 2 8 5

Exemplo 11. Faa um programa em que o usurio digite o nome de um arquivo e seja mostrado o seu contedo.
#include <stdio.h> int main ( int argc, char * argv[] ) { FILE *arquivo; char c; // Abre o arquivo para leitura arquivo = fopen (argv[1], "r"); if (arquivo == NULL){ printf ("Erro ao abrir o arquivo:%s",argv[1]); return 1; } // L caracteres at o fim do arquivo while((c = getc(arquivo)) != EOF) printf("%c", c); fclose (arquivo); return 0; }

Suponha que este programa chame-se mostra. Ento poderamos execut-lo assim: > mostra teste.c Neste caso, seria mostrado o contedo do arquivo teste.c na tela.
Observe tambm o comando while ((c = getc (arquivo)) != EOF)

Nesse comando estamos usando getc para ler um caractere. Este caractere est sendo atribudo varivel c. Depois o contedo da varivel c est sendo comparado a EOF (caractere de fim de arquivo). Assim, enquanto o caractere lido no for EOF, mostre na tela.

Poderamos substituir o comando while deste programa pelo seguinte comando for: for ( c = getc(arquivo) ; c != EOF ; c = getc(arquivo) )

Algoritmos e Programao

Francisco Rapchan rapchan@terra.com.br

Mais alguns exemplos

Exemplo 12. O programa abaixo mostra o texto o valor do fatorial dos nmeros 1 at 10. #include <stdio.h> void mensagem (void) { printf ("Ola Mundo!\n"); } int main (void) { mensagem(); return 0; } Observe que a funo mensagem no tem nenhum argumento (void) e tambm no retorna nenhum valor. Funes que no retornam valor tambm so chamadas de procedimentos.

Exemplo 13. O programa abaixo calcula a mdia de um conjunto de elementos.


#include <stdio.h> #define MAX 10 //define MAX com valor 10

// prottipo da funo float media (int vet_num[], int limite); // funo principal int main (void) { int num, i, vet[MAX]; printf ("Nmero de elementos: "); scanf ("%d",&num); for (i = 0; i< num; i++) { printf ("Nmero %d: ",i+1); scanf ("%d",&vet[i]); } printf ("Mdia: %f\n", media (vet, num)); return 0; } // definio da funo float media (int vet_num[], int limite) { int i, soma = 0; for (i = 0; i< limite; i++) soma = soma + vet_num[i]; return (soma / limite); }

A expresso #define permite definir algumas macros de compilao. Neste programa, onde houver o termo MAX, ser substitudo por 10. Esta substituio feita pelo prprio compilador imediatamente antes de compilar.
Outra coisa interessante neste programa que mostra o uso de prottipos de funo. A idia que permitido usar uma funo antes de definila desde que tenha sido definido pelo menos o seu prottipo, ou seja: o seu tipo de retorno, seu nome e os tipos de seus argumentos.

Observe tambm que, ao contrrio das variveis comuns, o contedo de um vetor pode ser modificado pela funo chamada. Isto ocorre porque a passagem de vetores para funes feita por referncia.

Algoritmos e Programao

Francisco Rapchan rapchan@terra.com.br

Вам также может понравиться