lunes, 13 de abril de 2009

Vectores Dinámicos en C

Si queremos usar vectores dinámicos en C necesitamos recurrir a funciones de manejo de memoria de la familia *alloc(). En este post explico cómo hacerlo de forma sencilla y añado algunas macros que facilitan la tarea.


Para empezar necesitaremos declarar el vector. Lo haremos como apuntador a NULL, creando así, un vector vacío. Necesitaremos también una variable que almacene el tamaño del vector, es decir, la cantidad de elementos que contiene.

Como ejemplo crearemos un vector de números enteros.

int *v = NULL;
size_t v_size = 0;



Tenemos un vector vacío, por lo que el siguiente paso no puede ser otro que añadir elementos. Lo haremos mediante realloc(), función que permite reasignar el tamaño reservado en memoria.



v_size++;
v = realloc(v, sizeof(int)*v_size);
v[v_size-1] = 5;


De esta manera podemos añadir tantos elementos como creamos oportuno. El acceso a ellos se realizará mediante la tradicional indexación de vectores v[i], donde i es el índice del vector. Así podremos acceder al contenido de las diferentes posiciones del vector tanto para leerlas como para escribir en ellas.

Finalmente, tendremos que liberar la memoria asignada al vector mediante la función free().


free(v);



A continuación pego un ejemplo completo del uso de vectores dinámicos con las sentencias comentadas anterioremente. Añado tambien un ejemplo de uso de la función qsort() que permite ordenar el vector.

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


int cmp(const void *a, const void *b)
{
   int *ia, *ib;

   ia = (int *) a;
   ib = (int *) b;

   return (*ia - *ib);
}

int main()
{
   /* Declaracion del vector y de su tamaño */
   int *v = NULL;
   size_t v_size = 0;


   /* Añade un elemento al vector con valor 5 */
   v_size++;
   v = realloc(v, sizeof(int)*v_size);
   v[v_size-1] = 5;

   /* Añade un elemento al vector con valor 3 */
   v_size++;
   v = realloc(v, sizeof(int)*v_size);
   v[v_size-1] = 3;

   /* Añade un elemento al vector con valor 1 */
   v_size++;
   v = realloc(v, sizeof(int)*v_size);
   v[v_size-1] = 1;

   /* Mofifica el valor del primer elemento del vector */
   v[0] = 2;

   /* Ordena el contenido del vector */
   qsort(v, v_size, sizeof(int), cmp);

   /* Muestra los elementos del vector */
   int i;
   for(i=0; i<v_size; i++)
      printf("%d ", v[i]);
   printf("\n");

   /* Libera la memoria asignada */
   free(v);

   return 0;
}




La sintaxis usada es un poco engorrosa, principalmente cuando se trata de añadir elementos a un vector. Esto puede solucionarse mediante el uso de macros. A continuación pego un ejemplo usando macros. En el puede verse también cómo pasar un vector como parámetro a una función.


#define VECTOR(v_var,v_size_var,type) \
   type *v_var = NULL; \
   size_t v_size_var = 0;

#define VECTOR_ADD(v_var,v_size_var,type,value) \
   (v_size_var)++; \
   v_var = realloc(v_var, sizeof(type)*(v_size_var)); \
   v_var[v_size_var-1] = value;
   
#define VECTOR_FREE(v_var) if(v_var) free(v_var);


void add_elements(int *v, size_t *v_size)
{
   VECTOR_ADD(v, *v_size, int, 3);
   VECTOR_ADD(v, *v_size, int, 5);
   VECTOR_ADD(v, *v_size, int, 7);
}  

int main()
{
   VECTOR(v, v_size, int);
   VECTOR_ADD(v, v_size, int, 2);
   
   add_elements(v, &v_size);

   int i;
   for(i=0; i<v_size; i++)
      printf("%d ", v[i]);
   printf("\n");
   
   VECTOR_FREE(v);

   return 0;
}




Para finalizar, solo recordar que el punto fuerte de los vectores es el acceso directo a los elementos (solo es necesaria una operación - O(1) ). Esto permite por ejemplo ordenar los elementos del vector a gran velocidad.

Por el contrario son costosas las inserciones de elementos. Pueden añadirse con facilidad al final, pero insertar un elemento en el medio, obliga a recolocar todos los demás elementos. Si se requiere una estructura de datos que permita estas operaciones es mejor recurrir a las listas dinámicas.


1 comentario:

LoboOscuro dijo...

Interesante, lastima que no sirve con new y delete.