Implementar Vector en C

Implementar Vector en C

En mi artículo anterior, expliqué cómo podemos crear una matriz dinámica en C. Pero mi lector dice que escriba un artículo para crear un vector en C. Básicamente, el vector es una matriz dinámica que tiene la capacidad de cambiar su tamaño automáticamente cuando un elemento añadir o eliminar del vector.

Un elemento vectorial se almacena de manera continua para que podamos acceder al elemento usando el índice. Es genial y también le gusta la lista enlazada, no necesitamos asignar la memoria para cada nodo. Asignamos la memoria adicional al principio y la ajustamos según el requisito.

Entonces, entremos en el tema y creemos un vector simple. Debido a que C no es compatible con la plantilla y el vector, aquí estoy creando un vector usando la estructura y el puntero. Este vector almacenará la dirección del elemento usando el void * (Puntero genérico, puedes ver este artículo). La ventaja del puntero vacío es que podemos almacenar la dirección de cualquier tipo de datos.

Implementación de código del vector en C

Primero, necesitamos crear una estructura que almacene los datos y también rastrear los datos almacenados. También estoy creando aquí otra estructura para almacenar el puntero de función que apunta a la función de vector (porque C no admite la función en una estructura como C++).

//Store and track the stored data
typedef struct sVectorList
{
    void **items;
    int capacity;
    int total;
} sVectorList;

//structure contain the function pointer
typedef struct sVector vector;
struct sVector
{
    sVectorList vectorList;
//function pointers
    int (*pfVectorTotal)(vector *);
    int (*pfVectorResize)(vector *, int);
    int (*pfVectorAdd)(vector *, void *);
    int (*pfVectorSet)(vector *, int, void *);
    void *(*pfVectorGet)(vector *, int);
    int (*pfVectorDelete)(vector *, int);
    int (*pfVectorFree)(vector *);
};

Ahora necesita crear alguna macro para una mejor legibilidad y asignar la memoria inicialmente. Puede cambiar el valor de la macro según sus requisitos.

#define VECTOR_INIT_CAPACITY 6
#define UNDEFINE  -1
#define SUCCESS 0


#define VECTOR_INIT(vec) vector vec;\
 vector_init(&vec)

Inicialización de vectores:

En esta función, estoy inicializando la capacidad del vector y los punteros de función con la función apropiada.

void vector_init(vector *v)
{
    //init function pointers
    v->pfVectorTotal = vectorTotal;
    v->pfVectorResize = vectorResize;
    v->pfVectorAdd = vectorPushBack;
    v->pfVectorSet = vectorSet;
    v->pfVectorGet = vectorGet;
    v->pfVectorFree = vectorFree;
    v->pfVectorDelete = vectorDelete;
    //initialize the capacity and allocate the memory
    v->vectorList.capacity = VECTOR_INIT_CAPACITY;
    v->vectorList.total = 0;
    v->vectorList.items = malloc(sizeof(void *) * v->vectorList.capacity);

}

Redimensionar el vector:

Esta función asigna la memoria con un nuevo tamaño utilizando la función de biblioteca realloc y actualiza el parámetro de seguimiento con el nuevo valor. También puedes ver el artículo , Cómo asignar memoria dinámica en C.

int vectorResize(vector *v, int capacity)
{
    int  status = UNDEFINE;
    if(v)
    {
        void **items = realloc(v->vectorList.items, sizeof(void *) * capacity);
        if (items)
        {
            v->vectorList.items = items;
            v->vectorList.capacity = capacity;
            status = SUCCESS;
        }
    }
    return status;
}

Función de retroceso:

Esta función inserta los datos al final del vector. Si no hay suficiente memoria disponible, cambiará el tamaño de la memoria.

int vectorPushBack(vector *v, void *item)
{
    int  status = UNDEFINE;
    if(v)
    {
        if (v->vectorList.capacity == v->vectorList.total)
        {
            status = vectorResize(v, v->vectorList.capacity * 2);
            if(status != UNDEFINE)
            {
                v->vectorList.items[v->vectorList.total++] = item;
            }
        }
        else
        {
            v->vectorList.items[v->vectorList.total++] = item;
            status = SUCCESS;
        }
    }
    return status;
}

Establecer datos en un índice determinado:

Esta función establece los datos en el índice dado si el índice es válido. Si pasa el índice no válido, no hará nada.

int vectorSet(vector *v, int index, void *item)
{
    int  status = UNDEFINE;
    if(v)
    {
        if ((index >= 0) && (index < v->vectorList.total))
        {
            v->vectorList.items[index] = item;
            status = SUCCESS;
        }
    }
    return status;
}

Obtenga la dirección de los datos del índice dado:

Si el índice es válido, esta función devolverá la dirección de los datos del índice dado. Si el índice no es válido, devolverá NULL (puntero nulo). Debe encasillar la memoria según los tipos de datos.

void *vectorGet(vector *v, int index)
{
    void *readData = NULL;
    if(v)
    {
        if ((index >= 0) && (index < v->vectorList.total))
        {
            readData = v->vectorList.items[index];
        }
    }
    return readData;
}

Eliminar los datos del índice dado:

Esta función asigna NULL al índice dado y desplaza todos los elementos en el vector en 1.

int vectorDelete(vector *v, int index)
{
    int  status = UNDEFINE;
    int i = 0;
    if(v)
    {
        if ((index < 0) || (index >= v->vectorList.total))
            return status;

        v->vectorList.items[index] = NULL;

        for (i = index; (i < v->vectorList.total - 1); ++i)
        {
            v->vectorList.items[i] = v->vectorList.items[i + 1];
            v->vectorList.items[i + 1] = NULL;
        }

        v->vectorList.total--;

        if ((v->vectorList.total > 0) && ((v->vectorList.total) == (v->vectorList.capacity / 4)))
        {
            vectorResize(v, v->vectorList.capacity / 2);
        }
        status = SUCCESS;
    }
    return status;
}

Libere la memoria asignada:

Esta función desasigna la memoria asignada.

int vectorFree(vector *v)
{
    int  status = UNDEFINE;
    if(v)
    {
        free(v->vectorList.items);
        v->vectorList.items = NULL;
        status = SUCCESS;
    }
    return status;
}

Código de ejemplo de un vector en C:

En este ejemplo, estoy creando un vector de cadena usando la función de retroceso. Después de la creación del vector, estoy mostrando la cadena almacenada con su índice. También configuré la cadena usando el índice. Debe recordar que la dirección de los datos debe ser válida y debe preocuparse por el puntero colgante. También puede ver este artículo “Cómo evitar que el puntero cuelgue“.

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


#define VECTOR_INIT_CAPACITY 6
#define UNDEFINE  -1
#define SUCCESS 0


#define VECTOR_INIT(vec) vector vec;\
 vector_init(&vec)

//Store and track the stored data
typedef struct sVectorList
{
    void **items;
    int capacity;
    int total;
} sVectorList;


//structure contain the function pointer
typedef struct sVector vector;
struct sVector
{
    sVectorList vectorList;
//function pointers
    int (*pfVectorTotal)(vector *);
    int (*pfVectorResize)(vector *, int);
    int (*pfVectorAdd)(vector *, void *);
    int (*pfVectorSet)(vector *, int, void *);
    void *(*pfVectorGet)(vector *, int);
    int (*pfVectorDelete)(vector *, int);
    int (*pfVectorFree)(vector *);
};


int vectorTotal(vector *v)
{
    int totalCount = UNDEFINE;
    if(v)
    {
        totalCount = v->vectorList.total;
    }
    return totalCount;
}

int vectorResize(vector *v, int capacity)
{
    int  status = UNDEFINE;
    if(v)
    {
        void **items = realloc(v->vectorList.items, sizeof(void *) * capacity);
        if (items)
        {
            v->vectorList.items = items;
            v->vectorList.capacity = capacity;
            status = SUCCESS;
        }
    }
    return status;
}

int vectorPushBack(vector *v, void *item)
{
    int  status = UNDEFINE;
    if(v)
    {
        if (v->vectorList.capacity == v->vectorList.total)
        {
            status = vectorResize(v, v->vectorList.capacity * 2);
            if(status != UNDEFINE)
            {
                v->vectorList.items[v->vectorList.total++] = item;
            }
        }
        else
        {
            v->vectorList.items[v->vectorList.total++] = item;
            status = SUCCESS;
        }
    }
    return status;
}

int vectorSet(vector *v, int index, void *item)
{
    int  status = UNDEFINE;
    if(v)
    {
        if ((index >= 0) && (index < v->vectorList.total))
        {
            v->vectorList.items[index] = item;
            status = SUCCESS;
        }
    }
    return status;
}

void *vectorGet(vector *v, int index)
{
    void *readData = NULL;
    if(v)
    {
        if ((index >= 0) && (index < v->vectorList.total))
        {
            readData = v->vectorList.items[index];
        }
    }
    return readData;
}

int vectorDelete(vector *v, int index)
{
    int  status = UNDEFINE;
    int i = 0;
    if(v)
    {
        if ((index < 0) || (index >= v->vectorList.total))
            return status;

        v->vectorList.items[index] = NULL;

        for (i = index; (i < v->vectorList.total - 1); ++i)
        {
            v->vectorList.items[i] = v->vectorList.items[i + 1];
            v->vectorList.items[i + 1] = NULL;
        }

        v->vectorList.total--;

        if ((v->vectorList.total > 0) && ((v->vectorList.total) == (v->vectorList.capacity / 4)))
        {
            vectorResize(v, v->vectorList.capacity / 2);
        }
        status = SUCCESS;
    }
    return status;
}

int vectorFree(vector *v)
{
    int  status = UNDEFINE;
    if(v)
    {
        free(v->vectorList.items);
        v->vectorList.items = NULL;
        status = SUCCESS;
    }
    return status;
}


void vector_init(vector *v)
{
    //init function pointers
    v->pfVectorTotal = vectorTotal;
    v->pfVectorResize = vectorResize;
    v->pfVectorAdd = vectorPushBack;
    v->pfVectorSet = vectorSet;
    v->pfVectorGet = vectorGet;
    v->pfVectorFree = vectorFree;
    v->pfVectorDelete = vectorDelete;
    //initialize the capacity and allocate the memory
    v->vectorList.capacity = VECTOR_INIT_CAPACITY;
    v->vectorList.total = 0;
    v->vectorList.items = malloc(sizeof(void *) * v->vectorList.capacity);

}

int main(int argc, char *argv[])
{
    int i =0;

    //init vector
    VECTOR_INIT(v);
    //Add data in vector
    v.pfVectorAdd(&v,"aticleworld.com\n");
    v.pfVectorAdd(&v,"amlendra\n");
    v.pfVectorAdd(&v,"Pooja\n");

    //print the data and type cast it
    for (i = 0; i < v.pfVectorTotal(&v); i++)
    {
        printf("%s", (char*)v.pfVectorGet(&v, i));
    }


    //Set the data at index 0
    v.pfVectorSet(&v,0,"Apoorv\n");

    printf("\n\n\nVector list after changes\n\n\n");

    //print the data and type cast it
    for (i = 0; i < v.pfVectorTotal(&v); i++)
    {
        printf("%s", (char*)v.pfVectorGet(&v, i));
    }


    return 0;
}

Salida: 

Artículos recomendados para ti:

  • ¿Cómo crear una matriz dinámica en C?
  • ¿Cómo acceder a la matriz 2D en C?
  • Puntero de función en c, una guía detallada
  • ¿Cómo usar la estructura del puntero de función en lenguaje c?
  • Puntero de función en la estructura.
  • Implementar memmove propio en C.
  • memmove frente a memcpy.
  • Implementar memcpy propio en C.
  • Cómo usar strncpy() e implementar su propio strncpy().
  • ¿Cómo pasar una matriz como parámetro?
  • Implementar atoi propio en C.
  • ¿Cómo usar la condición if-else de C?
  • ¿Cómo usar el bucle for en C?
  • Debe saber mientras usa el bucle.
  • Operadores con precedencia y asociatividad.
  • Aritmética de punteros en C.
  • puntero vacío en C.
  • Una breve descripción del puntero en C.
  • Puntero colgante, vacío, nulo y salvaje
  • ¿Cuándo y cómo usar array en C?
  • Diseño de memoria en C.
  • Manejo de archivos en C, en pocas horas.