Ponteiros de funções na programação C com exemplos

Índice:

Anonim

Os ponteiros fornecem muitas possibilidades para funções 'C', as 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 dos dados.

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.

Neste tutorial, você aprenderá-

  • Exemplo de ponteiros de funções
  • Funções com parâmetros de matriz
  • Funções que retornam um array
  • Ponteiros de função
  • Array of Function Pointers
  • Funções usando ponteiros de void
  • Ponteiros de função como argumentos

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;}}

Resultado:

m is 25, n is 100m is 100, n is 25

O programa troca os valores reais das variáveis ​​porque a função os acessa por endereço usando ponteiros. Aqui, discutiremos o processo do programa:

  1. Declaramos a função responsável por trocar os dois valores das variáveis, que recebe dois ponteiros inteiros como parâmetros e retorna qualquer valor quando é chamada.
  2. Na função principal, declaramos e inicializamos duas variáveis ​​inteiras ('m' e 'n') e depois imprimimos seus valores respectivamente.
  3. 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.
  4. Aqui definimos o conteúdo da função swap () que leva dois endereços de variáveis ​​inteiras como parâmetros e declaramos 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.
  5. Salve o conteúdo da primeira variável apontada por 'a' na variável temporária.
  6. Armazene a segunda variável apontada por b na primeira variável apontada por a.
  7. 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 matriz

Em C, não podemos passar um array por valor para uma função. Enquanto um nome de array é um ponteiro (endereço), então apenas passamos um nome de array para uma funçã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);}

Resultado:

 Total summation is 471

Aqui, vamos explicar o código do programa com seus detalhes

  1. Declaramos e definimos a função add_array () que recebe um endereço de array (ponteiro) com seu número de 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 nós acumulamos o somatório em uma variável local que será retornada após a iteração de todo o array de elementos.
  2. 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 add_array () chamado de função como argumentos.

Funções que retornam um array

Em C, podemos retornar um ponteiro para uma matriz, como no seguinte programa:

#include 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);}

Resultado:

12345

E aqui, vamos discutir os detalhes do programa

  1. Definimos e declaramos uma função que retorna um endereço de array contendo um valor inteiro e não aceita nenhum argumento.
  2. Declaramos um ponteiro inteiro que recebe o array completo construído depois que a função é chamada e imprimimos seu conteúdo iterando todo o array de cinco elementos.

Observe que um ponteiro, não uma matriz, é definido para armazenar o endereço da matriz 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 a função é declarado com *, a declaração geral de sua declaração é:

return_type (*function_name)(arguments)

Você tem que lembrar que os parênteses ao redor de (* function_name) são importantes porque sem eles, o compilador pensará que function_name está retornando um ponteiro de return_type.

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 comum, define um ponteiro de função, atribui o ponteiro de função à função comum e, em seguida, chama a função por meio do ponteiro:

#include 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");} 

Resultado:

HiHiHi

  1. Nós definimos e declaramos uma função padrão que imprime um texto Hi k vezes indicado pelo parâmetro times quando a função é chamada
  2. Definimos uma função de ponteiro (com sua declaração especial) que recebe um parâmetro inteiro e não retorna nada.
  3. Inicializamos nossa função de ponteiro com a função Hi_, o que significa que o ponteiro aponta para a função Hi_ ().
  4. Em vez da função padrão chamar gravando o nome da função com argumentos, chamamos apenas a função de ponteiro passando o número 3 como argumentos, e é isso!

Lembre-se de 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.

Array of Function Pointers

Uma matriz de ponteiros de função pode desempenhar um papel switch ou uma instrução if para tomar uma decisão, como no próximo programa:

#include 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 48Enter 0 to sum, 1 to subtract, 2 to multiply, or 3 to divide: 2624

Aqui, discutimos os detalhes do programa:

  1. Declaramos e definimos quatro funções que recebem dois argumentos inteiros e retornam um valor inteiro. Essas funções somam, subtraem, multiplicam e dividem os dois argumentos a respeito de qual função está sendo chamada pelo usuário.
  2. Declaramos 4 inteiros para lidar com operandos, tipo de operação e resultado, respectivamente. Além disso, declaramos uma matriz de quatro ponteiros de função. Cada ponteiro de função do elemento da matriz leva dois parâmetros inteiros e retorna um valor inteiro.
  3. 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.
  4. Buscamos operandos e tipo de operação do usuário digitados no teclado.
  5. Chamamos o elemento de array apropriado (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.

O resultado da declaração = ope [escolha] (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 de void

Ponteiros nulos são usados ​​durante declarações de funções. Usamos licenças de tipo de retorno void * para retornar qualquer tipo. Se assumirmos que nossos parâmetros não mudam ao passar para uma função, nós a declaramos como const.

Por exemplo:

 void * cube (const void *); 

Considere o seguinte programa:

#include 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:

  1. Definimos e declaramos uma função que retorna um valor inteiro e leva um endereço de variável inalterável sem um tipo de dados específico. Calculamos o valor do cubo da variável de conteúdo (x) apontada pelo ponteiro num, e como é um ponteiro vazio, temos que digitar, convertê-lo em um tipo de dados inteiro usando um ponteiro de notação específico (* tipo de dados), e retornamos o valor do cubo.
  2. Declaramos o operando e a variável de resultado. Além disso, inicializamos nosso operando com o valor "4".
  3. Chamamos a função de cubo passando o endereço do operando e tratamos o valor de retorno na variável de resultado

Ponteiros de função como argumentos

Outra maneira de explorar um ponteiro de função passando-o como um argumento para outra função, às vezes chamada de "função de retorno de chamada" porque a função receptora "o chama de volta".

No arquivo de cabeçalho stdlib.h, a função Quicksort "qsort ()" usa essa técnica que é um algoritmo dedicado a classificar uma matriz.

void qsort(void *base, size_t num, size_t width, int (*compare)(const void *, const void *))
  • void * base: void ponteiro para a matriz.
  • size_t num: O número do elemento da matriz.
  • size_t width O tamanho do elemento.
  • int (* compare (const void *, const void *): ponteiro de função composto de 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 uma matriz de inteiros de um número pequeno a grande usando a função qsort ():

#include #include 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:

  1. Definimos a função de comparação composta de 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. Os parâmetros são um tipo de ponteiros void convertidos para o tipo de dados de matriz apropriado (inteiro)
  2. Definimos e inicializamos um array inteiro. O tamanho do array é armazenado na variável num e o tamanho de cada elemento do array é armazenado na variável width usando o operador C predefinido sizeof ().
  3. Chamamos a função qsort e passamos 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 tomando em cada iteração dois elementos do array até o array inteiro será classificado.
  4. Imprimimos os elementos do array para ter certeza de que nosso array está bem classificado, iterando todo o array usando o loop for.