PRÁTICA - MODULARIZAÇÃO
Uma das características mais importantes da linguagem C são as funções, pois são nelas que ocorrem todas as atividades de um programa. Cada função equivale a um bloco de instruções, o qual pertence exclusivamente à mesma, não podendo ser acessado por nenhuma outra, exceto por meio de uma chamada à esta função.
Dividindo o programa em várias funções, torna-se mais fácil a detecção de erros e organização do código. É importante observar que na linguagem C não existe distinção entre funções (possui um único retorno) e procedimentos (não possui retorno algum).
<tipo de dado> <identificador> (lista de parâmetros)
Tipo de dado: especifica o tipo de valor que o comando return devolve á função, consistindo do seu único valor de retorno. Quando este campo não foi informado, o compilador interpreta como seu tipo de dado padrão int (inteiro).
Identificador: corresponde ao nome dado a função, respeitando todas as regras de dar nomes a objetos (variáveis e constantes) na programação computacional.
Lista de parâmetros: compreende valores que serão enviados pela chamada da função que necessita enviar alguns dados para dentro dela, de forma que ela possa resolver corretamente o que lhe é solicitado.
É similar a uma "lista de variáveis" separadas por vírgula e entre os parênteses da função, com seus respectivos tipos de dados totalmente compatíveis com os definidos em sua declaração (protótipo da função). Uma função pode ter vários parâmetros ou nenhum, mas sempre deve possuir seus parênteses: ( - abrir e ) - fechar.
Exemplos - observe alguns protótipos a seguir:
float media (float nota1,float nota2); //função //float com 2 parâmetros float int soma (int valor1, int valor2); //função int com //2 parâmetros int char mostra ( ); //função char sem nenhum parâmetro potencia (int exp, float base, char resp);
A função deve ser declarada no início do programa a ser elaborado por meio do seu protótipo. Após a criação da função principal (função main), o corpo da função desejada, e já declarada pelo seu protótipo, deve ser definido, consistindo ele na cópia de sua declaração (protótipo), sem o ponto e vírgula (;) no final. Em seguida, similar a função principal, o corpo da nova função começa a ser definido, sempre entre chaves: { - abrir e } - fechar.
Exemplo - observe o corpo da função MEDIA que teve seu protótipo (declaração) realizado no exemplo anterior:
float media (float nota1, float nota2) { //Declarações float resultado; //criação de uma nova variável, sendo ela local //Instruções resultado = (nota1 + nota2) / 2; return (resultado); }
Este exemplo mostra uma função que calcula a média entre duas notas e retorna o resultado deste cálculo. Observe qual seria o algoritmo desta função e veja a similaridade da criação de ambos.
funcao real media (real nota1, real nota2) //corpo da função real resultado; //criação da variável local resultado resultado = (nota1 + nota2) / 2; retorna resultado; fimFuncao
Todo programa em C consiste em uma ou mais funções, sendo a main a única função que necessariamente precisa estar presente em qualquer programa, pois ela é a primeira a ser chamada quando a execução do programa começa. Por se tratar de uma função, a main segue as mesmas regras de declaração de uma função. Também é chamada de função principal.
Existem duas maneiras de se passar dados para dentro de uma função, sendo elas conhecidas como: passagem por VALOR ou por REFERÊNCIA.
Quando uma função é chamada, a mesma função faz cópias dos valores enviados como parâmetros, dessa forma os valores originais não são alterados, pois a função manipula apenas as cópias dos mesmos.
Os valores existentes na função que foi chamada não podem ser acessados por outras funções, a menos que estes valores sejam enviados por parâmetros para outras funções, a partir da mesma, ou ainda retornados por ela. Todos os valores de uma função são apagados com o término da execução da mesma.
Ao invés de se fazer uma cópia dos valores existentes na função principal, a função que é chamada leva como parâmetro o endereço de memória original das variáveis que ela manipulará durante sua execução, por meio dos parâmetros enviados a ela.
Neste tipo de passagem de parâmetros, o valor original da variável pode ser alterado, já que a função tem acesso ao seu endereço original, onde o dado manipulado esta realmente armazenado na memória do computador. Quando esta função é encerrada, o conteúdo enviado para ela não é destruído, pois ela somente recebeu o endereço original pertencente a outra função, normalmente a função principal, que só permitirá sua destruição quando ela for encerrada. Porém, quando uma função principal é encerrada o programa termina.
Exemplo:
& - o "E comercial" na linguagem C é o operador de endereço e indica a
O comando return é usado na execução de duas ações na função, similar ao que já foi estudado no comando retorna em algoritmo. Este comando finaliza a função fazendo com que sua execução retorne à função chamadora e devolva um único valor existente dentro desta função para a função chamadora.
Todas as funções, com exceção as do tipo de dado void, retornam um único valor. Caso não exista nenhum comando return presente, o valor de retorno será tecnicamente indefinido (na maioria dos casos, os compiladores C devolvem ZERO quando não há nenhum valor de retorno especificado, mas isto não é recomendado para elaboração de programas eficientes). Uma função pode ter vários comandos return, mas somente um será executado realmente, pois após a sua execução ele encerra a função em execução e retorna para função chamadora, imediatamente.
Na linguagem C, procedimento corresponde a uma função sem retorno, como em algoritmo. Nesta linguagem não existe distinção entre função e procedimento, sendo ambos tratados como função, ou seja, um subprograma com lógica bem definida que pode ser acionada quantas vezes sejam necessárias para solucionar um problema.
O procedimento corresponde a uma função do tipo void (tipo de dado indefinido) que não possui o comando return devolvendo algum valor para a função chamadora. Desta forma se for preciso armazenar os dados coletados durante a execução da função pode-se recorrer a passagem de parâmetros por referência, uso de variáveis globais ou ainda alguns outros métodos que serão estudados mais adiante sobre esta linguagem de programação computacional.
As variáveis locais são variáveis que são declaradas dentro das funções. Somente as funções que as criaram podem utilizá-las, sendo que após o término da função, estas variáveis são destruídas (apagadas da memória do computador).
Exemplo:
/* SÍNTESE Objetivo: Determinar se um estudante foi aprovado ou reprovado Entrada: Média Saída: Mensagem informativa de "Aprovado" ou "Reprovado" */ #include <stdio.h> #include <conio.h> //de acordo com a versão do Dev-C pode ser usada <conio.c> void main (void) { //Declarações int situacao (float val); //declaração de outra função (seu protótipo) float media; int verifica; //Início printf("Informe a media do aluno"); scanf("%f",&media); //lê a média do aluno verifica = situacao(media); //verifica recebe o resultado da função if(verifica == 1) puts("APROVADO"); else puts("REPROVADO"); getch(); return(0); } //Corpo da função situacao (descrição do que a função situacao faz int situacao (float val) //parâmetro VAL só existe dentro da função { //funcionando como uma variável local // Declarações int auxiliar; //declaração de variável local - só existe dentro da função //Instruções if(val >= 7) auxiliar=1; else auxiliar=2; return(auxiliar); //valor de auxiliar é retornado para função chamadora } /* Após a execução do comando return a variável auxiliar e o parâmetro val são apagados da memória, ou seja, são destruidos */
Supondo uma execução, onde o usuário tenha informado o valor 8.9 para a variável media, observe o resultado do programa acima na tela a seguir:
As variáveis globais, ao contrário das locais, são declaradas fora de qualquer função (inclusive da função main), sendo seu conteúdo acessado por todas as funções que compõem o programa como um todo, pois tal variável (ou constante) é global e só será destruída da memória quando o programa terminar, ou seja, somente quando a função principal encerrar sua execução.
Exemplo:
/* SÍNTESE Objetivo: inicializar um vetor com um valor. Entrada: valor Saída: vetor inicializado. */ #include <stdio.h> #include <conio.h> void inicializaVetor(int vetor[],int valor); void mostravetor( int vetor[]); //declarações globais dos procedimentos int TAMANHO = 5; //declara�ao da variavel global int main (void) { //Declarações int vetor[5], valor; //Instruções printf("Digite o valor para iniciar os elementos do vetor: " ); scanf("%d",&valor ); inicializaVetor(vetor, valor); // Passagem de parametros para o procedimento mostravetor(vetor); // chamada do procedimento que mostra o vetor system("pause"); return 0; } void inicializaVetor(int vetor[], int valor){ // procdimento que inicializa o vetor //Declara�oes locais int i; // instrucoes for ( i = 0; i < TAMANHO; i++) { vetor[i] = valor; } } void mostravetor( int vetor[]){ // procedimento que exibe o vetor //Declara�oes locais int i; // instrucoes puts(" "); printf("vetor: "); for ( i = 0; i < TAMANHO; i++) { printf("%d ", vetor[i]); } } /* Mesmo após o término da execução da função, o conteúdo de TAMANHO continua disponível na memória, pois estas variáveis são globais */
Supondo que o usuário informou o nome Carlos Henrique e o país Argentina, o resultado da execução seria:
O uso de variáveis globais não é recomendado, pois facilita a ocorrência de alguns problemas e dificulta a localização de erros no código fonte, além de não contribuir com a segurança no uso de funções (subprogramas em geral) devido as variáveis serem públicas durante toda a execução do programa, podendo serem alteradas a qualquer momento no mesmo.
Uma função pode chamar outras funções durante o seu funcionamento. Quando isso acontece, o funcionamento da função que chamou é interrompido e a função chamada entra em execução. Após seu término, o programa continua a execução de onde parou, neste caso, logo após a chamada de função.
Exemplo:
/* Síntese Objetivo: encontra a posição em que um valor estó dentro do vetor. Entrada: valor. Saída: posição em que o valor está e vetor ordenado. */ #include <stdio.h> #include <stdlib.h> int buscaBinaria(int vetor[],int valor,int tamanho);//protótipo da função int main(void) { //Declarações //inicializaçao do vetor com valores nao ordenados int vetor[14] = {10,20,8,9,15,1,0,80,32,60,2,3,4,5}; int tamanho = 14; // tamanho do vetor int valor,posicao,i; //Instruções printf("Digite o numero que deseja encontar:"); scanf("%d",&valor ); //chamanda da função que retona a poição do valor posicao = buscaBinaria(vetor,valor,tamanho); if (posicao == -1){ printf("valor nao encontrado\n"); }else{ printf("o valor procurado esta na posição: %d\n",posicao ); } // imprime o vetor após a ordenaçãao printf("\n vetor ordenado: "); for(i = 0; i < tamanho ; i++){ printf("%d ",vetor[i]); } getch(); return 0; } //======= FUNÇÕES E PROCEDIMENTOS ====== void ordenaVetor(int vetor[],int tamanho){ //procedimento que ordena o vetor //Declarações locais int i,j,aux; //instruções for ( i = 0; i < tamanho; i++) { for ( j = 0; j < tamanho - 1; j++) { if (vetor[j] > vetor[j+1] ){ aux = vetor[j]; vetor[j] = vetor[j+1]; vetor[j+1] = aux; } } } } int buscaBinaria(int vetor[],int chave,int Tamanho){//função que faz a busca no vetor //Declarações locais void ordenaVetor(int vetor[],int tamanho); int inferior = 0; // limite inferior (o primeiro índice de vetor em zero) int superior = Tamanho-1; // limite superior (termina em um número a menos ) int meio; //instruções ordenaVetor(vetor,Tamanho); while (inferior <= superior) { meio = (inferior + superior)/2; if (chave == vetor[meio]) return meio; if (chave < vetor[meio]) superior = meio-1; else inferior = meio+1; } return -1; // se o valor não for encontrado }
Assim como as variáveis, as funções também podem ser globais e locais, onde as funções locais só podem ser acessadas pelas funções nas quais estão declaradas, enquanto as funções globais podem ser utilizadas por todas as funções que compõem o programa. As regras de declaração das variáveis aplicam-se também às funções e/ou procedimentos.
Observe no exemplo anterior que a função denominada buscaBinaria esta declarada fora de qualquer outra função, sendo ela então uma função global, porém a função ordenaVetor esta declarada dentro da função buscaBinaria, o que faz dela uma função local podendo ser acionada somente a partir da função buscaBinaria e seu retorno será também para ela (a função buscaBinaria).
Atividade de Fixação
No intuito de fixar a aprendizagem iniciada por meio deste módulo e verificar como seu entendimento sobre este conteúdo está, estão sendo sugeridos alguns exercícios de fixação para serem resolvidos. Clique no link de exercícios ao lado, pois será por meio dele iniciada a lista de exercícios sobre os conteúdos estudados até este momento nesta disciplina.