Ponteiros de funções em programação C com exemplos
Os ponteiros oferecem grandes possibilidades para funções 'C', nas quais estamos limitados a retornar um valor. Com parâmetros de ponteiro, nossas funções agora podem processar dados reais em vez de uma cópia de data .
Para modificar os valores reais das variáveis, a instrução de chamada passa endereços para parâmetros de ponteiro em uma função.
Exemplo de ponteiros de funções
Por exemplo, o próximo programa troca dois valores de dois:
void swap (int *a, int *b); int main() { int m = 25; int n = 100; printf("m is %d, n is %d\n", m, n); swap(&m, &n); printf("m is %d, n is %d\n", m, n); return 0;} void swap (int *a, int *b) { int temp; temp = *a; *a = *b; *b = temp;} }
Saída:
m is 25, n is 100 m is 100, n is 25
O programa troca os valores reais das variáveis porque a função as acessa por endereço usando apontador. Aqui discutiremos o processo do programa:
- Declaramos a função responsável por trocar os valores das duas variáveis, que recebe dois ponteiros inteiros como parâmetros e retorna qualquer valor quando é chamada.
- Na função principal, declaramos e inicializamos duas variáveis inteiras ('m' e 'n') e depois imprimimos seus valores respectivamente.
- Chamamos a função swap() passando o endereço das duas variáveis como argumentos usando o símbolo e comercial. Depois disso, imprimimos os novos valores trocados das variáveis.
- Aqui definimos o conteúdo da função swap() que recebe dois endereços de variáveis inteiras como parâmetros e declara uma variável inteira temporária usada como uma terceira caixa de armazenamento para salvar uma das variáveis de valor que será colocada na segunda variável.
- Salve o conteúdo da primeira variável apontada por 'a' na variável temporária.
- Armazene a segunda variável apontada por b na primeira variável apontada por a.
- Atualize a segunda variável (apontada por b) pelo valor da primeira variável salva na variável temporária.
Funções com parâmetros de array
Em C, não podemos passar um array por valor para uma função. Considerando que o nome de um array é um ponteiro (endereço), apenas passamos um nome de array para uma função, o que significa passar um ponteiro para o array.
Por exemplo, consideramos o seguinte programa:
int add_array (int *a, int num_elements); int main() { int Tab[5] = {100, 220, 37, 16, 98}; printf("Total summation is %d\n", add_array(Tab, 5)); return 0;} int add_array (int *p, int size) { int total = 0; int k; for (k = 0; k < size; k++) { total += p[k]; /* it is equivalent to total +=*p ;p++; */} return (total);}
Saída:
Total summation is 471
Aqui, explicaremos o código do programa com seus detalhes
- Declaramos e definimos a função add_array() que recebe um endereço de array (ponteiro) com o número de seus elementos como parâmetros e retorna a soma total acumulada desses elementos. O ponteiro é usado para iterar os elementos do array (usando a notação p[k]), e acumulamos o somatório em uma variável local que será retornada após iterar todo o array de elementos.
- Declaramos e inicializamos um array inteiro com cinco elementos inteiros. Imprimimos o somatório total passando o nome do array (que atua como endereço) e o tamanho do array para o add_array()função chamada como argumentos.
Funções que retornam um array
Em C, podemos retornar um ponteiro para um array, como no programa a seguir:
#include <stdio.h> int * build_array(); int main() { int *a; a = build_array(); /* get first 5 even numbers */ for (k = 0; k < 5; k++) printf("%d\n", a[k]); return 0;} int * build_array() { static int Tab[5]={1,2,3,4,5}; return (Tab);}
Saída:
1 2 3 4 5
E aqui discutiremos os detalhes do programa
- Definimos e declaramos uma função que retorna um endereço de array contendo um valor inteiro e não aceita nenhum argumento.
- Declaramos um ponteiro inteiro que recebe o array completo construído após a chamada da função e imprimimos seu conteúdo iterando todo o array de cinco elementos.
Observe que um ponteiro, e não um array, é definido para armazenar o endereço do array retornado pela função. Observe também que quando uma variável local está sendo retornada de uma função, temos que declará-la como estática na função.
Ponteiros de função
Como sabemos por definição que os ponteiros apontam para um endereço em qualquer local da memória, eles também podem apontar para o início do código executável como funções na memória.
Um ponteiro para função é declarado com * , a declaração geral de sua declaração é:
return_type (*function_name)(arguments)
Você deve lembrar que os parênteses em torno de (*nome_da_função) são importantes porque sem eles, o compilador pensará que o nome_da_função está retornando um ponteiro de tipo_de_retorno.
Depois de definir o ponteiro de função, temos que atribuí-lo a uma função. Por exemplo, o próximo programa declara uma função ordinária, define um ponteiro de função, atribui o ponteiro de função à função ordinária e depois chama a função através do ponteiro:
#include <stdio.h> void Hi_function (int times); /* function */ int main() { void (*function_ptr)(int); /* function pointer Declaration */ function_ptr = Hi_function; /* pointer assignment */ function_ptr (3); /* function call */ return 0;} void Hi_function (int times) { int k; for (k = 0; k < times; k++) printf("Hi\n");}
Saída:
Hi Hi Hi
- Definimos e declaramos uma função padrão que imprime um texto Hi k vezes indicado pelo parâmetro vezes quando a função é chamada
- Definimos uma função ponteiro (com sua declaração especial) que recebe um parâmetro inteiro e não retorna nada.
- Inicializamos nossa função de ponteiro com Hi_function, o que significa que o ponteiro aponta para Hi_function().
- Em vez de chamar a função padrão gravando o nome da função com argumentos, chamamos apenas a função de ponteiro passando o número 3 como argumentos, e pronto!
Tenha em mente que o nome da função aponta para o endereço inicial do código executável como um nome de array que aponta para seu primeiro elemento. Portanto, instruções como function_ptr = &Hi_function e (*funptr)(3) estão corretas.
NOTA: Não é importante inserir o operador de endereço & e o operador de indireção * durante a atribuição de função e chamada de função.
Matriz de ponteiros de função
Uma matriz de ponteiros de função pode desempenhar uma função de switch ou de instrução if para tomar uma decisão, como no próximo programa:
#include <stdio.h> int sum(int num1, int num2); int sub(int num1, int num2); int mult(int num1, int num2); int div(int num1, int num2); int main() { int x, y, choice, result; int (*ope[4])(int, int); ope[0] = sum; ope[1] = sub; ope[2] = mult; ope[3] = div; printf("Enter two integer numbers: "); scanf("%d%d", &x, &y); printf("Enter 0 to sum, 1 to subtract, 2 to multiply, or 3 to divide: "); scanf("%d", &choice); result = ope[choice](x, y); printf("%d", result); return 0;} int sum(int x, int y) {return(x + y);} int sub(int x, int y) {return(x - y);} int mult(int x, int y) {return(x * y);} int div(int x, int y) {if (y != 0) return (x / y); else return 0;}
Enter two integer numbers: 13 48 Enter 0 to sum, 1 to subtract, 2 to multiply, or 3 to divide: 2 624
Aqui, discutimos os detalhes do programa:
- Declaramos e definimos quatro funções que aceita dois argumentos inteiros e retorna um valor inteiro. Essas funções somam, subtraem, multiplicam e dividem os dois argumentos referentes a qual função está sendo chamada pelo usuário.
- Declaramos 4 inteiros para lidar com operandos, tipo de operação e resultado, respectivamente. Além disso, declaramos um array de quatro ponteiros de função. Cada ponteiro de função do elemento da matriz recebe dois parâmetros inteiros e retorna um valor inteiro.
- Atribuímos e inicializamos cada elemento do array com a função já declarada. Por exemplo, o terceiro elemento que é o terceiro ponteiro de função apontará para a função de operação de multiplicação.
- Buscamos operandos e tipo de operação do usuário digitado com o teclado.
- Chamamos o elemento apropriado da matriz (ponteiro de função) com argumentos e armazenamos o resultado gerado pela função apropriada.
A instrução int (*ope[4])(int, int); define a matriz de ponteiros de função. Cada elemento da matriz deve ter os mesmos parâmetros e tipo de retorno.
A instrução result = ope[choice](x, y); executa a função apropriada de acordo com a escolha feita pelo usuário. Os dois inteiros inseridos são os argumentos passados para a função.
Funções usando ponteiros vazios
Ponteiros vazios são usados durante declarações de funções. Usamos um tipo de retorno void * que permite retornar qualquer tipo. Se assumirmos que nossos parâmetros não mudam ao passar para uma função, nós os declaramos como const.
Por exemplo:
void * cube (const void *);
Considere o seguinte programa:
#include <stdio.h> void* cube (const void* num); int main() { int x, cube_int; x = 4; cube_int = cube (&x); printf("%d cubed is %d\n", x, cube_int); return 0;} void* cube (const void *num) { int result; result = (*(int *)num) * (*(int *)num) * (*(int *)num); return result;}
Resultado:
4 cubed is 64
Aqui, discutiremos os detalhes do programa:
- Definimos e declaramos uma função que retorna um valor inteiro e recebe um endereço de variável imutável sem um tipo de dados específico. Calculamos o valor do cubo da variável de conteúdo (x) apontado pelo ponteiro num, e como é um ponteiro vazio, temos que digitá-lo para um tipo de dados inteiro usando um ponteiro de notação específica (* tipo de dados), e retornamos o valor do cubo.
- Declaramos o operando e a variável de resultado. Além disso, inicializamos nosso operando com valor “4”.
- Chamamos a função cubo passando o endereço do operando e tratamos o valor retornado na variável de resultado
Ponteiros de função como argumentos
Outra maneira de explorar um ponteiro de função, passando-o como argumento para outra função, às vezes chamada de “função de retorno de chamada” porque a função receptora “chama-o de volta”.
No arquivo de cabeçalho stdlib.h, a função Quicksort “qsort()” usa esta técnica que é um algoritmo dedicado a classificar um array.
void qsort(void *base, size_t num, size_t width, int (*compare)(const void *, const void *))
- void *base: ponteiro vazio para o array.
- size_t num: o número do elemento da matriz.
- size_t largura O tamanho do elemento.
- int (*compare (const void *, const void *) : ponteiro de função composto por dois argumentos e retorna 0 quando os argumentos têm o mesmo valor, <0 quando arg1 vem antes de arg2 e >0 quando arg1 vem depois de arg2.
O programa a seguir classifica um array de inteiros de um número pequeno para um grande usando a função qsort():
#include <stdio.h> #include <stdlib.h> int compare (const void *, const void *); int main() { int arr[5] = {52, 14, 50, 48, 13}; int num, width, i; num = sizeof(arr)/sizeof(arr[0]); width = sizeof(arr[0]); qsort((void *)arr, num, width, compare); for (i = 0; i < 5; i++) printf("%d ", arr[ i ]); return 0;} int compare (const void *elem1, const void *elem2) { if ((*(int *)elem1) == (*(int *)elem2)) return 0; else if ((*(int *)elem1) < (*(int *)elem2)) return -1; else return 1;}
Resultado:
13 14 48 50 52
Aqui, discutiremos os detalhes do programa:
- Definimos a função de comparação composta por dois argumentos e retorna 0 quando os argumentos têm o mesmo valor, <0 quando arg1 vem antes de arg2 e> 0 quando arg1 vem depois de arg2. (inteiro)
- Definimos e inicializamos um array inteiro O tamanho do array é armazenado no Números variável e o tamanho de cada elemento da matriz é armazenado na variável de largura usando sizeof() predefinido Operador C.
- Chamamos o qsort função e passar o nome do array, tamanho, largura e função de comparação definida anteriormente pelo usuário para classificar nosso array em ordem crescente. A comparação será realizada pegando em cada iteração dois elementos do array até que todo o array seja classificado.
- Imprimimos os elementos do array para ter certeza de que nosso array está bem classificado, iterando o array inteiro usando para laço.