Diferenças
Aqui você vê as diferenças entre duas revisões dessa página.
Ambos lados da revisão anterior Revisão anterior Próxima revisão | Revisão anterior | ||
c:funcoes [2023/08/31 11:19] – [Protótipos] maziero | c:funcoes [2023/09/05 16:17] (atual) – maziero | ||
---|---|---|---|
Linha 1: | Linha 1: | ||
+ | ====== Funções ====== | ||
+ | |||
+ | este módulo apresenta o uso de funções na linguagem C. Funções são o principal elemento de modularização de código nesta linguagem, são muito versáteis e extensivamente usadas. | ||
+ | |||
+ | ===== Declaração ===== | ||
+ | |||
+ | Em C, uma função é declarada da seguinte forma geral: | ||
+ | |||
+ | <return type> function_name (<type parameter>, | ||
+ | { | ||
+ | < | ||
+ | return < | ||
+ | } | ||
+ | |||
+ | Um exemplo trivial: uma função para somar dois inteiros: | ||
+ | |||
+ | <code c soma.c> | ||
+ | #include < | ||
+ | |||
+ | int soma (int a, int b) | ||
+ | { | ||
+ | return (a + b) ; | ||
+ | } | ||
+ | |||
+ | int main () | ||
+ | { | ||
+ | printf ("soma (2, 5): %d\n", soma (2, 5)) ; | ||
+ | return (0) ; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Um exemplo de função para calcular o fatorial de um número inteiro: | ||
+ | |||
+ | <code c fatorial.c> | ||
+ | #include < | ||
+ | |||
+ | long fatorial (int n) | ||
+ | { | ||
+ | int i ; | ||
+ | long fat ; | ||
+ | |||
+ | if (n <= 1) // por definição | ||
+ | fat = 1 ; | ||
+ | else | ||
+ | { | ||
+ | fat = 1 ; | ||
+ | for (i = 2; i <= n; i++) | ||
+ | fat *= i ; | ||
+ | } | ||
+ | |||
+ | return (fat) ; | ||
+ | } | ||
+ | |||
+ | int main () | ||
+ | { | ||
+ | printf ("fat (10): %ld\n", | ||
+ | return (0) ; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Obviamente, a função '' | ||
+ | |||
+ | <code c fatorial.c> | ||
+ | long fatorial (int n) | ||
+ | { | ||
+ | long fat ; | ||
+ | | ||
+ | if (n <= 1) | ||
+ | fat = 1 ; | ||
+ | else | ||
+ | fat = n * fatorial (n - 1) ; | ||
+ | | ||
+ | return fat ; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Ou: | ||
+ | |||
+ | <code c fatorial.c> | ||
+ | long fatorial (int n) | ||
+ | { | ||
+ | if (n <= 1) | ||
+ | return 1 ; | ||
+ | else | ||
+ | return (n * fatorial (n - 1)) ; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Ou ainda: | ||
+ | |||
+ | <code c fatorial.c> | ||
+ | long fatorial (int n) | ||
+ | { | ||
+ | return (n <= 1 ? 1 : n * fatorial (n - 1)) ; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | <note warning> | ||
+ | A linguagem C **não aceita** funções aninhadas (definidas dentro de outras funções). Assim todas as funções são definidas no mesmo nível hierárquico. Observe que **isso não impede de chamar uma função dentro de outra função**. | ||
+ | </ | ||
+ | |||
+ | Cabe observar que não é obrigatório usar o valor de retorno de uma função. Por exemplo, o código abaixo é perfeitamente válido (apesar de ser inútil): | ||
+ | |||
+ | <code c> | ||
+ | fatorial (20) ; | ||
+ | </ | ||
+ | |||
+ | O valor de retorno de uma função pode ser de qualquer tipo suportado pela linguagem C (tipos numéricos, ponteiros, //chars//, // | ||
+ | |||
+ | <code c> | ||
+ | void hello () | ||
+ | { | ||
+ | printf (" | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ===== Protótipos ===== | ||
+ | |||
+ | Em princípio, toda função em C deve ser declarada antes de ser usada. Caso o compilador encontre uma função sendo usada que não tenha sido previamente declarada, ele pressupõe que essa função retorna um '' | ||
+ | |||
+ | Em algumas situações não é possível respeitar essa regra. Por exemplo, se duas funções diferentes se chamam mutuamente, teremos: | ||
+ | |||
+ | <code c> | ||
+ | char patati (int a, int b) | ||
+ | { | ||
+ | ... | ||
+ | c = patata (x, y, z) ; // precisa declarar " | ||
+ | ... | ||
+ | } | ||
+ | |||
+ | char patata (int a, int b, int c) | ||
+ | { | ||
+ | ... | ||
+ | x = patati (n1, n2) ; | ||
+ | ... | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Para evitar problemas, é possível declarar um " | ||
+ | |||
+ | <code c> | ||
+ | // protótipos das funções " | ||
+ | char patati (int a, int b) ; | ||
+ | char patata (int a, int b, int c) ; | ||
+ | |||
+ | // implementação da função " | ||
+ | char patati (int a, int b) | ||
+ | { | ||
+ | ... | ||
+ | c = patata (x, y, z) ; // ok, patata tem um protótipo definido | ||
+ | ... | ||
+ | } | ||
+ | |||
+ | // implementação da função " | ||
+ | char patata (int a, int b, int c) | ||
+ | { | ||
+ | ... | ||
+ | x = patati (n1, n2) ; // ok, patati tem um protótipo definido | ||
+ | ... | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | <note tip> | ||
+ | Um protótipo de função pode ser visto como a sua " | ||
+ | </ | ||
+ | ===== Parâmetros ===== | ||
+ | |||
+ | Em C, os parâmetros das funções são transferidos sempre **por valor** (ou por cópia), pois os valores fornecidos na chamada da função são copiados para dentro da pilha (//stack//) e ficam à disposição do código interno da função. Em consequência, | ||
+ | |||
+ | Por exemplo: | ||
+ | |||
+ | <code c paramcopia.c> | ||
+ | #include < | ||
+ | |||
+ | void inc (int n) | ||
+ | { | ||
+ | n++ ; | ||
+ | printf ("n vale %d\n", n) ; | ||
+ | } | ||
+ | |||
+ | int main () | ||
+ | { | ||
+ | int a = 0 ; | ||
+ | printf ("a vale %d\n", a) ; | ||
+ | inc (a) ; | ||
+ | printf ("a vale %d\n", a) ; | ||
+ | return (0) ; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | A execução deste código resulta em: | ||
+ | |||
+ | a vale 0 | ||
+ | n vale 1 | ||
+ | a vale 0 | ||
+ | |||
+ | ===== Parâmetros por referência ===== | ||
+ | |||
+ | Para que as ações de uma função sobre seus parâmetros sejam visíveis fora da função, esses parâmetros devem ser informados **por referência**. C não suporta nativamente a passagem de parâmetros por referência, | ||
+ | |||
+ | <code c paramref.c> | ||
+ | #include < | ||
+ | |||
+ | void inc (int *n) | ||
+ | { | ||
+ | (*n)++ ; | ||
+ | } | ||
+ | |||
+ | int main () | ||
+ | { | ||
+ | int a = 0 ; | ||
+ | printf ("a vale %d\n", a) ; | ||
+ | inc (&a) ; // informar a referência (endereço) de a | ||
+ | printf ("a vale %d\n", a) ; | ||
+ | return (0) ; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | E a execução fica: | ||
+ | |||
+ | a vale 0 | ||
+ | a vale 1 | ||
+ | |||
+ | Deve-se observar que o ponteiro '' | ||
+ | |||
+ | Um exemplo clássico de passagem de parâmetros por referência é a troca de valores entre duas variáveis. O código abaixo implementa essa função: | ||
+ | |||
+ | <code c troca.c> | ||
+ | #include < | ||
+ | |||
+ | // troca os valores de dois inteiros entre si | ||
+ | void troca (int *a, int *b) | ||
+ | { | ||
+ | int aux ; | ||
+ | | ||
+ | aux = *a ; | ||
+ | *a = *b ; | ||
+ | *b = aux ; | ||
+ | } | ||
+ | |||
+ | int main () | ||
+ | { | ||
+ | int i, j ; | ||
+ | |||
+ | i = 21 ; | ||
+ | j = 76 ; | ||
+ | printf ("i: %d, j: %d\n", i, j) ; | ||
+ | |||
+ | troca (&i, &j) ; | ||
+ | printf ("i: %d, j: %d\n", i, j) ; | ||
+ | |||
+ | return (0) ; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | <note important> | ||
+ | O que acontece no código acima se chamarmos '' | ||
+ | </ | ||
+ | |||
+ | ===== Parâmetros vetoriais ===== | ||
+ | |||
+ | A passagem de vetores e matrizes como parâmetros de funções tem algumas particularidades que devem ser observadas: | ||
+ | |||
+ | * Como o nome de um vetor representa o endereço de seu primeiro elemento, na prática vetores são passados à função **por referência**; | ||
+ | * Em consequência, | ||
+ | |||
+ | Um exemplo simples de chamada de função com parâmetros vetoriais: | ||
+ | |||
+ | <code c> | ||
+ | #define SIZE 100 | ||
+ | |||
+ | // " | ||
+ | void clean_vect (int n, int v[]) // ou "int v[SIZE]" | ||
+ | { | ||
+ | int i ; | ||
+ | for (i = 0 ; i < n; i++) | ||
+ | v[i] = 0 ; | ||
+ | } | ||
+ | |||
+ | int main () | ||
+ | { | ||
+ | int vector[SIZE] ; | ||
+ | int num ; | ||
+ | |||
+ | ... | ||
+ | clean_vect (num, vector) ; | ||
+ | ... | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | No caso de matrizes (vetores multidimensionais), | ||
+ | |||
+ | <code c> | ||
+ | #define MAXLIN 100 | ||
+ | #define MAXCOL 50 | ||
+ | |||
+ | void clean_mat (int l, int c, int m[][MAXCOL]) | ||
+ | { | ||
+ | int i, j ; | ||
+ | for (i = 0 ; i < l; i++) | ||
+ | for (j = 0 ; j < c; j++) | ||
+ | m[i][j] = 0 ; | ||
+ | } | ||
+ | |||
+ | int main () | ||
+ | { | ||
+ | int mat[MAXLIN][MAXCOL] ; | ||
+ | int lin, col ; | ||
+ | | ||
+ | ... | ||
+ | clean_mat (lin, col, mat) ; | ||
+ | ... | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ===== Uso do return ===== | ||
+ | |||
+ | A estrutura " | ||
+ | |||
+ | <code c> | ||
+ | int compara (int a, int b) | ||
+ | { | ||
+ | int result ; | ||
+ | |||
+ | if (a < b) | ||
+ | result = -1 ; | ||
+ | else | ||
+ | if (a > b) | ||
+ | result = 1 ; | ||
+ | else | ||
+ | result = 0 ; | ||
+ | |||
+ | return result ; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Entretanto, é possível sair da função invocando '' | ||
+ | |||
+ | <code c> | ||
+ | int compara (int a, int b) | ||
+ | { | ||
+ | if (a < b) return -1 ; | ||
+ | if (a > b) return | ||
+ | return 0 ; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ===== Exercícios ===== | ||
+ | |||
+ | a) Passagem de parâmetros por valor: | ||
+ | |||
+ | - Escrever funções em C para: | ||
+ | - calcular a< | ||
+ | - trocar duas variáveis inteiras entre si. | ||
+ | - comparar dois números inteiros //a// e //b//; a função retorna -1 se //a<b//, 0 se //a=b// e +1 se //a>b//. | ||
+ | - retornar o maior valor em um vetor de inteiros. | ||
+ | |||
+ | b) Passagem de parâmetros vetoriais: | ||
+ | |||
+ | - Escrever um programa em C para somar dois vetores de inteiros. Crie funções separadas para a) ler um vetor; b) somar dois vetores; c) imprimir um vetor. | ||
+ | - Escreva um programa para ordenação de vetores, com as seguintes funções: | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | - Escreva um programa para transpor matrizes, com as seguintes funções: | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | c) Passagem de parâmetros por referência: | ||
+ | |||
+ | - Escreva uma função '' | ||
+ | - Defina uma estrutura '' | ||
+ | * '' | ||
+ | * '' | ||
+ | - Escreva uma função '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * retorno: 1 em sucesso ou 0 em erro | ||