Programação com a Linguagem C

 

Funções e Estrutura de Programas

 

1 - Funções

 

·       Funções são uma das características mais importantes da linguagem C; o local onde toda a atividade do programa ocorre.

·       As funções dividem grandes tarefas de computação em tarefas menores.

·       Permitem às pessoas trabalharem sobre o que outras já fizeram.

·       Podem esconder detalhes de operação que não necessitam ser conhecidos.

·       Facilitam mudanças, já que cada função resolve um problema menor.

·       C utiliza várias pequenas funções eficientes e fáceis de usar (biblioteca).

·       O programa pode residir em vários arquivos-fonte.

·       Os arquivos-fonte podem ser compilados separadamente e carregados juntos, com funções de bibliotecas previamente compiladas.

·       Com o padrão ANSI, é possível declarar os tipos dos argumentos quando uma função é declarada.

·       A nova sintaxe possibilita às declarações casarem com as definições das funções, tornando possível uma melhor detecção de erros.

 

Conceitos Básicos

 

·       Observe o programa abaixo para cálculo do fatorial de um número inteiro.

 

#include <stdio.h>

#include <conio.h>

 

void main() {

 

     int numero, fatorial, fator;

 

     clrscr();

     printf("\nValor para o fatorial:");

     scanf("%d", &numero);

 

     fatorial = 1;

     for(fator = 1; fator <= numero; fator++) {

         fatorial = fatorial * fator;

     }

     printf("\nFatorial de %d = %d", numero, fatorial);

}

 

·       Podemos representar o processamento para cálculo do fatorial através de uma função. Nesse caso, o programa acima seria:

 

#include <stdio.h>

#include <conio.h>

 

void main() {

 

     int numero;

     int fatorial(int valor);

 

     clrscr();

 

     printf("\nValor para o fatorial:");

     scanf("%d", &num);

 

     printf("\nFatorial de %d = %d", num, fatorial(num));

}

 

int fatorial(int numero) {

 

     int fator, fat;

     fat = 1;

     for(fator = 1; fator <= numero; fator++) {

         fat = fat * fator;

     }

     return fat;

}

 

·       Outro exemplo de uso de função:

 

#include <stdio.h>

#include <conio.h>

 

/* Programa para gera uma tabela de conversão de

   graus Celcius para Farenheit, com valores de

   Farenheit = -10.0, -9.5, -9.0, ... , 9.5, 10.0

*/

void main() {

 

     int numero;

     float gfparagc(float tempf);

 

     clrscr();

     printf("\Graus Farenheit   Graus Celcius\n");

     for(grausf = -10.0; grausf <= 10.0;

         grausf += 0.5) {

         grausc = 5.0 / 9 * (grausf – 32);

         printf("   %12.3f   %12.3\n", grausf,

                gfparagc(grausf));

     }

}

 

float gfparagc(float farenheit) {

 

     return 5.0 / 9 * (farenheit – 32);

}

 

·       Forma geral de definição de uma função:

 

     tipo-retorno nome(declarações de parâmetros) {

         declarações e comandos - corpo da função

     }

 

·       A lista de declaração de parâmetros para uma função tem esta forma geral:

 

     func(tipo nomeVar1, tipo nomeVar2, …, tipo nomeVar3) {

 

·       A menor função que poderíamos escrever:

 

vazia() {}

 

·       Quando o tipo de retorno não é especificado considera-se o tipo int.

·       A comunicação entre funções é feita essencialmente através de: argumentos e retorno.

·       Os argumentos de uma função são passados na sua chamada.

 

. . .

     func(valor1, valor2);

     . . .

 

·       O retorno do valor de uma função é realizado pelo comando return.

 

     return expressão;

 

·       O comando return tem duas funcionalidades: provocar uma saída imediata da função que o contém, devolver um valor ao programa chamador.

·       A chamada da função pode ignorar o valor retornado.

·       As funções podem retornar valores numéricos ou literais, além de apontadores.

·       Se o tipo do retorno da função é void, pode-se deixar de colocar o comando return.

·       O controle retorna sempre que o fluxo atinge o último comando da função mesmo sem return.

 

Regras de escopo de funções

·       Regras de escopo de uma linguagem são as regras que determinam se um trecho de código conhece ou tem acesso a outro trecho de código ou dados.

·       Em C, cada função é um bloco de código.

·       O código e os dados que são definidos internamente em uma função não podem interagir com o código ou dados definidos em uma outra função porque as duas têm escopos diferentes.

·       Variáveis internas a uma função são chamadas variáveis locais.

·       Variáveis locais não são reconhecidas (acessíveis) fora de seu próprio bloco de código.

·       O ciclo de vida de uma variável local está associado à execução da função – variáveis existem enquanto o bloco de código em que foram declaradas está sendo executado.

·       Ao contrário das variáveis locais, variáveis globais, aquelas que são definidas fora das funções, são reconhecidas pelo programa inteiro e podem ser usadas por qualquer trecho de código.

 

. . .

void func1(void);

void func2(void);

 

int contador; /* contador é uma variável global */

 

void main() {

     . . .

     contador = 100;

     func1();

     . . .

}

 

void func1(void) {

     int temp;

     temp = contador;

     . . .

     func2();

     printf(“O valor de contador eh %d”, contador);

}

 

void func2(void) {

     int indice, contador; /* contador é uma variável local */

    

     contador = 0;

     for(indice = 0; indice < 10; i++) {

         if(…) {

              contador++;

         }

     }

     printf(“O valor de contador eh %d”, contador);

}

 

·       Em C, todas as funções estão no mesmo nível de escopo, isto é, não é possível definir uma função internamente a uma outra função.

 

Especificadores de tipo de classe de armazenamento

 

·       Os especificadores de tipo de classe de armazenamento são aplicados às variáveis locais e/ou globais. Tais especificadores servem para indicar ao compilador como uma variável deve ser armazenada:

§        extern      avisa ao compilador que a variável foi definida em outro arquivo e que sua compilação será em separado.

§        static       avisa ao compilador que o conteúdo da variável local será conservado para as próximas chamadas da função.

§       register    avisa ao compilador que esta variável não será alocada na memória principal e sim num registrador da CPU.

·       Exemplo:

 

void serie (void) {

  static int num_serie = 0; /*variaveis locais estaticas*/

  num_serie = num_serie++;

  return (num_serie);

}

 

Argumentos de funções

·       Se uma função usa argumentos, ela deve declarar variáveis que receberão os valores dos argumentos; tais variáveis são denominadas parâmetros formais.

·       Os parâmetros formais se comportam como qualquer outra variável local dentro da função.

·       Aproveitando a definição da função fatorial(), já mostrada:

 

     int fatorial(int numero){

         . . .

     }

 

·       A função fatorial() tem um único parâmetro: numero. É preciso assegurar-se de que os argumentos usados para chamar a função sejam compatíveis com o tipo de seus parâmetros.

·       Incompatibilidade de tipos não são detectadas pelo compilador mas podem gerar resultados inesperados – o uso de protótipos de funções pode ajudar a achar esses tipos de erros, como veremos mais adiante.

·       Por exemplo: experimente chamar a função fatorial() da seguinte maneira:

 

#include <stdio.h>

#include <conio.h>

 

void main() {

 

     int numero;

 

     clrscr();

     printf("\nValor para o fatorial:");

     scanf("%d", &numero);

 

     printf("\nFatorial de %d = %d", numero,

            fatorial(“erro”));

 

}

 

·       Ocorreram erros de compilação? Qual o valor retornado?

·       Agora inclua no programa acima o protótipo da função fatorial:

 

#include <stdio.h>

 

int fatorial(int);

. . .

 

·       Quais as mudanças em relação ao comportamento do compilador?

 

Chamada por valor, chamada por referência

·       Os argumentos para funções são passados de duas maneiras: chamadas por valor ou por referência.

·       Na chamada por valor, copia-se o valor de um argumento no parâmetro formal da função. Nesse caso, alterações feitas no parâmetro da função não têm nenhum efeito sobre as variáveis usadas para chamá-la.

·       Na chamada por referência, o endereço é usado para acessar o argumento real passado na chamada da função. Nesse caso, as alterações feitas no parâmetro afetam a variável usada para chamar a função.

·       No uso da função fatorial(), verifica-se a chamada por valor.

 

int fatorial(int);

     . . .

  printf("\nFatorial de %d = %d", num, fatorial(num));

     . . .

 

·       Observe este outro exemplo de passagem de parâmetros por valor:

 

/*

   Cálculo do Máximo Divisor Comum entre dois inteiros

*/

#include <stdio.h>

#include <conio.h>

 

int leInteiro();

int mdc(int, int);

 

void main() {

    

     clrscr();

     printf¨("Cáculo do MDC entre dois números:\n\n";

     printf¨("MDC = %d\n", mdc(leInteiro(), leInteiro()));

}

 

int leInteiro() {

     int inteiro;

     printf("Informe o valor de um inteiro: \n");

     scanf("%d", &inteiro);

     return inteiro;

}

 

int mdc(int primeiro, int segundo) {

    

     while(primeiro != segundo) {

         if(primeiro > segundo) {

              primeiro = primeiro – segundo;

         else {

              segundo = segundo – primeiro;

         }

     }

}

 

·       Veremos a passagem de parâmetros por referência no próximo capítulo, quando aprenderemos a lidar com apontadores.

 

Argumentos para a função main() – argc e argv

·       É possível passar informações para a função main() através de argumentos da linha de comandos.

·       Um argumento da linha de comandos é a informação que segue o nome do programa na linha de comandos do sistema operacional. Por exemplo: (no DOS)

 

     C:\>cd turbo_C

 

·       Há dois argumentos internos especiais: argc e argv, que são usados para receber os argumentos da linha de comandos.

·       O argc contém o número de argumentos da linha de comandos e é um inteiro (seu valor é, no mínimo, 1, porque o nome do programa é qualificado como primeiro argumento).

·       O argv é um apontador para um vetor de apontadores para caracteres. Cada elemento nesse vetor aponta para um argumento da linha de comandos (no caso, strings).

·       Um exemplo simples:

     . . .

/* programa para mostrar mensagem de boas-vindas */

void main(int argc, char *argv[]) {

 

     clrscr();

     if(argc != 2) {

         printf(“\nERRO: voce esqueceu de digitar seu nome!”);

         exit(1); /* execucao do programa eh finalizada */

     }

     printf(“Bem-vindo %s!!!”, argv[1]);

}

 


Versão Word (.doc) do material acima.