Baixe o app para aproveitar ainda mais
Prévia do material em texto
1 LINGUAGEM E TÉCNICA DE PROGRAMAÇÃO I Profa. Gisele Busichia Baioco gisele@ft.unicamp.br Modularização de Programas Subprogramas em C Parte 1 – Conceitos Básicos 1 Introdução Em C, os subprogramas são todos classificados como funções, sendo que os procedimentos são considerados como funções que não retornam valores. Na realidade um programa C é todo composto por funções, inclusive o main() é uma função. O objetivo de se utilizar funções é a modularização de programas, pois as funções dividem grandes tarefas computacionais em tarefas menores. Além disso, o uso de funções: • permite que programadores utilizem o que outros programadores já implementaram ao invés de partir da estaca zero; • evita que o programador tenha que escrever o mesmo código repetidas vezes. Por exemplo, suponha que exista em um programa uma operação onde se calcula o quadrado de um número. Se mais adiante no mesmo programa for necessário realizar a mesma operação, a solução mais direta seria escrevê-la novamente. Entretanto, com o uso de funções, basta escrever uma seção de código para calcular o quadrado de um número qualquer e usá-la em todos os pontos do programa que é necessário calcular o quadrado. Assim, uma função em C é uma unidade de código de programa autônoma, desenhada para cumprir uma tarefa particular. É importante observar que a chamada de uma função aumenta o tempo de execução de um programa. Entretanto, na maioria das aplicações, esse custo adicional de tempo de execução é deixado de lado pelos outros benefícios trazidos pelo uso de funções (legibilidade, reutilização de código, facilidade de manutenção etc). Assim, o uso de funções só deve ser evitado quando o tempo de execução for realmente primordial. 2 Declaração de funções em C Sintaxe de declaração de uma função em C: tipo-de-retorno nome-da-função(lista-de-parâmetros) { corpo-da-função } onde: tipo-de-retorno: é opcional e especifica o tipo do valor que a função retornará. Caso o tipo não tenha sido especificado, por default (padrão) a função retornará um resultado inteiro (tipo int). nome-da-função: qualquer identificador válido em C. 2 lista-de-parâmetros: é opcional e consiste de uma lista composta por tipos de dados e nomes de variáveis, que são os parâmetros da função, separados por vírgula. Sintaxe: tipo-de-dado nome-do-parâmetro1, ..., tipo-de-dado nome-do-parâmetroN corpo-da-função: consiste da implementação da função. É nele que as entradas são processadas, saídas são geradas ou outras coisas são feitas. Deve-se observar que uma função não terá que ter obrigatoriamente uma lista de parâmetros e nem sempre devolverá um valor. Um tipo void deve ser utilizado para funções que não retornam valor. Exemplos: /* Declaração da função soma, que retorna o resultado da soma de seus parâmetros */ float soma(float x, float y) { return (x+y); } /* Declaração da função imprime_soma, que imprime o resultado da soma de seus parâmetros na tela, não retornando valor */ void imprime_soma(float x, float y) { printf(“%f”, x+y); } 3 Protótipos de Funções Protótipo de função é a definição de uma função, declarando o tipo e o número de parâmetros da mesma. Protótipos de funções devem ser colocados perto do início do programa, antes do main(), para que o compilador possa fazer as verificações de tipo de retorno e tipos de parâmetros das chamadas das funções que, em sua maioria estarão dentro do main(). As declarações das funções ficam, então, após o main(). Sintaxe de protótipos de funções em C: tipo-de-retorno nome-da-função(lista-de-tipos-dos-parâmetros); Exemplos: #include <stdio.h> /* Protótipos de funções */ float soma(float, float); void divide(float, int); main() { float prim, seg, res; int terc; prim = 10.5; seg = 9.4; terc = 3; res = soma(prim, seg); /* Chamada da função soma */ printf("%f\n", res); 3 divide(seg, terc); /* Chamada da função divide */ } /* Declaração da função soma, que retorna o resultado da soma de seus parâmetros */ float soma(float x, float y) { return (x+y); } /* Declaração da função divide, que imprime na tela o resultado da divisão de seu segundo parâmetro pelo primeiro, não retornando valor */ void divide(float a, int b) { printf("%f\n", a/(float)b); } Os protótipos de funções foram acrescentados pela comissão do padrão ANSI C, para permitir que C faça uma verificação forte de tipos, parecida com a do Pascal. Isso faz com que o compilador emita mensagens de erros quando não há coincidência de tipos entre os argumentos da função chamada e os parâmetros declarados. 4 O Comando return O comando return é utilizado para interromper a execução de uma função e voltar para a parte do código que a chamou, retornando ou não um valor. Suponha que uma função está sendo executada. Quando se chega a um comando return a função é encerrada imediatamente e, se o valor de retorno é informado, a função retorna esse valor. 4.1 Retorno de uma função O retorno de uma função sem nenhum valor pode ser executado de duas maneiras: • o computador executa o último comando da função e depois encontra } que significa o fim da função; • usando o comando return sozinho, sem nenhum valor associado a ele. Sintaxe do comando return, sem nenhum valor associado: return; 4.2 Valores de retorno Quando usado para retornar um valor, o comando return tem a seguinte sintaxe: return valor-de-retorno; É importante lembrar que o valor de retorno fornecido tem que ser compatível com o tipo de retorno declarado para a função. Na chamada de um função, pode-se atribuir valores de retorno da função a uma variável, mas uma função não pode ser objeto de uma atribuição. Exemplos: x = abs(y) /* comando coreto */ swap(x,y) = 100 /* comando incorreto */ 4 No segundo exemplo, haverá um erro de compilação. Embora todas as funções que não sejam do tipo void retornem valores, pode-se criar funções de dois tipos: • computacional: função criada especificamente para efetuar operações em seus argumentos e devolver um valor com base naquelas operações. Por exemplo, as funções de biblioteca sqrt() e sin(), que devolvem a raiz quadrada de um número e seu seno, respectivamente. • função que manipula informações e cujo valor retornado indica o sucesso ou o fracasso da mesma: por exemplo, a função fwrite(), usada para gravar informações em um arquivo em disco e que devolve o número de bytes caso a gravação seja bem sucedida e qualquer outro valor caso contrário. O valor retornado por uma função pode não ser utilizado. Por exemplo, a função printf() retorna o número de caracteres impressos, porém não seria comum encontrar um programa que realmente verificasse esse valor de retorno. 4.3 Exemplos da utilização de return #include <stdio.h> /* Protótipo da função */ int quadrado(int); main() { int num; printf ("Entre com um numero inteiro: "); scanf ("%d",&num); num = quadrado(num); printf("\nO seu quadrado vale: %d",num); } /* Declaração da função quadrado que retorna o valor do quadrado de um número inteiro passado como parâmetro */ int quadrado(int a) { return(a*a); } #include <stdio.h> /* Protótipo da função */ int par(int); main() { int num; printf ("Entre com numero inteiro: "); scanf ("%d",&num); if (par(num) == 1) printf ("\nO numero e par."); else printf ("\nO numero e impar."); } 5 /* Declaração da função par, que retorna 1 se o valor passado como parâmetro é par e 0 caso contrário */ int par(int a) { if (a%2 == 0) /* Verifica se a é divisível por dois */ return 1; /* Retorna 1 se for divisível – é par */ else return 0; /* Retorna0 se não for divisível – não é par */ } Como pode ser observado, no último exemplo uma função pode ter vários comandos return. 5 O Tipo Void Em inglês, void quer dizer vazio e é isto mesmo que o void é. Ele permite fazer funções que não retornam nenhum valor e funções que não têm parâmetros. Uma função que não retorna nenhum valor é similar a um procedimento. Pode-se agora escrever o protótipo de uma função que não retorna valor algum: void nome-da-função(lista-de-prâmetros); Em uma função como a anterior, não existe valor de retorno em return. Aliás, neste caso, o comando return não é necessário na função. Pode-se também fazer funções que não têm parâmetros: tipo-de-retorno nome-da-função(void); ou, ainda, funções que não tem parâmetros e não retornam nada: void nome-da-função(void); Um exemplo de funções que usam o tipo void: #include <stdio.h> void mensagem (void); main () { mensagem(); printf ("\nDiga de novo:\n"); mensagem(); } void mensagem (void) { printf ("Ola! Eu estou vivo.\n"); } Deve-se lembrar agora que a função main() é uma função. O compilador acha que a função main() deve retornar um inteiro. Isso pode ser interessante caso se deseje que o sistema operacional receba um valor de retorno da função main(), considerando a seguinte 6 convenção: se o programa retornar zero, significa que ele terminou normalmente, e, se o programa retornar um valor diferente de zero, significa que o programa teve um término anormal. Caso não seja necessário o retorno de main(), basta declara-lo como void. As duas funções main() abaixo são válidas: main() /* ou int main() ou int main(void) */ { ... return 0; } void main() /* ou void main(void) */ { ... } A primeira opção é válida pois, como já visto anteriormente, as funções em C têm por default retorno inteiro. Alguns compiladores podem reclamar da segunda opção, dizendo que main() sempre deve retornar um inteiro. Se isto acontecer basta utilizar a primeira opção. 6 Escopo de Variáveis As regras de escopo determinam quais variáveis são acessíveis dentro de um certo trecho do programa e estabelecem o tempo de vida (tempo em que uma variável fica alocada na memória) das mesmas. Além disso, pode-se dizer que o código e os dados que são definidos dentro de uma função não podem interagir com o código e dados que são definidos em outra função, pois seus escopos são diferentes. De acordo com as regras de escopo de C, existem três tipos de variáveis: variáveis locais, parâmetros formais e variáveis globais. 6.1 Variáveis locais As variáveis locais são aquelas definidas dentro de uma função ou dentro de um bloco de código. Logo, essas variáveis serão conhecidas apenas dentro da função ou do bloco de código onde foram declaradas. Exemplo: void f() { char ch; /* esta variável só é criada na função f */ printf("continua? (S/N):"); ch = getche(); if (ch == 'S') /* segue apenas se a resposta for 'S' */ { char s[80]; /* esta variável só é criada neste bloco */ printf("Digite seu nome: "); gets(s); } } Desse modo, as variáveis são criadas (alocadas na memória) na entrada da função ou do bloco de código e destruídas (desalocadas da memória) na saída. Conseqüentemente, seu conteúdo é perdido quando a execução da função ou do bloco termina. 7 6.2 Parâmetros formais Os parâmetros formais são especificados na declaração das funções. Esses parâmetros são as variáveis que aceitarão os valores dos argumentos (ou parâmetro reais) que são passados na chamada de uma função. Exemplo: main() { int a, b, res; ... res = func(a, b); /* a e b são argumentos ou parâmetros reais */ ... } int func(int s, int c) /* s e c são parâmetros formais */ { return (s*c); } Os parâmetros formais são desconhecidos quando a execução da função termina. Atenção: deve-se verificar sempre se os parâmetros formais declarados são do mesmo tipo dos argumentos que usados para chamar a função. 6.3 Variáveis globais As variáveis globais são declaradas fora de qualquer função C e são conhecidas e acessíveis em todo o programa, pois fica alocada na memória durante toda a execução do programa. Caso uma variável local e uma global tenham o mesmo nome, todas as referências aquele nome dentro da função na qual a variável local estiver declarada, estarão ligadas à variável local e não terão nenhum efeito sobre a variável global. Sempre que possível deve-se utilizar outro tipo de variável, pois as variáveis globais têm as seguintes desvantagens: • ocupam memória durante toda a execução do programa e não apenas quando são necessárias; • o uso de uma variável global, quando é viável a utilização de uma local, torna a função menos generalizada; • o uso de muitas variáveis globais pode levar a programação a erros por causa de efeitos colaterais desconhecidos e indesejados. 6.4 Exemplo geral de escopo /* um programa com vários escopos */ int cont /* variável global */ void func(int); /* protótipo de func */ main() { int s; /* local a main() */ 8 func(s); } void func(int r) /* r é o parâmetro formal de func */ { if (r) { int a, b; /* locais ao bloco if dentro de func */ ... } ... } 7 Exercícios de Fixação 1. Fazer uma função C que calcule e imprima na tela a média aritmética de dois números. Fazer um programa C para testar a função. 2. Fazer uma função C que calcule e retorne um número inteiro elevado a qualquer potência (inteira). Fazer um programa C para testar a função. 3. Fazer uma função C que determine e retorne o maior de três lados de um triângulo passados como parâmetros. Fazer um programa C para testar a função. 4. Um número é primo se for divisível apenas por si próprio e por 1. Fazer uma função primo(int num) para verificar se um número passado como parâmetro é primo. A função deve retornar 1 se o número for primo e 0 caso contrário. Em seguida fazer uma função divisor(int a, int b) que verifica se b é divisor de a (b é divisor de a se o resto da divisão de a por b é zero). A função deve retornar 1 se b for divisor, caso contrário deve retornar zero. Usando as duas funções construídas, fazer um programa C para determinar os divisores primos de um número. 5. Estude o seguinte programa e aponte o valor de cada variável sempre que solicitado: #include <stdio.h> int num; int func(int, int); main() { int first = 0, sec = 50; num = 10; num = num + func(first, sec); /* Qual é o valor de num, first e séc antes e depois da atribuicao? */ printf("\nConfira: num = %d first = %d sec = %d",num, first, sec); } int func(int a, int b) { a = (a+b)/2; /* Qual é o valor de a apos a atribuição? */ num = num - a; return a; }
Compartilhar