Home > Software design >  Dynamically growing array of strings in C
Dynamically growing array of strings in C

Time:11-19

I want to create an array of variable size that stores strings of maximum length 40. I have performed research and found the following code,which creates a dynamic array of integers.

typedef struct {
  int *array;
  size_t used;
  size_t size;
} Array;

void initArray(Array *a, size_t initialSize) {
  a->array = malloc(initialSize * sizeof(int));
  a->used = 0;
  a->size = initialSize;
}

void insertArray(Array *a, int element) {
  // a->used is the number of used entries, because a->array[a->used  ] updates a->used only *after* the array has been accessed.
  // Therefore a->used can go up to a->size 
  if (a->used == a->size) {
    a->size *= 2;
    a->array = realloc(a->array, a->size * sizeof(int));
  }
  a->array[a->used  ] = element;
}

void freeArray(Array *a) {
  free(a->array);
  a->array = NULL;
  a->used = a->size = 0;
} 

I am currently trying to modify the code, to make it work for my problem. I have so far come up with this

typedef struct {
  
  size_t used;
  size_t size;
  char *array[][40];
} Array;

void initArray(Array *a, size_t initialSize) {
  a->array = malloc(initialSize * sizeof(char));
  a->used = 0;
  a->size = initialSize;
}

void insertArray(Array *a, char element) {
  // a->used is the number of used entries, because a->array[a->used  ] updates a->used only *after* the array has been accessed.
  // Therefore a->used can go up to a->size 
  if (a->used == a->size) {
    a->size *= 2;
    a->array = realloc(a->array, a->size * sizeof(char));
  }
  strcpy(a->array[a->used  ], element);
} 

Finally

Array a;
char srcname[40];
initArray(&a, 100); 
insertArray(&a, srcname); 

This produces a segmentation fault. Although I have researched, I have not managed to make a working dynamic array of strings. Any guidance would be appreciated

CodePudding user response:

If you want to store the strings with max length of 40 characters including the terminating null character, you can use flexible array members. You do not special function to initialize the array, the string adding one will do initialization as well (you only need to pass NULL as a parameter showing that the array was not initialized yet). The function automatically changes the size of the string array in the steps defined in STEP macrodefinition.

typedef struct {
  size_t used;
  size_t size;
  char array[][40];
} Array;

#define STEP    64

Array *addString(Array *arr, const char *str)
{
    size_t newsize;
    if(!arr || arr -> size == arr -> used)
    {
        newsize = arr ? arr -> size   STEP : STEP;
        arr = realloc(arr, sizeof(*arr)   newsize * sizeof(arr -> array[0]));
        arr -> size = newsize;
        arr -> used = newsize == STEP ? 0 : arr -> used;
    }
    if(arr)
    {
        strncpy(arr -> array[arr -> used], str, sizeof(arr -> array[0]));
        arr -> array[arr -> used][sizeof(arr -> array[0]) - 1] = 0;
        arr -> used  ;
    } 
    return arr;
}

int main(void)
{
    Array *arr = NULL, *tmp;

    // function wrks same as realloc so you need to assign the temp variable to
    // avoid memory leak in case of error. I will skip it for the simplicity of the example

    for(size_t i = 0; i < 256; i  )
    {
        char str[40];
        sprintf(str,"String no: %zu", i);
        arr = addString(arr, str);
        printf("Array: size: %3zu used: %3zu\n", arr -> size, arr -> used);
    }

    for(size_t i = 0; i < 256; i  )
    {
        printf("Array sting no %zu: `%s`\n", i, arr -> array[i]);
    }
}

https://godbolt.org/z/8E7EbeaW7

CodePudding user response:

The declaration of the data member array in the structure

typedef struct {
  
  size_t used;
  size_t size;
  char *array[][40];
} Array;

is incorrect.

If you want to declare a pointer then you need to write

typedef struct {
  
  size_t used;
  size_t size;
  char ( *array )[40];
} Array;

The function initArray is also incorrect.

void initArray(Array *a, size_t initialSize) {
  a->array = malloc(initialSize * sizeof(char));
  a->used = 0;
  a->size = initialSize;
}

because there is allocated an incorrect array.

The function can look the following way

int initArray( Array *a, size_t initialSize) 
{
    a->used = 0;

    a->array = malloc( initialSize * sizeof( char[40] ) );
    int success = a->array != NULL;
    
    if ( success )
    {  
        a->size = initialSize;
    }
    else
    {
        a->size = 0;
    }

    return success;
}

Correspondingly the function insertArray (that has an incorrect type of the second parameter because you are going to pass a string not a single character are not you?) should be declared and defined like

int insertArray( Array *a, const char *element ) 
{
    int success = 1;

    if ( a->used == a->size ) 
    {
        char ( *tmp )[40] = realloc( a->array, 2 * a->size * sizeof( char[40] ) );
        if ( ( success = tmp != NULL ) )
        {
            a->array = tmp;
            a->size *= 2;
        }
    }

    if ( success )
    { 
        strcpy( a->array[a->used  ], element );
    }

    return success;
} 

And at last the array srcname

char srcname[40];

must contain a string before passing the array to the function insertArray.

  • Related