Chiara
Chiara

Reputation: 45

Implementing vector (dynamic array) in C - functions and main file

This is a memory allocation program: I have to complete a given code (main and function file) given a header that has to implement the C++ vector functions in C. Here is the expected output (but of course the code has to be generalized enough not to just copy the output):


Vector vc1 now contains 5 characters (capacity=8): ciao
Vector vc2 now contains 9 characters (capacity=16): ciaociao
Vector vc2 now contains 11 characters (capacity=16): ciao--ciao
Vector vi1 now contains 10 integers:  0 1 2 3 4 5 6 7 8 9
Vector vc2 now contains 21 characters (capacity=32): ciao-0123456789-ciao
Vector vc2 now contains 5 characters (capacity=8): ciao
Vector vd1 now contains 10 doubles (capacity=16):  9.5 8.5 6.5 5.5 3.14159 4.5 3.5 2.5 1.5 0.5
Vector vd1 now contains 1 double (capacity=2):  6.28318
Vector vi1 now contains 2 integers (capacity=4):  0 9

I can only modify the code between the "TO BE DONE START" and "TO BE DONE END". I need to modify both the function file and the main file in order to make the program work.

Here is the function file (vector.c), and what I've already done is commented on the side with "THIS IS WHAT I'VE ADDED":

#include "vector.h"


void fail(const char* msg){
    fprintf(stderr,"\nERROR: %s\n\n",msg);
    exit(1);
}


void * check_a(void*p){
    if ( p == NULL )
        fail("check_a(): NULL pointer");
    return p;
}


vector_type v_create_empty(char type){
    vector_type my_v = (vector_type)check_a(malloc(sizeof(struct vector_struct)));

    my_v->e_sz = (type == V_INT ? sizeof(int) : type == V_DOUBLE ? sizeof(double) : 1);

    my_v->e_type = type;
    my_v->no_e = my_v->cur_cap = 0;
    my_v->e_array = NULL;
    return my_v;
}


void v_destroy(vector_type my_v){
    if ( my_v == NULL )
        return;

/*** TO BE DONE START ***/
    free(my_v->e_array);          //THIS IS WHAT I'VE ADDED
/*** TO BE DONE END ***/

    free((void*)my_v);
}


void* v_at(vector_type v, iterator i) {
    if ( v == NULL )
        fail("v_at() Error: no such vector");
    if ( i == iterator_end )
        i = v->no_e -1;
    if ( i < 0 || i >= v->no_e )
        fail("v_at() Error: no such element in this vector");

/*** TO BE DONE START ***/
    else                           //THIS IS WHAT I'VE ADDED
    v->e_array[i];
/*** TO BE DONE END ***/

}


void v_push_back(vector_type v, void* new_val){
    if ( v->no_e >= v->cur_cap ) {
        /*** need to expand the array ***/
        v->cur_cap += (v->cur_cap)? v->cur_cap : 2;

/*** TO BE DONE START ***/

/*** TO BE DONE END ***/

    }
    /*** copy new_val into the array at end position (v->no_e) ***/

/*** TO BE DONE START ***/
      v->e_array[v->no_e] = e_array      //THIS IS WHAT I'VE ADDED     
    v->e_array[v->e_sz++] = e_array;
/*** TO BE DONE END ***/

    (v->no_e)++;
}


void v_pop_back(vector_type v){
    if ( v == NULL )
        fail("v_pop_back(): no such vector");
    if ( v->no_e == 0 )
        return;
    if ( --(v->no_e) < ((v->cur_cap)>>1) ) {
        /*** reallocate a smaller array ***/
        (v->cur_cap) >>= 1;

/*** TO BE DONE START ***/                      //THIS IS WHAT I'VE ADDED (but I'm lost on this one)
//    for (int i = 0; i < v->no_e - 1; i++) {
//        v->e_array[i] = v->e_array[i + 1];
//        v->e_array[i + 1] = NULL;
//    }
//   v->no_e--;
/*** TO BE DONE END ***/

    }
}


void v_insert_n(vector_type v,iterator start_i,unsigned n,void* new_val){
    char tmp[v->e_sz];
    int i;
    unsigned to_move;

    if ( n==0 ) /*** nothing to insert ***/
        return;
    if ( v == NULL )
        fail("v_insert_n(): no such vector");
    if ( start_i == iterator_end )
        start_i = v->no_e;
    if ( start_i < 0 )
        fail("v_insert_n(): bad iterator");

    /*** a zero element of suitable size ***/
    memset((void*)tmp,0,v->e_sz);

    if ( start_i >= v->no_e ) {
        /*** want to append past the end ***/
        /*** fill the possible gap with zero elements... ***/
        while ( start_i > v->no_e )
            v_push_back(v,(void*)tmp);
        /*** ...then append new elements at end ***/
        for (i=0; i<n; i++)
            v_push_back(v,new_val);
        return;
    }

    /*** want to insert at intermediate position ***/
    /*** expand the array by appending zero elements ***/
    /*** then move some elements towards end to make room ***/

    to_move = v->no_e - start_i;

    for (i=0; i<n; i++)
        v_push_back(v,tmp);

    for (i=0; i<to_move; i++)
        memcpy (
            v->e_array + (v->no_e-1-i) * v->e_sz,
            v->e_array + (v->no_e-1-i-n) * v->e_sz,
            v->e_sz);

    /*** now copy new elements in the room ***/
    for (i=0; i<n; i++) {

/*** TO BE DONE START ***/

/*** TO BE DONE END ***/

    }
}


void v_erase_range(vector_type v,iterator start_i,iterator end_i){
    int i, j;

    if ( v == NULL )
        fail("v_erase_range(): no such vector");
    if ( start_i == iterator_end )
        start_i = v->no_e-1;
    if ( end_i == iterator_end )
        end_i = v->no_e;
    if ( start_i < 0 || start_i >= v->no_e || end_i < 0 )
        fail("v_erase_range(): bad iterator");
    if ( start_i >= end_i ) /*** nothing to erase ***/
        return;

    for ( i = start_i, j = end_i ; j < v->no_e ; i++, j++ )
        memcpy(
            v->e_array + (v->e_sz) * i,
            v->e_array + (v->e_sz) * j,
            v->e_sz);

    /*** call v_pop_back() to actually erase elements ***/
/*** TO BE DONE START ***/

/*** TO BE DONE END ***/

}

This is the main file I've got to modify:

#include "vector.h"

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

int main(){
    vector_type vi1, vd1, vc1, vc2;
    char c1;
    int i1;
    double d1;

    vi1 = v_create_empty(V_INT);
    vd1 = v_create_empty(V_DOUBLE);
    vc1 = v_create_empty(V_CHAR);
    vc2 = v_create_empty(V_CHAR);

    c1 = 'c'; v_push_back(vc1,(void*)&c1);
    c1 = 'i'; v_push_back(vc1,(void*)&c1);
    c1 = 'a'; v_push_back(vc1,(void*)&c1);
    c1 = 'o'; v_push_back(vc1,(void*)&c1);
    c1 = 0; v_push_back(vc1,(void*)&c1);

    printf("Vector vc1 now contains %d characters (capacity=%1d): %s\n",
           vector_size(vc1),vector_capacity(vc1),vector_string(vc1));

    for ( i1 = 0, c1 = vector_char_at(vc1,i1) ; c1 ; i1++, c1 = vector_char_at(vc1,i1) )
        v_push_back(vc2,(void*)&c1);
    for ( i1 = 0, c1 = vector_char_at(vc1,i1) ; c1 ; i1++, c1 = vector_char_at(vc1,i1) )
        v_push_back(vc2,(void*)&c1);
    v_insert_n(vc2,iterator_end,1,(void*)&c1); /*** inserting 0 at the end ***/

    printf("Vector vc2 now contains %d characters (capacity=%1d): %s\n",
           vector_size(vc2),vector_capacity(vc2),vector_string(vc2));

    c1 = '-'; v_insert_n(vc2,vector_size(vc1)-1,2,(void*)&c1);

    printf("Vector vc2 now contains %d characters (capacity=%1d): %s\n",
           vector_size(vc2),vector_capacity(vc2),vector_string(vc2));

    for ( i1 = 0 ; i1 < 10 ; i1++ )
        v_push_back(vi1,(void*)&i1);

    printf("Vector vi1 now contains %d integers: ",vector_size(vi1));
    for ( i1 = 0 ; i1 < vector_size(vi1) ; i1++ )
        printf(" %1d",vector_int_at(vi1,i1));
    printf("\n");

    for ( i1 = 0 ; i1 < vector_size(vi1) ; i1++ ) {
        c1 = '0' + vector_int_at(vi1,i1); /*** converting decimal number to char ***/
        v_insert_n(vc2,5+i1,1,(void*)&c1);
      }

    printf("Vector vc2 now contains %d characters (capacity=%1d): %s\n",
           vector_size(vc2),vector_capacity(vc2),vector_string(vc2));

    v_erase_range(vc2,2,3+vector_size(vc1)+vector_size(vi1));

    printf("Vector vc2 now contains %d characters (capacity=%1d): %s\n",
           vector_size(vc2),vector_capacity(vc2),vector_string(vc2));

    v_destroy(vc1); v_destroy(vc2);

    for ( i1 = vector_size(vi1)-1 ; i1 >= 0 ; i1-- ) {
        d1 = 0.5 + (double)(vector_int_at(vi1,i1));
        v_push_back(vd1,(void*)&d1);
      }
    d1 = 3.14159192; /*** approximation of Pi ***/
    v_insert_n(vd1,5,1,(void*)&d1);
    v_erase_range(vd1,2,3);

    printf("Vector vd1 now contains %d doubles (capacity=%1d): ",
           vector_size(vd1),vector_capacity(vd1));
    for ( i1 = 0 ; i1 < vector_size(vd1) ; i1++ )
        printf(" %lg",vector_double_at(vd1,i1));
    printf("\n");

    d1 = vector_double_at(vd1,8) + vector_double_at(vd1,9); /*** d1 = 1.5+0.5 = 2.0 ***/
    v_erase_range(vd1,0,4); /*** erase first 4 elements **/
    vector_double_at(vd1,0) *= d1; /*** 2*Pi at index 0 ***/
    v_erase_range(vd1,1,iterator_end); /*** erase all elements but the first ***/

    printf("Vector vd1 now contains %d double (capacity=%1d): ",
           vector_size(vd1),vector_capacity(vd1));
    for ( i1 = 0 ; i1 < vector_size(vd1) ; i1++ )
        printf(" %lg",vector_double_at(vd1,i1));

/*** TO BE DONE START ***/ //NOT SURE ABOUT HERE
    d1 = vector_double_at(vd1,8) + vector_double_at(vd1,9) + vector_double_at(vd1,10) + vector_double_at(vd1,11); // d1 = 6.0+0.2+0.08+0.003+0.008 = 6.2838 
/*** TO BE DONE END ***/

    v_erase_range(vi1,1,9); /*** erase elements 1,...,8 ***/
    printf("Vector vi1 now contains %d integers (capacity=%1d): ",
           vector_size(vi1),vector_capacity(vi1));
    for ( i1 = 0 ; i1 < vector_size(vi1) ; i1++ )
        printf(" %1d",vector_int_at(vi1,i1));
    printf("\n");
    v_destroy(vi1);

    exit(0);
}


This is the header file:

#ifndef vECTOR_h
#define vECTOR_h

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

typedef int iterator;
#define iterator_begin 0
#define iterator_end -1

typedef struct vector_struct {
    size_t e_sz;
        char e_type;

#define V_INT 1
#define V_DOUBLE 2
#define V_CHAR 3

    unsigned no_e;
    unsigned cur_cap;
    void* e_array;

}* vector_type;

#define vector_size(v) ((v)->no_e)
#define vector_capacity(v) ((v)->cur_cap)

#define vector_int_at(v,i) (*((int*)v_at(v,i)))
#define vector_double_at(v,i) (*((double*)v_at(v,i)))
#define vector_char_at(v,i) (*((char*)v_at(v,i)))
#define vector_string(v) ((char*)v_at(v,0))


extern void* check_a(void*);
extern void fail(const char*);
extern vector_type v_create_empty(char);
extern void v_destroy(vector_type);
extern void* v_at(vector_type, iterator);
extern void v_push_back(vector_type,void*);
extern void v_pop_back(vector_type);
extern void v_insert_n(vector_type,iterator,unsigned,void*);
extern void v_erase_range(vector_type,iterator,iterator);

#endif

Thanks in advance for any possible help!

Upvotes: 0

Views: 731

Answers (1)

Faizan Shah
Faizan Shah

Reputation: 133

inside V_AT() Return return (v->e_array+i*v->e_sz); //return element

void* v_at(vector_type v, iterator i) {
    if ( v == NULL )
        fail("v_at() Error: no such vector");
    if ( i == iterator_end )
        i = v->no_e -1;
    if ( i < 0 || i >= v->no_e )
        fail("v_at() Error: no such element in this vector");
/*** TO BE DONE START ***/
    return (v->e_array+i*v->e_sz); //return element
/*** TO BE DONE END ***/

}

Similarly at V_push_back:

void v_push_back(vector_type v, void* new_val){
    if ( v->no_e >= v->cur_cap ) {
        /*** need to expand the array ***/
        v->cur_cap += (v->cur_cap)? v->cur_cap : 2;
/*** TO BE DONE START ***/
        v->e_array = check_a(realloc(v->e_array, sizeof(void*) * v->cur_cap));
        //allocate memory
/*** TO BE DONE END ***/

    }
    /*** copy new_val into the array at end position (v->no_e) ***/
/*** TO BE DONE START ***/
    if(v->e_type==V_CHAR){
        memcpy(
              v->e_array +(v->no_e)*v->e_sz,
              new_val,
              v->e_sz
              );
    }else{
        v->e_array = check_a(realloc(v->e_array, v->e_sz * v->cur_cap));
        memcpy(
              v->e_array +(v->no_e*v->e_sz),
              new_val,
              v->e_sz
              );
    }
/*** TO BE DONE END ***/

    (v->no_e)++;
}

Upvotes: 1

Related Questions