next up previous contents
Next: Argumentos na linha de Up: Ponteiros Previous: Ponteiros e estruturas   Sumário


Ponteiros para funções

Como foi visto no Capítulo 1, um programa é um conjunto de instruções armazenado na memória, assim como seus dados. Por este motivo, é possível referenciar o endereço de uma função. Em C, o endereço de uma função é acessível ao programador através de uma variável do tipo ponteiro para função.

Ponteiros para funções podem ser passados como argumentos para outras funções, e a função apontada pode ser invocada a partir de seu ponteiro. Um exemplo prático desta capacidade é seu uso em uma rotina de ordenação de elementos de um arranjo. Se o arranjo é de inteiros, então uma função de comparação de inteiros deverá ser suportada, tal como

    /*
     *  compara dois inteiros, retornando:
     *      0 se os dois elementos forem iguais
     *      um inteiro negativo se o primeiro elemento for menor
     *      um inteiro positivo se o primeiro elemento for maior
     */
     int comp_int(int *e1, int *e2) {
        return(*e1 - *e2);
     }

O problema surge quando se deseja usar o mesmo algoritmo de ordenação para ordenar outros arranjos de tipos que não sejam inteiros. Por exemplo, se os elementos a comparar forem strings, então a rotina de comparação acima não mais serviria, apesar de todo o restante do algoritmo de ordenação ainda ser basicamente o mesmo.

A solução é passar qual função deve ser usada para a comparação como um dos argumentos para a rotina de ordenação genérica. Esta abordagem é adotada por rotinas usualmente supridas juntamente com o compilador C, tal como qsort para ordenação de arranjos e bsearch para a realização de busca binária em arranjos ordenados.

A forma de declarar uma variável do tipo ponteiro para função é ilustrada no seguinte exemplo, com uma referência à função comp_int definida acima:

    main() {
        /* prototipo de comp_int: */
        int comp_int(int *, int *);
        /* ponteiro para uma funcao retornando inteiro */
        int (*apcmp)();
        int a, b;

        apcmp = comp_int;       /* inicializa ponteiro */
        ...
        (*apcmp)(a, b);         /* invoca funcao */
    }

Algumas observações relativas a este exemplo são importantes. A primeira refere-se à declaração do ponteiro. A declaração de um ponteiro para a função deve incluir os parênteses em torno do nome da variável ponteiro. Uma definição na forma int *apcmp(); seria interpretada como o protótipo de uma função retornando um ponteiro para um inteiro, o que não é o desejado neste caso.

A segunda observação refere-se à forma utilizada para definir o valor do ponteiro no comando de atribuição. Como o protótipo de comp_int já havia sido definido, então o compilador sabe que este identificador refere-se a uma função. Quando o identificador comp_int é encontrado novamente, desta vez sem parênteses, ele é identificado como o endereço desta função, podendo assim ser atribuído a um ponteiro para uma função com o mesmo tipo de retorno. Repare a semelhança com referências a nomes de arranjos.

Finalmente, a invocação da função através de seu ponteiro: a forma usando o operador de dereferência (*apcmp) indica o conteúdo do ponteiro apcmp, que é a função (neste caso, comp_int). Assim, a última linha no exemplo é apenas uma invocação para a rotina apontada por apcmp, e o que vem a seguir de (*apcmp) são simplesmente os argumentos para a função. O padrão ANSI também permite que a forma equivalente,

     apcmp(a, b);
seja utilizada. Muitos programadores preferem a forma apresentada no exemplo original para tornar claro que um ponteiro para função está sendo usado, embora internamente não haja diferenças entre a ativação de uma função por seu nome ou através de um ponteiro.

Ponteiros para funções tornam-se interessantes quando o programador não pode determinar qual função deve ser executada em uma dada situação a não ser durante a execução do programa. Em tais casos, o trecho do programa referenciando esta ``função variável'' pode ser escrito em termos de ativação de uma função através de ponteiros para funções, os quais são corretamente inicializados em tempo de execução.


next up previous contents
Next: Argumentos na linha de Up: Ponteiros Previous: Ponteiros e estruturas   Sumário
Ivan L. M. Ricarte 2003-02-14