PUNTEROS A FUNCIONES

Hasta el momento, el estudio de los punteros se ha limitado a los datos de un programa; esto quiere decir que hemos definido variables capaces de almacenar direcciones de memoria en cuyas celdas se encuentran almacenados datos. Nos hemos acostumbrado a declarar variables de tipo puntero y asignarles direcciones válidas de manera dinámica (con el uso de new o malloc) o de manera estática (asignando la dirección de memoria de otra variable); sin embargo, la dirección que se le asigna a un puntero puede ser la de cualquier parte memoria, como se vio en el capítulo de punteros, y en esa dirección podemos encontrar información que se puede interpretar como un dato, al igual que como código ejecutable. Más aun, debemos recordar que un identificador es un nombre relacionado con una posición de memoria y estos sirven para denotar tanto las variables como las funciones, y por otro lado el identificador de una función está relacionado con la direcció de inicio del código de la función; por lo tanto, al igual que con las variables, el identificador de una función se puede emplear para asignar una dirección de memoria a un puntero. Pues bien, un puntero a función es puntero, con una forma de declaración especial, que puede recibir la dirección de inicio del código de una función y ejecutarla a través de él.

La forma de declarar un puntero a función se muestra a continuación:

<Tipo de dato devuelto>  (* identificador)  (lista de parámetros);

Por ejemplo, en la siguiente declaración:

int (* operacion) (int,  int);

Define al identificador operacion como un puntero que es capaz de apuntar al inicio del código de cualquier función que tenga como argumentos a dos enteros y que devuelva un valor entero.

Observe que la declatración anterior es muy distinta que la siguiente:

int * operacion (int,  int);

En la primera, *operacion se encuentra entre paréntesis y en la segunda no. Este detalle hace que, en el segundo caso, el compilador interprete a operacion como una función (ya no como un puntero) que recibe como parámetro dos enteros y que devuelve un puntero a un entero. Por lo tanto, debe tener presente que un puntero a función se debe definir encerrando entre paréntesis el asterisco y el identificador de manera obligatoria.

El siguiente ejemplo muestra de una manera muy sencilla:

Grabar este ejemplo

#include <stdio.h>

float cubo(float x) {
   return  x * x * x;
}

int main(void) {
   float (*ptrAFunc) (float);  // Definimos el puntero a función
   float x = 3.5,   xxx1,   xxx2;

   xxx1 = cubo(x);
   printf("\nFuncion: Cubo de %f = %f\n", x, xxx1);

   ptrAFunc = cubo;        // El puntero apunta al inicio del código de la función
   xxx2 = ptrAFunc(x);   // Ejecutamos la función a través del puntero
   printf("\nPuntero: Cubo de %f = %f\n", x, xxx2);

   return 0;
}

Existen muchas formas de manejar un puntero a función, a continuación mostraremos alguas de éstas. En el primer ejemplo que presentamos veremos cómo emplear un puntero a funcón a través de un arreglo, y en el segundo se pretende pasar como parámetro a una función la dirección de inicio del código de otra función.

Ejemplo 1: Uso de punteros a función a través de arreglos.

Grabar este ejemplo

#include <stdio.h>

float suma(float x, float y) {
    return  x + y;
}

float resta(float x, float y) {
    return  x - y;
}

float multiplica(float x, float y) {
    return  x * y;
}

float divide(float x, float y) {
    return  x / y;
}

int main(void) {
    // Se define un arreglo de punteros a funciones y se le asigna a cada
    // elemento la dirección de una función
    float (*operacion[4]) (float, float) = { suma, resta, multiplica, divide };

    char oper[ ] = "+-x/";
    float a = 45, b = 12, c;

    printf("Operaciones:\n");
    for(int i = 0; i < 4; i++) {
        c = operacion[i] (a, b);  // Ejecutamos la función a través de los
                                         // elementos del arreglo

        printf("    %6.2f  %c  %6.2f = %6.2f\n", a, oper[i], b, c);
    }
    return 0;
}

La respuesta de ese programa será como se muestra a continuación:

Ejemplo 2: Uso de punteros a función a como parámetros de otra función.

Grabar este ejemplo

#include <stdio.h>

float suma(float x, float y) {
    return x + y;
}
float resta(float x, float y) {
    return x - y;
}
float multiplica(float x, float y) {
    return x * y;
}
float divide(float x, float y) {
    return x / y;
}

float fOpera(float x, float y, float (*f)(float, float)){
    // El puntero f recibe la dirección de inicio de una función
    // no se sabe qué función será la recibida

    return f(x, y);  // Ejecutamos la función a trav6eacute;s del puntero
}

int main(void) {
    float a = 45, b = 12, c;

    printf("Operaciones:\n");
    // Se llama a la función fOpera pasando como par6aacute;metro la función suma
    c = fOpera(a, b, suma);
    printf("    Suma:        %6.2f  + %6.2f = %6.2f\n\n", a, b, c);
    // Se llama a la función fOpera pasando como par6aacute;metro la función multiplica
    c = fOpera(a, b, multiplica);
    printf("    Multiplica: %6.2f  x %6.2f = %6.2f\n\n", a, b, c);
    // Se llama a la función fOpera pasando como par6aacute;metro la función resta
    c = fOpera(a, b, resta);
    printf("    Resta:       %6.2f  - %6.2f = %6.2f\n\n", a, b, c);
    // Se llama a la función fOpera pasando como par6aacute;metro la función divide
    c = fOpera(a, b, divide);
    printf("    Divide:      %6.2f  / %6.2f = %6.2f\n\n", a, b, c);

    return 0;
}

Al ejecutar el programa se verá en la pantalla algo similar a lo que se muestra a continuación:

Funciones qsort y bsearch

Las funciones qsort y bsearch son ejemplos de funciones que que reciben como parámetro un puntero a función. Estas funciones están definidas en la biblioteca de funciones stdlib.h. Se trata de funciones muy versátiles, en el caso de qsort, la función permite ordenar por le método quick sort, cualquier tipo de arreglo empleando cualquier criterio de ordenación, así por ejemplo se pueden ordenar un arreglos de cadenas de caractere, de valores enteros, de punto flotante, etc., tanto de manera ascendente como descendente. De manera similar la función bsearch permite encontrar un valor en cualquier tipo de arreglo empleando una búsqueda binaria.

El lo que sigue mostraremos cómo trabaja la función qsort

La sintaxis de la función qsort la presentamos a continuación:

void  qsort(void *datos,   int numElem,   int tamaño,   int (*ptrFCmp)(const void *,  const void *));

Se puede apreciar en la línea anterior que el parámetro datos es un puntero genérico (void *) por lo tanto puede cirecibir la dirección de memoria de cualquier tipo o estructura dedatos. Podría recibir la deirección de un arreglo de enteros (int *) para ordenar sus valores, también podría recibir la derección de un arreglo de punteros a char (char **) para poder ordenar cadenas de caracteres y de manera similar podría recibir la derección de memoria de un arreglo de punteros genéricoa (void **) para ordenar registros de datos, en fin cualquier cosa.

El parámetro numElem debe recibir el número el número de elementos que tiene el arreglo datos.

El parámetro tamaño debe recibir el tamaño en bytes del elemento del arreglo recibido. En otras palabras si datos es de tipo int *, entonces tamaño debe recibir sizeof(int), si es char ** debe recibir sizeof(char*), etc.

El siguiente parámetro corresponde a un puntero a función, ptrFCmp es un puntero que puede recibir la dirección de cualquier función que reciba como argumentos dos direcciones de memoria que esten referidas a culaquier tipo de dato (void *) y que devuelva un entero. Si es cierto que el primer argumento permite trabajar con arreglos de cualquier tipo, este último argumento permite que la ordenación pueda realizarse empleando cualquier criterio. Esto se da porque en el código que emplea qsort para ordenar, a la hora de comparar dos elementos del arreglo para saber si están en el orden adecuado, la comparación se hace a través de la función asignada a ptrFCmp, por lo que dependerá de la forma en que el usuario implemente la función de comparación para establecer el criterio de ordenación.

La función de comparación que se implemente para ser introducida como parámetro a la función qsort debe permitir recibir como parámerto las direcciones de dos elementos del arreglo (ver la figura siguiente), y devolver un valor entero que indique si es que el contenido del primer elemento del arrego recibido como parámetro es menor que el segundo (con un valor menor que cero), es igual que el segundo (valor igual a cero) o si es mayor (valor mayor que cero).

En el siguiente ejemplo podemos apreciar como se emplea la función qsort para ordenar una lista de nombres almacenados en un archivo de textos y una serie de valores numéricos almacenados en un arreglo.

El archivo que contiene los nombres que se quiere ordenar, se presenta a continuación:

El código es el siguiente;

Grabar este ejemplo

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

//  Función que compara dos cadenas de caracteres para ordenar alfabéticamente
int strComp(const void *v1,  const void* v2) {
    char **s1 = (char**)v1,    **s2 = (char**)v2;
    // Definimos s1 y s2 para no tener que trabajar con los punteros void

    return strcmp(*s1, *s2);  // Para ordenar de mayor a menor
                                         // ==> return -strcmp(*s1, *s2);  ó
                                         // ==> return strcmp(*s2, *s1);
}

// Función que compara dos valores enteros de menor a mayor
int intComp(const void *v1,  const void *v2) {
    int i1, i2;

    i1 = *(int*)v1;  // Tomamos el valor apuntado por v1 y v2
    i2 = *(int*)v2;

    return i1 - i2;  // Para ordenar de mayor a menor ==> return i2 - i1;
}

// Prototipos de funciones de entrada y salida de cadenas de caracteres
void leeCad(char **&, int &);
void imprime(char **, int);

int main(void) {
    // Ordenamos una lista de nombres en un arreglo de caracteres
    char **nombre;
    int numDat = 0, i;

    leeCad(nombre, numDat);
    qsort(nombre,  numDat,  sizeof(char *),  strComp);
    imprime(nombre, numDat);

    // Ordenamos un arreglo con valores enteros
    int arr[] = {34, 56, 22, 36, 12, 7, 83, 18, 63, 14};
    qsort(arr,  10,  sizeof(int),  intComp);

    printf("Los valores ordenados:\n");
    for(i = 0;  i < 10;  i++)
        printf("%4d", arr[i]);
    printf("\n");

    return 0;
}

void leeCad(char **&nombre, int &numDat) {
    char *auxNomb[100], cad[100];
    int tam, i;

    while (1) {
        gets(cad);
        tam = strlen(cad);
        if (tam == 0) break;
        auxNomb[numDat] = new char[tam+1];
        strcpy(auxNomb[numDat], cad);
        numDat++;
    }
    nombre = new char*[numDat];
    for(i = 0; i&lr; numDat; i++)
        nombre[i] = auxNomb[i];
}

void imprime(char **nombre, int numDat) {
    int i;
    printf("Los nombres ordenados:\n");
    for(i = 0; i<numDat; i++)
        printf("%s\n", nombre[i]);
    putchar('\n');
}

Aplicaciones con punteros a funciones

A continuación se presentan dos aplicaciones que pretenden ilustrar el uso de ls punteros a funciones, en el primero vamos a mostrar la ordenación de datos simples de modo que se pueda ordenar diferente tipo de información almacenada en un archivo de textos, en este caso se emplearán arreglos. La segunda aplicación pretenderá tambi&aecute; ordenar datos pero empleando una lista ligada.

Ordenación de datos mediante arreglos

Si tenemos archivos de textos como los que se muestran a continuación:

Debido a que se trata de archivos diferentes, lo primero que se podría pensar para ordenarlos es elaborar tres programas, uno por cada tipo de dato, pero esto no es lógico.

Una segunda solución que se podría plantear sería, ya que los datos están en un archivo de textos, almacenar los datos en un arreglo de cadenas de caracteres, y ordenarlos como tal. Sin embargo , si hacemos eso la respuesta sería como se presenta a continuación:

Observe que con los nombres la ordenación estaría bien, pero con los otros no. La razón es porque el sistema, para saber si una cadena es mayor que otra, compara el primer caracter de ambas cadenas, si son diferentes la cadena mayor será que tenga el caracter con mayor código ASCII, si son iguales analiza los segundos caracteres de ambas cadenas, y así hasta encontrar una diferencia; por eso es que en el archivo de números primero salen los que comienzan por 1, luego por 2, etc. Lo mismo pasa con las fechas.

Otra forma de solucionar el problema es mediante el uso de una función que tenga como parámetro un puntero a función, algo similar a qsort pero más simple. La función recibirá como parámetro además un arreglo de cadenas de caracteres y los límites entre los cuales se desea ordenar. El puntero a función recibirá lal dirección de la función que emplearemos para ordenar. Para que el programa pueda distinguir qué función deberá emplear, ingresaremos parámetros al programa desde la línea de comandos del sistema operativo, de modo que si ingresamos el parámetro "-c" el programa tomará los datos del archivo y los ordenara como cadenas de caracteres simple, si se ingresa "-n" los datos serán comparados como números, y si se ingresa "-f" se considerará que los datos son fechas. Esta forma de resolver el problema nos permitirá en cualquier momento agregar nuevas funciones de comparación cuando se nos prsente un nuevo tipo de dato a ordenar.

A continuación mostramos el código del programa que realiza esta operación:

Grabar este ejemplo

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

// Prototipos de funciones
    void error(void);
    void leerDatos(char ** &, int &);
    void imprimeDatos(char **, int);
    int intcmp(char *, char *);
    int fechcmp(char *, char *);
    void ordenar(char **, int, int, int (*)(char *, char *));
    void intercambiar(char **, int, int);

int main(int argc, char ** argv) {
    char ** datos;
    int numElem = 0;
    int (*ptrFunCmp)(char *, char *);

    // Verificamos si colocó la opción que indica cómo ordenar
    if (argc != 2) { // 2 indica que hay un argumento
        error();  return 0;
    }
    else {
        switch (argv[1][1]) { // Se compara el 2do. caracter del 1er. argumento
            case 'c':
                  ptrFunCmp = (int (*)(char *, char *)) strcmp;
                  // El "cast" se debe a que strcmp no coincide exactamente
                  // con el parámetro de la función ordenar

                  break;
            case 'n':
                  ptrFunCmp = intcmp;
                  break;
            case 'f':
                  ptrFunCmp = fechcmp;
                  break;
            default:
                  error( );   return 0;
        }
        leerDatos(datos, numElem);
        ordenar (datos, 0, numElem - 1, ptrFunCmp);
        imprimeDatos(datos, numElem);
    }
    return 0;
}

void error(void) { // Función que muestra un error al ejecutar el programa
    printf("Debe ejecutar el programa con un parametro:\n");
    printf("\t-c\tPara ordenar nombres alfabeticamente\n");
    printf("\t-n\tPara ordenar numeros ascendentemente\n");
    printf("\t-f\tPara ordenar fechas cronologicamente\n");
}

void leerDatos(char **amp;datos, int &numElem) {
    // lee los datos como cadenas de caracteres
    char *auxDatos[500], cad[100];
    int tam, i;

    while (1) {
        gets(cad);
        tam = strlen(cad);
     if (tam == 0) break;  //el final delos datos se da con una cadena vacía
        auxDatos[numElem] = new char[tam + 1];
        strcpy(auxDatos[numElem], cad);
        numElem++;
    }
    // Pasamos los datos a un arreglo dinámico de capacidad exacta
    datos = new char *[numElem];
    for(i = 0; i < numElem; i++)
        datos[i] = auxDatos[i];
}

void imprimeDatos(char **datos, int numElem) {
    int i;
    printf("Los datos ordenados:\n");
    for(i = 0; i < numElem; i++)
        printf("%s\n", datos[i]);
    putchar('\n');
}

int intcmp(char *s1, char *s2) {  // función para comparar las cadenas como
                                               // números enteros
    int i1, i2;
    i1 = atoi(s1);
    i2 = atoi(s2);
    return i1 - i2;  // Valor retornado: < 0 si i16 < i2, 0 si son iguales y > 0 si i1 > i2
}

int fechcmp(char *s1, char *s2) {  // función para comparar las cadenas como fechas
    char f1[11], f2[11];

    s1[2] = s1[5] = s2[2] = s2[5] = 0;
    strcpy(f1, &s1[6]);        strcpy(f2, &s2[6]);
    strcat(f1, "/");             strcat(f2, "/");
    strcat(f1, &s1[3]);         strcat(f2, &s2[3]);
    strcat(f1, "/");             strcat(f2, "/");
    strcat(f1, s1);               strcat(f2, s2);
    s1[2] = s1[5] = s2[2] = s2[5] = '/';

    return strcmp(f1, f2);
}

void ordenar (char **datos, int izq, int der, int (*cmp)(char*, char*)){
    int ultimo;

    if(izq >= der) return;
    intercambiar(datos, izq, (izq + der)/2);
    ultimo = izq;
    for (int i = izq + 1; i <= der; i++)
        if (cmp(datos[i], datos[izq]) < 0)
              intercambiar(datos, ++ultimo, i);

    intercambiar(datos, izq, ultimo);

    ordenar(datos, izq, ultimo - 1, cmp);
    ordenar(datos, ultimo + 1, der, cmp);
}

void intercambiar(char **datos, int i, int j) {
    char *aux;

    aux = datos[i];
    datos[i] = datos[j];
    datos[j] = aux;
}

A continuación mostramos la ejecución del programa:

Listas ligadas genéricas

Este ejercicio pretende construir una lista simplemente ligada ordenada de punteros, en la cual podamos colgra cualquier tipo de información. La figura siguiente muetra algunas listas simplemente ligadas como las que s equieren comfeccionar:

La idea en la solución de este problema es la de poder crear primero una biblioteca de funciones que permita crear, imprimir y eliminar una lista ligada simplemente enlazada. La particularidad de esto está en que las funcione definidas en esta biblioteca no saben qué tipo de dato va a administrar la lista; el campo de datos de los nodos de la lista manejará sólo un puntero genérico. La creación de los datos, su colocación ordenada en la lista, la impresión del dato y su eliminación se manejaán através de punteros a funciones.

De acuerdo a esto, para trabajar con una lista que maneje un tipo de dato en particular (valores numéricos, cadenas de caracteres, registros, etc.) sólo se tendrá que crear una bibliteca de funciones que permita leer, imprimir, eliminar y comparar el tipo de dato en particular. Estas funciones tendrán que definirse bajo una plantilla establecida.

El codigo de este programa se muestra a continuación:

Grabar este ejemplo

1 - Función principal

Aquí, la función main no sabe qué tipo de datos se va a almacenar en la lista ligada. El cuerpo de la función sólo hace un llamado a las funciones creaLista, imprimeLista y eliminaLista que están definidas en los módulos lista.h y lista.cpp. En esas llamadas se pasa como parámetros las funciones compDato, impDato y elimDato que están definidas en los módulos manipDato.h y manipDato.cpp; estas funciones deben seguir una plantilla y tener el código necesario para manipular el tipo de dato que deseamos colgar de nuestra lista.

#include <stdlib.h>
#include "manipDato.h"
#include "lista.h"

int main(void) {
    void *lista = NULL;
    // Aquí, la función main no sabe qué tipo de datos va a almacenar en la
    // lista dligada.
    // Las funciones: creaLista, imprimeLista y eliminaLista están definidas
    // en los módulos lista.h y lista.cpp
    // Las funciones: compDato, impDato y elimdato están definidas envlos
    // módulos manipDato.h y manipDato.cpp

    crearLista(lista, leeDato, compDato);
    imprimeLista(lista, impDato);
    eliminaLista(lista, elimDato);

    return (EXIT_SUCCESS);
}

2 - Biblioteca de funciones Lista.h y Lista.cpp

Esta biblioteca trata de definir las funciones necesarias para crear y manipular una lista ligada, aquí encontramos funciones de permiten insetar nodos en una lista simplemente ligada, imprimir la lista completa y finalmente eliminarla de la meoria. La particularidad de esta biblioteca es que, como en el caso de la función main, las funciones definidas aquí, tampoco saben qué tipo de dato se van a manejar; de este modo se garantiza que sea cula sea el tipo de dato que se desee colgar de la lista, las funciones definidas en esta biblioteca no se modificarán.

//****************************************************
//
//                                Módulo: Lista.h
//
//            Funciones para crear, imprimir y eleiminar
//                                una lista genérica
//
//****************************************************


#ifndef _LISTA_H
#define _LISTA_H
    void crearLista(void *&,  void * (*)(void),  int (*)(void *, void *));
    void imprimeLista(void *, void (*)(void *));
    void eliminaLista(void *, void (*)(void *));
    void insertLista(void *∓, void *, int (*)(void *, void *));
#endif  /* _LISTA_H */

//****************************************************
//
//                                Módulo: Lista.cpp
//
//                Módulo de implementación de la funciones
//
//****************************************************


#include <stdio.h>
#include "lista.h"

// Aquí, las funciones definidas son capaces de manipular una lista ligada
// sin saber qué tipo de dato va a manejar, todo el trabajo se realiza
// a través de punteros a funciones que son los que manipulan los datos
// específicos para cada situación.


void crearLista(void *∓lista, void * (*leeDato)(void),
                        int (*compDato)(void *, void*)) {
    void *dato;

    while (1) {
        dato = leeDato();  // Lee un dato de cualquier tipo y devuelve
                                   // un puntero genérico que apunta al dato

        if (dato == NULL) break;
        insertLista(lista, dato, compDato);
    }
}

void insertLista(void *&lista, void *dato,
                        int (*compDato)(void*, void*) ) {
    void **p, **nuevo, **ant;

    nuevo = new void *[2];
    nuevo[0] = dato;  // Cuelga el dato sea cual fuera su naturaleza

    p = (void**)lista;
    ant = NULL;
    while(p) {
        if (compDato(p[0], dato) > 0) break;  // Compara dosVdatos, devuelve 0 si
                   // son iguales, un valor mayor que cereo si el primero es mayor que
                   // el segundo y un valor menor que cereo si el primero es menor que
                   // el segundo. El tipo de dato que comprar depende de la función a
                   // la que apunte el puntero

        ant = p;
        p = (void**)(p[1]);
    }
    nuevo[1] = p;
    if(ant == NULL) lista = nuevo;
    else ant[1] = nuevo;
}

void imprimeLista(void *lista, void (*impDato)(void *)) {
    void **lst;

    lst = (void**)lista;

    while (lst) {
        impDato(lst[0]);  // imprime un dato sea cualfuera su naturaleza
        lst = (void**)lst[1];
    }
}

void eliminaLista(void *lista, void (*elimDato)(void *)) {
    void **lst, **sale;

    lst = (void**)lista;

    while (lst) {
        elimDato(lst[0]);  // elimina un dato sea cual fuera su naturaleza
        sale = lst;
        lst = (void**)lst[1];
        delete [ ]sale;
    }
}

3 - Biblioteca de funciones ManipDato.h y ManipDatos.cpp

Esta biblioteca es la que manipulará los datos que se desea colgar de la lista simplemente ligada. Se deberá implementar las funciones de ella cada vez que se quiera colgar un tipo de dato diferente. Los prototipos de las funciones no deben cambiar y debe ser considerados como una plantilla.

A continuación se presenta el archivo Manip.h:

//****************************************************
//
//                                Módulo: ManipDato.h
//
//                  Funciones que permiten crear, imprimir,
//              eliminar y comparar un dato específico según
//                                  una plantilla dada
//
//****************************************************


#ifndef _MANIPDATO_H
#define _MANIPDATO_H
    void * leeDato(void);
    // Lee un dato a través de un putero, devuelve un puntero genérico
    // al dato o NULL en caso que se hayan terminado los datos.


    int compDato(void *, void *);
    // Compara dos datos a través de dos punteros void. Si son iguales
    // devuelve cero, si el primeto es menor que el segundo, se devuelve
    // un valor menor que cero y encaso contrario un valor mayor que cero.


    void impDato(void *);
    // Imprime un dato a través de un puntero void.

    void elimDato(void *);
    // Elimina un dato a través de un puntero void.
#endif  /* _MANIPDATO_H */

A partir de estos prototipos se podrá implementar las funciones de acuerdo al tipo de datos que se quiere procesar. Veamos algunos casos:

a) - Manipulación de datos enteros

En este caso se quiere colgar vaolres numéricos enteros en la lista, entonces el código de las funciones será como sigue:

//****************************************************
//
//                        Módulo: ManipDato.cpp Versión 1
//
//                Módulo de implementación de la funciones
//                        para manejar valores enteros
//
//****************************************************


#include <stdio.h>

void * leeDato(void) {
    // lee un entero, si se intenta leer el fin del archivo
    // devuelve NULL

    int dato, *ptDato;

    if (scanf("%d", &dato) == EOF) return NULL;
    ptDato = new int;
    *ptDato = dato;
    return ptDato;
}

int compDato(void *v1, void *v2) {
    int *n1, *n2;
    // Compara los valores enteros apuntados por los punteros
    n1 = (int *)v1;
    n2 = (int *)v2;
    return *n1 - *n2;
}

void impDato(void *v) {
   int *n;

    // Imprime los valores enteros apuntados por los punteros
    n = (int *)v;
    printf("%d\n", *n);
}

void elimDato(void *v) {
    int *n;

    // Elimina los valores enteros apuntados por los punteros
    n = (int *)v;
    delete n;
}

b) - Manipulación de cadenas de caracteres

//****************************************************
//
//                        Módulo: ManipDato.cpp Versión 2
//
//                Módulo de implementación de la funciones
//                    para manejar cadenas de caracteres
//
//****************************************************


#include <stdio.h>
#include <string.h>

void * leeDato(void) {
    // lee una cadena, si se intenta leer una cadena
    // vacía develve NULL
    char *dato, aux[300];
    int tam;

    if (gets(aux) == NULL) return NULL;
    tam = strlen(aux);
    if (tam == 0) return NULL;
    dato = new char[tam + 1];
    strcpy(dato, aux);

    return dato;
}

int compDato(void *v1, void *v2) {
    char *n1, *n2;

    // Compara las cadenas de caracteres apuntadas por los punteros
    n1 = (char *)v1;
    n2 = (char *)v2;
    return strcmp(n1, n2);
}

void impDato(void *v) {
    char *n;

    // Imprime las cadenas apuntados por los punteros
    n = (charv*)v;
    printf("%s\n", n);
}

void elimDato(void *v) {
    char *n;

    // Elimina las cadenas apuntadas por los punteros
    n = (char *)v;
    delete [ ]n;
}

c) - Manipulación de registros de datos

//****************************************************
//
//                        Módulo: ManipDato.cpp Versión 3
//
//                Módulo de implementación de la funciones
//                      para manejar registros de datos
//
//****************************************************


#include <stdio.h>
#include <string.h>
void * leeDato(void) {
    void **dato;
    char auxStr[300], *nombre, *fechIng;  // <-- dd/mm/aaaa
    int *codigo, tam;
    float *sueldo;

    // lee una ficha que contiene el nombre, el código,
    // la fecha de ingreso y el sueldo de empleados a una
    // compañía, si se intenta leer un nombre vacío
    // develve NULL

    printf("Nombre: ");
    tam = strlen(auxStr);
    if (tam == 0) return NULL;

    dato = new void *[4];
    nombre = new char[strlen(auxStr) + 1];
    strcpy(nombre, auxStr);

    printf("Codigo: ");
    codigo = new int;
    scanf("%d", codigo);
    while(getchar( ) != '\n');

    printf("Fecha de ingreso: ");
    fechIng = new char[11];  // <-- dd/mm/aaaa0
    scanf("%s", fechIng);

    printf("Sueldo: ");
    sueldo = new float;
    scanf("%f", sueldo);
    while(getchar( ) != '\n');

    dato[0] = nombre;
    dato[1] = codigo;
    dato[2] = fechIng;
    dato[3] = sueldo;

    return dato;
}

int compDato(void *v1, void *v2) {
    void **n1, **n2;
    int *c1, *c2;

    // Compara los segundos campos de registros apuntados
    // por los punteros

    n1 = (void **)v1;
    n2 = (void **)v2;
    c1 = (int *)n1[1];
    c2 = (int *)n2[1];

    return *c1 - *c2;
}

void impDato(void *v){
    void **n;

    // Imprime los campos de registros apuntados por
    // los punteros

    n = (void **)v;
    char *nombre, *fechIng;
    int *codigo;
    float *sueldo;

    nombre  = (char *)n[0];
    codigo    = (int *)n[1];
    fechIng  = (char *)n[2];
    sueldo    = (float *)n[3];

    printf("Nombre:              %s\n", nombre);
    printf("Codigo:                %d\n", *codigo);
    printf("Fecha de ingreso: %s\n", fechIng);
    printf("Sueldo:                %f\nV, *sueldo);
}

void elimDato(void *v) {
    void **n;
    char *nombre, *fechIng;
    int *codigo;
    float *sueldo;

    // elimina los campos y los registros apuntados por
    // los punteros

    n = (void **)v;
    nombre   = (char *)n[0];
    codigo    = (int *)n[1];
    fechIng  = (char *) n[2];
    sueldo     = (float *)n[3];

    delete [ ]nombre;
    delete codigo;
    delete [ ]fechIng;
    delete sueldo;
    delete [ ]n;
}

Volver a contenidos AtrásSiguiente