Punteros de funciones en programación C con ejemplos

Los punteros brindan grandes posibilidades a las funciones 'C' en las que estamos limitados a devolver un valor. Con parámetros de puntero, nuestras funciones ahora pueden procesar datos reales en lugar de una copia de los datos.

Para modificar los valores reales de las variables, la declaración de llamada pasa direcciones a parámetros de puntero en una función.

Ejemplo de punteros de funciones

Por ejemplo, el siguiente programa intercambia dos valores de dos:

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

Salida:

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

Ejemplo de punteros de funciones

El programa intercambia los valores reales de las variables porque la función accede a ellos por dirección usando puntero. Aquí discutiremos el proceso del programa:

  1. Declaramos la función responsable de intercambiar los dos valores de las variables, que toma dos punteros enteros como parámetros y devuelve cualquier valor cuando se llama.
  2. En la función principal, declaramos e inicializamos dos variables enteras ('m' y 'n') y luego imprimimos sus valores respectivamente.
  3. Llamamos a la función swap() pasando la dirección de las dos variables como argumentos usando el símbolo comercial. Después de eso, imprimimos los nuevos valores intercambiados de las variables.
  4. Aquí definimos el contenido de la función swap() que toma dos direcciones de variables enteras como parámetros y declara una variable entera temporal utilizada como un tercer cuadro de almacenamiento para guardar una de las variables de valor que se colocará en la segunda variable.
  5. Guarde el contenido de la primera variable señalada por 'a' en la variable temporal.
  6. Almacene la segunda variable señalada por b en la primera variable señalada por a.
  7. Actualice la segunda variable (señalada por b) por el valor de la primera variable guardada en la variable temporal.

Funciones con parámetros de matriz

En C, no podemos pasar una matriz por valor a una función. Mientras que un nombre de matriz es un puntero (dirección), simplemente pasamos un nombre de matriz a una función, lo que significa pasar un puntero a la matriz.

Por ejemplo, consideremos el siguiente 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);}

Salida:

 Total summation is 471

Aquí explicaremos el código del programa con sus detalles.

Funciones con parámetros de matriz

  1. Declaramos y definimos la función add_array() que toma una dirección de matriz (puntero) con su número de elementos como parámetros y devuelve la suma total acumulada de estos elementos. El puntero se usa para iterar los elementos de la matriz (usando la notación p[k]) y acumulamos la suma en una variable local que se devolverá después de iterar toda la matriz de elementos.
  2. Declaramos e inicializamos una matriz de números enteros con cinco elementos enteros. Imprimimos la suma total pasando el nombre de la matriz (que actúa como dirección) y el tamaño de la matriz al agregar_matriz()función llamada como argumentos.

Funciones que devuelven una matriz

En C, podemos devolver un puntero a una matriz, como en el siguiente programa:

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

Salida:

1
2
3
4
5

Y aquí discutiremos los detalles del programa.

Funciones que devuelven una matriz

  1. Definimos y declaramos una función que devuelve una dirección de matriz que contiene un valor entero y no toma ningún argumento.
  2. Declaramos un puntero entero que recibe la matriz completa creada después de llamar a la función e imprimimos su contenido iterando la matriz completa de cinco elementos.

Observe que se define un puntero, no una matriz, para almacenar la dirección de la matriz devuelta por la función. Observe también que cuando una función devuelve una variable local, tenemos que declararla como estática en la función.

Punteros de función

Como sabemos por definición que los punteros apuntan a una dirección en cualquier ubicación de la memoria, también pueden apuntar al comienzo del código ejecutable como funciones en la memoria.
Un puntero a función se declara con el *, la declaración general de su declaración es:

return_type (*function_name)(arguments)

Debe recordar que los paréntesis alrededor de (*nombre_función) son importantes porque sin ellos, el compilador pensará que nombre_función está devolviendo un puntero de tipo_retorno.
Después de definir el puntero de función, tenemos que asignarlo a una función. Por ejemplo, el siguiente programa declara una función ordinaria, define un puntero de función, asigna el puntero de función a la función ordinaria y luego llama a la función a través del puntero:

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

Salida:

Hi
Hi
Hi

Punteros de funciones en C

  1. Definimos y declaramos una función estándar que imprime un texto Hola k veces indicado por el parámetro veces cuando se llama a la función.
  2. Definimos una función de puntero (con su declaración especial) que toma un parámetro entero y no devuelve nada.
  3. Inicializamos nuestra función de puntero con Hi_function, lo que significa que el puntero apunta a Hi_function().
  4. En lugar de llamar a la función estándar grabando el nombre de la función con argumentos, llamamos solo a la función de puntero pasando el número 3 como argumento, ¡y eso es todo!

Tenga en cuenta que el nombre de la función apunta a la dirección inicial del código ejecutable como un nombre de matriz que apunta a su primer elemento. Por lo tanto, instrucciones como function_ptr = &Hi_function y (*funptr)(3) son correctas.
NOTA: No es importante insertar el operador de dirección & y el operador de dirección indirecta * durante la asignación de función y la llamada de función.

Matriz de punteros de función

Una serie de punteros de función puede desempeñar un papel de interruptor o declaración if para tomar una decisión, como en el siguiente 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

Aquí discutimos los detalles del programa:

Matriz de punteros de función

  1. Declaramos y definimos cuatro funciones que toma dos argumentos enteros y devuelve un valor entero. Estas funciones suman, restan, multiplican y dividen los dos argumentos relacionados con qué función llama el usuario.
  2. Declaramos 4 números enteros para manejar operandos, tipo de operación y resultado respectivamente. Además, declaramos una matriz de cuatro punteros de función. Cada puntero de función del elemento de la matriz toma dos parámetros enteros y devuelve un valor entero.
  3. Asignamos e inicializamos cada elemento del array con la función ya declarada. Por ejemplo, el tercer elemento, que es el tercer puntero de función, apuntará a la función de operación de multiplicación.
  4. Buscamos operandos y tipo de operación por parte del usuario tecleado con el teclado.
  5. Llamamos al elemento de matriz apropiado (puntero de función) con argumentos y almacenamos el resultado generado por la función apropiada.

La instrucción int (*ope[4])(int, int); define la matriz de punteros de función. Cada elemento de la matriz debe tener los mismos parámetros y tipo de retorno.
El resultado de la declaración = ope[choice](x, y); ejecuta la función apropiada de acuerdo con la elección hecha por el usuario. Los dos números enteros ingresados ​​son los argumentos pasados ​​a la función.

Funciones que utilizan punteros vacíos

Los punteros nulos se utilizan durante las declaraciones de funciones. Usamos un tipo de devolución nulo * que permite devolver cualquier tipo. Si asumimos que nuestros parámetros no cambian al pasar a una función, la declaramos como constante.
Por ejemplo:

 void * cube (const void *);

Considere el siguiente 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

Aquí discutiremos los detalles del programa:

Funciones que utilizan punteros vacíos

  1. Definimos y declaramos una función que devuelve un valor entero y toma una dirección de variable inmutable sin un tipo de datos específico. Calculamos el valor cúbico de la variable de contenido (x) apuntada por el puntero num, y como es un puntero vacío, tenemos que escribirlo para convertirlo a un tipo de datos entero usando un puntero de notación específica (* tipo de datos) y devolvemos el valor del cubo.
  2. Declaramos el operando y la variable resultado. Además, inicializamos nuestro operando con el valor "4".
  3. Llamamos a la función del cubo pasando la dirección del operando y manejamos el valor de retorno en la variable de resultado.

Punteros de función como argumentos

Otra forma de explotar un puntero de función pasándolo como argumento a otra función a veces se le llama "función de devolución de llamada" porque la función receptora "la devuelve".
En el archivo de encabezado stdlib.h, la función Quicksort “qsort()” utiliza esta técnica, que es un algoritmo dedicado a ordenar una matriz.

void qsort(void *base, size_t num, size_t width, int (*compare)(const void *, const void *))
  • void *base: puntero vacío a la matriz.
  • size_t num: el número de elemento de la matriz.
  • size_t ancho El tamaño del elemento.
  • int (*compare (const void *, const void *): puntero de función compuesto por dos argumentos y devuelve 0 cuando los argumentos tienen el mismo valor, 0 cuando arg1 viene después de arg2.

El siguiente programa ordena una matriz de números enteros de pequeño a grande usando la función 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

Aquí discutiremos los detalles del programa:

Punteros de función como argumentos

  1. Definimos la función de comparación compuesta por dos argumentos y devuelve 0 cuando los argumentos tienen el mismo valor, 0 cuando arg1 viene después de arg2. Los parámetros son un tipo de punteros nulos convertidos al tipo de datos de matriz apropiado (entero)
  2. Definimos e inicializamos una matriz de enteros. El tamaño de la matriz se almacena en el número variable y el tamaño de cada elemento de la matriz se almacena en la variable de ancho usando sizeof() predefinido operador C.
  3. Llamamos a la ordenar function y pase el nombre de la matriz, el tamaño, el ancho y la función de comparación definida previamente por el usuario para ordenar nuestra matriz en orden ascendente. La comparación se realizará tomando en cada iteración dos elementos de la matriz hasta que se ordene toda la matriz.
  4. Imprimimos los elementos de la matriz para asegurarnos de que nuestra matriz esté bien ordenada iterando toda la matriz usando en bucle.