Utilizando a função QSort em C
Neste artigo darei uma breve introdução a ponteiros de funções: O que são? Como declará-los? É possível usá-los?. Além disso falaremos de uma função muito mistificada por nós brasileiros, a QSort. A QSort é definida pelo ANSI C e seu nome se deve a utilizar o algoritmo QuickSort.
Parte 2: Ponteiros para funções
Antes de entrar em ponteiros de funções, vamos recapitular o básico...
O que é uma variável?
Uma variável é um espaço reservado na memória para seu programa poder usar referenciado por um nome.
O que é uma função?
Uma função é um trecho de código com alguma finalidade...
O que é um ponteiro?
Um ponteiro é uma variável que contém o local de um outro espaço alocado na memória.
A revisão dos conceitos estão sendo "por cima", pois acredito que quem vai ler isso já tenha conhecimento suficiente para seguir adiante...
Uma função é como já dizemos, um trecho de código para alguma finalidade. Esse código fica em algum lugar da memória e sempre que chamamos certa função. É procurado num banco que contém o endereço de todas as funções aninhadas (o C não suporta aninhamento) para aquele nível, esse banco tem entre outras coisas o endereço da função. Assim, o C nós permite recuperar este dado e colocá-lo numa variável, isto é, um ponteiro para função.
Agora que nós já sabemos o que é um ponteiro de função, como vamos declará-lo?
Basicamente a sintaxe de um ponteiro para função segue este estilo:
retorno(*nomedavariavel)(tipoparametro_funcao...)
A partir dessa sintaxe básica podemos ter dois tipos de declaração. Ambas, estão corretas:
O que é uma variável?
Uma variável é um espaço reservado na memória para seu programa poder usar referenciado por um nome.
O que é uma função?
Uma função é um trecho de código com alguma finalidade...
O que é um ponteiro?
Um ponteiro é uma variável que contém o local de um outro espaço alocado na memória.
A revisão dos conceitos estão sendo "por cima", pois acredito que quem vai ler isso já tenha conhecimento suficiente para seguir adiante...
Uma função é como já dizemos, um trecho de código para alguma finalidade. Esse código fica em algum lugar da memória e sempre que chamamos certa função. É procurado num banco que contém o endereço de todas as funções aninhadas (o C não suporta aninhamento) para aquele nível, esse banco tem entre outras coisas o endereço da função. Assim, o C nós permite recuperar este dado e colocá-lo numa variável, isto é, um ponteiro para função.
Agora que nós já sabemos o que é um ponteiro de função, como vamos declará-lo?
Basicamente a sintaxe de um ponteiro para função segue este estilo:
retorno(*nomedavariavel)(tipoparametro_funcao...)
A partir dessa sintaxe básica podemos ter dois tipos de declaração. Ambas, estão corretas:
int *fsoma;
int (*insere)(char *, void *);
int (*insere)(char *, void *);
No primeiro caso, no ponteiro para inteiro "fsoma" nós não estamos especificando os parâmetros da função. Mas, isso não causa nenhum problema. Esse fato permite o ponteiro receber uma gama maior de funções, já que não definimos como tem que ser os parâmetros da função.
No segundo caso, temos um ponteiro para função especificando como ficarão os parâmetros da função. Assim, o endereço da função que for alojada ali terá que ter os tipos de parâmetros como os citados, senão o compilador não deixará continuar.
Também podemos ter ponteiros para funções que retornam funções, como é o caso de:
int (*teste)(void)();
Voltemos um pouco para algo que já ia deixando escapar... Se temos uma função definida chamada "Soma", ela pode ser chamada de duas formas:
|Forma|Resultado|
|Soma|Será retornado o endereço da função Soma()|
|Soma()|A função Soma() será executada pelo sistema|
Ao fazer:
int (*seila)() = Soma;
Estamos atribuindo o endereço de Soma() para o apontador de inteiro seila. Agora você deve estar se perguntando, se tenho o endereço da função em algum ponteiro então isso quer dizer que posso chamar a função pelo ponteiro? Sim isso é possível!
No exemplo se fizermos:
(seila)(); //Soma não tem parâmetros
A função Soma() será executada mesmo chamando seila. Mas se tivéssemos algo como:
int *seila = Soma;
Resultaria em erro a tentativa anterior, pois para ele seila é somente um ponteiro para inteiro e não para função. Assim, chegamos a conclusão que o que havíamos dito anteriormente não é verdade. Se quisermos um apontador para inteiro existe somente uma forma, que nesse caso foi a segunda citada.
Notei que você usou cast dentro da função que compara os valores, tem outro meio de fazer isso (as vezes até mais facil).
A função para comparar você já define como inteiro..
int compara(int *x, int *y)
{
if (*x > *y)
return 1;
else if (*x == *y)
return 0;
else if (*x < *y)
return -1;
}
E na hora de usar o qsort você faz um cast para void* na função...
qsort( vetor, (size_t) tamanho, sizeof(int), (void *) compara );
Abraços,
Fiquem com Deus.