Vamos entender algumas práticas comuns, e depois partir para exemplos:
- int i -> Int variável 'i'
- int *p -> 'P' ponteiro para um int
- int a[] -> Matriz 'a' de Int
- int f() -> 'F' função com valor de retorno do tipo int
- int **p -> 'Pp' ponteiro para um ponteiro para um int
- int (*pa)[] -> 'Pa' ponteiro para um array de int
- int (*pf)() -> pf ponteiro para uma função com valor de retorno int
- int *p[] -> Array 'p' de ponteiros para um int
- int *var() -> Função "var", que retorna um ponteiro para um int
- int ***var -> 'var' ponteiro para um ponteiro para um ponteiro para um int
- int (**var)[] -> 'var' ponteiro para um ponteiro para um array de int
- int (**var)() -> 'var' ponteiro para um ponteiro para uma função com valor de retorno do tipo int
- int *(*c)[] -> 'c' ponteiro para uma matriz de ponteiros para um int
- int *(*c)() -> "c 'ponteiro para uma função com valor de retorno do tipo ponteiro para um int
- int **app[] -> 'App' ponteiro para um ponteiro para uma matriz de ponteiros para um int
- int (*b[])[] -> Uma série de 'b' ponteiros para um array de int
- int (*c[])() -> Um array 'c' ponteiros para uma função com valor de retorno do tipo int
- int ***fpp() -> "Fpp 'função que retorna um ponteiro para um ponteiro para um ponteiro para um int
- int (*fpa())[] -> Função 'fpa ", que retorna um ponteiro para um array de int
- int (*fpf())() -> "FPF" função que retorna um ponteiro para uma função com valor de retorno int
Fique calmo, não é para decorar. Tenha em mente: leitura da esquerda para direita, e sempre começando pelo nome da variável.
Uma prática muito comum em C, é usar Void Pointer, para muitos que estão iniciando não é normal de se ver, entretanto, estudando códigos de
terceiros, pode-se ver muito.
Usar Ponteiro colabora no desempenho e o código em Assembly gerado, fica menor de fato. Um 'Disassemble Main' no GDB pode te dar ponto empírico.
Um exemplo vale mais do que mil palavras:
// exemplo void pointer by Cooler_
#include <stdio.h>
//ideia de polimorfismo
void foo(void *point,int size)
{
// int == 4 bytes
if(size==sizeof(int))
//tem que fazer casting do ponteiro para STDOUT
printf("int : %d , bytes: %d\n",*(int *)point,sizeof(point));
// double == 8 bytes
if(size==sizeof(double))
//casting de novo para o write(1...
printf("double : %f , bytes: %d\n",*(double *)point,sizeof(double));
}
int main()
{
int a=64;
double b=3.14;
printf("bytes do void : %d\n",sizeof(void));
// & usamos para dizer o endereço da memória de determinada variável
foo(&a,sizeof(int));
foo(&b,sizeof(double));
return 0;
}
Outro exemplo, seguindo a mesma lógica:
#include <stdio.h>
#include <string.h>
typedef struct _myst
{
int a;
char b[10];
}myst;
void func(myst *mt)
{
printf("resposta %d %s \n",mt->a,mt->b);
}
int main()
{
void (*resposta)(void *);
myst x;
x.a=4;
strncpy(x.b,"1234",8);
resposta = (void*)func;
resposta(&x);
return 0;
}
Outra prática muito vista: Ponteiro de arrays para funções.
Vejamos um terceiro exemplo:
// example pointer of arrays to function by Cooler_
#include <stdio.h>
#include <malloc.h>
void foo1(int x)
{
printf("int: %d\n",x);
}
void foo2(int x)
{
printf("num: %d\n",x);
}
void foo3(int z)
{
printf("result %d\n",z*z);
}
void func2func(void (*fp)(void *), void *q)
{
fp(q);
}
int main()
{
//se a função tiver mais de um argv use "," (int,char...
void (**list)(int);
//alocamos 3 endereços na heap
list=(void *)malloc(3*sizeof(void *));
list[0]=foo1;
list[0](2);
list[1]=foo2;
list[1](4);
list[2]=foo3;
list[2](8);
// função para função lol
func2func(foo2, 4);
free(list);
return 0;
}