Los punteros brindan grandes posibilidades a las funciones 'C' que estamos limitados a devolver un valor. Con los parámetros de puntero, nuestras funciones ahora pueden procesar datos reales en lugar de una copia de datos.
Para modificar los valores reales de las variables, la declaración de llamada pasa direcciones a los parámetros del puntero en una función.
En este tutorial, aprenderá:
- Ejemplo de punteros de funciones
- Funciones con parámetros de matriz
- Funciones que devuelven una matriz
- Punteros de función
- Matriz de punteros de función
- Funciones que utilizan punteros vacíos
- Punteros de función como argumentos
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;}}
Producción:
m is 25, n is 100m is 100, n is 25
El programa intercambia los valores de las variables reales porque la función accede a ellos por dirección usando punteros. Aquí discutiremos el proceso del programa:
- Declaramos la función responsable de intercambiar los dos valores variables, que toma dos punteros enteros como parámetros y devuelve cualquier valor cuando se llama.
- En la función principal, declaramos e inicializamos dos variables enteras ('m' y 'n') y luego imprimimos sus valores respectivamente.
- Llamamos a la función swap () pasando la dirección de las dos variables como argumentos usando el símbolo ampersand. Después de eso, imprimimos los nuevos valores intercambiados de variables.
- Aquí definimos el contenido de la función swap () que toma dos direcciones de variables enteras como parámetros y declaramos una variable entera temporal utilizada como un tercer cuadro de almacenamiento para guardar una de las variables de valor que se colocarán en la segunda variable.
- Guarde el contenido de la primera variable señalada por 'a' en la variable temporal.
- Almacene la segunda variable apuntada por b en la primera variable apuntada por a.
- 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. Considerando que, un nombre de matriz es un puntero (dirección), por lo que simplemente pasamos un nombre de matriz a una función, lo que significa pasar un puntero a la matriz.
Por ejemplo, consideramos 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);}
Producción:
Total summation is 471
Aquí, explicaremos el código del programa con sus detalles.
- 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 del arreglo (usando la notación p [k]), y acumulamos la suma en una variable local que será devuelta después de iterar el arreglo completo del elemento.
- Declaramos e inicializamos una matriz de 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 a la función llamada add_array () como argumentos.
Funciones que devuelven una matriz
En C, podemos devolver un puntero a una matriz, como en el siguiente programa:
#includeint * 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);}
Producción:
12345
Y aquí, discutiremos los detalles del programa.
- Definimos y declaramos una función que devuelve una dirección de matriz que contiene un valor entero y no toma ningún argumento.
- Declaramos un puntero entero que recibe la matriz completa construida después de que se llama a la función e imprimimos su contenido iterando toda la matriz de cinco elementos.
Observe que se define un puntero, no una matriz, para almacenar la dirección de 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 la función se declara con *, la declaración general de su declaración es:
return_type (*function_name)(arguments)
Debe recordar que los paréntesis alrededor (* function_name) son importantes porque sin ellos, el compilador pensará que function_name está devolviendo un puntero de return_type.
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:
#includevoid 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");}
Producción:
HiHiHi
- Definimos y declaramos una función estándar que imprime un texto alto k veces indicado por el parámetro veces cuando se llama a la función
- Definimos una función de puntero (con su declaración especial) que toma un parámetro entero y no devuelve nada.
- Inicializamos nuestra función de puntero con Hi_function, lo que significa que el puntero apunta a Hi_function ().
- En lugar de llamar a la función estándar escribiendo el nombre de la función con argumentos, solo llamamos a la función de puntero pasando el número 3 como argumentos, ¡y listo!
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 indirección * durante la asignación de función y la llamada de función.
Matriz de punteros de función
Una matriz de punteros de función puede jugar un cambio o una función de declaración if para tomar una decisión, como en el siguiente programa:
#includeint 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
Aquí, discutimos los detalles del programa:
- Declaramos y definimos cuatro funciones que toman dos argumentos enteros y devuelven un valor entero. Estas funciones suman, restan, multiplican y dividen los dos argumentos con respecto a qué función está siendo llamada por el usuario.
- Declaramos 4 enteros para manejar operandos, tipo de operación y resultado respectivamente. Además, declaramos una matriz de puntero de cuatro funciones. Cada puntero de función del elemento de matriz toma dos parámetros enteros y devuelve un valor entero.
- Asignamos e inicializamos cada elemento de la matriz 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.
- Buscamos operandos y tipo de operación del usuario tecleado con el teclado.
- Llamamos al elemento de matriz apropiado (puntero de función) con argumentos y almacenamos el resultado generado por la función adecuada.
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.
La sentencia result = ope [elección] (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 vacíos se utilizan durante las declaraciones de funciones. Usamos un permiso de tipo de retorno vacío * para 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:
#includevoid* 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:
- 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 del cubo de la variable de contenido (x) apuntada por el puntero num, y como es un puntero vacío, tenemos que escribirlo a un tipo de datos entero usando un puntero de notación específico (* tipo de datos), y devolvemos el valor del cubo.
- Declaramos el operando y la variable de resultado. Además, inicializamos nuestro operando con el valor "4".
- 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 un argumento a otra función a veces llamada "función de devolución de llamada" porque la función receptora "devuelve la llamada".
En el archivo de encabezado stdlib.h, la función Quicksort "qsort ()" usa 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 del elemento de la matriz.
- size_t width 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 antes de arg2 y> 0 cuando arg1 viene después de arg2.
El siguiente programa ordena una matriz de enteros de números pequeños a grandes usando la función 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
Aquí, discutiremos los detalles del programa:
- 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 antes de arg2 y> 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)
- Definimos e inicializamos una matriz de enteros. El tamaño de la matriz se almacena en la variable num y el tamaño de cada elemento de la matriz se almacena en la variable de ancho usando el operador C predefinido sizeof ().
- Llamamos a la función qsort y pasamos 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 completar la matriz. serán ordenados.
- Imprimimos los elementos de la matriz para asegurarnos de que nuestra matriz esté bien ordenada iterando toda la matriz utilizando el bucle for.