¿Alguien podria explicarme como funciona el puntero tipo función?

Iniciado por Gojira, 25 Febrero 2018, 18:27 PM

0 Miembros y 1 Visitante están viendo este tema.

Gojira

¿A que esta apuntando el puntero pFunc de la siguiente imagen?¿A la dirección en memoria del valor que retorne Sum con los parámetros que le aporte el puntero?

¿Y por que se permite que se le asigne la direccion en memoria de sum(), pero a un puntero normal no se le permite hacer lo propio con una variable?


MAFUS

Para entender el tema de los punteros primero hay que saber qué es un puntero en su sentido más básico.
Un puntero es una variable de tamaño de la palabra del procesador (size_t, que suele ser un typedef de unsigned long), 64bits o 32bits según el procesador.

El tipo de dato del puntero (int*, char*, double*, etc) sirve para que sumando o restando unidades se tome una dirección relativa a ese puntero para conseguir el siguiente dato. Dicho con ejemplo:
Un char es de tamaño de 1 byte. Un int es de tamaño de 4 bytes.

· Supongamos que char* c está en la posición 100.
  c+1 regresará 101, pues internamente C hara 100 + (1 * 1).

· Supongamos que int* i está en la posición 200.
  i+1 regresará 204, pues internamente C hará 200 + (1 * 4).


A lo que íbamos.
El código también se aloja en la memoria del ordenador y el nombre de las funciones indican su punto de entrada, eso es dónde empieza su porción de código.
De igual forma las funciones tienen un tamaño y esto se lo da tanto su tipo de dato devuelto como los tipos de datos que hay en sus argumentos (a todo esto se le llama firma y por esta razón se deben usar prototipos si una función está definida después de que sea llamada; de aquí los archivos de cabecera, etc. C debe conocer el tamaño de la función para alojarla en la memoria). Y esta es la razón por la que pueden existir punteros a funciones e incluso arrays de funciones.

Al igual que a un puntero a int se de declara como
int *i;

Un puntero a función debe declararse con el mismo tipo que la función a la que va a apuntar.
Supongamos que tenemos la siguiente función:
int suma(int n1, int n2) {
    return n1 + n2;
}

El puntero debe retornar un int y tener dos argumentos de tipo int. La declaración sería entonces:
int (*pfun)(int, int)

Como puede verse es declarar una función normal pero con la particularidad del paréntesis en el nombre (*pfun). Esto es necesario porque si no hubiera estos parentesis sería lo siguiente:
int *pfun(int, int)

Que reubicando el asterisco:
int* pfun(int, int)

Eso es: sería una función llamada pfun que devolvería un puntero a entero (int*) y tendría dos argumentos enteros (int); para romper el tipo de dato e informar que se trata de un puntero se usa el paréntesis (*pfun).
Para que lo veas mejor:
Si para declarar un puntero haces lo siguiente:
int *i
Vemos que int es el tipo de dato que será el puntero e
*i (nótese que al nombre le antecede el asterisco) indica de que se trata de un puntero.

Así en
int (*pfun)(int, int)

Sabemos de que se trata de un puntero (*pfun), los parentesis, como ya se ha dicho, son para que el asterisco forme parte del nombre, que devuelve un int y tiene dos argumentos tipo int.

Ahora como el nombre de una función representa su punto de entrada, al igual que un array, como ya te dije en otro post, no hace falta el & para conseguir su dirección.

Así tenemos que:
#include<stdio.h>

int suma(int n1, int n2) {
    return n1+n2;
}

int main(){
    int (*pfun)(int, int);
    pfun = suma;

    printf("2 + 3 = %d", pfun(2, 3));
}