Home > database >  How to properly replace day in a dynamically allocated C array
How to properly replace day in a dynamically allocated C array

Time:05-18

I am working on a basic framework to dynamically allocate array with the C language. I have created a function to create an array of strings titled init_string_vector. Data can be appended to the array with the append_string_vector function and data can be de-allocated from the heap with the free_string_array function. I am currently working on a function titled replace_string_vector_index that allows a user to pass an array index to the function as well as a pointer to the string array. If the array is typed as a STRING array and the index is not out of bounds, the function should replace the existing data with the string that a user passes to the function.

The replace_string_vector_index function appears to work properly and does replace the string at the index with the other string the user passed to the function. However, the free_string_array function no longer works once I have used to replace_string_vector_index function to act on the array. This makes me think that the process within the function is causing an issue, but I cannot see how. An example is shown below. When the free_string_array function fails, I get the following error, free(): invalid pointer.

vector.h

#ifndef ARRAY_H
#define ARRAY_H

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

typedef enum
{
    FLOAT,
    DOUBLE,
    CHAR,
    INT,
    STRING
} dat_type;
// --------------------------------------------------------------------------------

typedef struct
{
    char **array;
    size_t len;
    int elem;
    dat_type dat;
} StringVector;
// --------------------------------------------------------------------------------

int string_vector_mem_alloc(StringVector *array, size_t num_indices);
// --------------------------------------------------------------------------------

StringVector init_string_vector();
// --------------------------------------------------------------------------------

int append_string_vector(StringVector *s, char *value);
// --------------------------------------------------------------------------------

void free_string_array(StringVector *array);
// --------------------------------------------------------------------------------

int replace_string_vector_index(StringVector *array, int index, char string[]);
// --------------------------------------------------------------------------------

vector.c

#include "vector.h"

int string_vector_mem_alloc(StringVector *array, size_t num_indices) {
    // Determine the total memory allocation and assign to pointer
    void *pointer;
    pointer = malloc(num_indices * array->elem);

    // If memory is full fail gracefully
    if (pointer == NULL) {
        printf("Unable to allocate memory, exiting.\n");
        free(pointer);
        return 0;
    }
    // Allocate resources and instantiate Array
    else {
        array->array = pointer;
        array->len = 0;
        return 1;
    }
}
// --------------------------------------------------------------------------------

StringVector init_string_vector() {
    StringVector array;
    array.dat = STRING;
    array.elem = sizeof(char *);
    string_vector_mem_alloc(&array, array.elem);
    return array;
}
// --------------------------------------------------------------------------------

int append_string_vector(StringVector *array, char *value) {
    value = strdup(value);
    if (!value) {
        return -1;
    }
    array->len  ;
    char **resized = realloc(array->array, sizeof(char *)*array->len   1);
    if (!resized) {
        free(value);
        return -1;
    }
    resized[array->len-1] = value;
    array->array = resized;
    return 0;
}
// --------------------------------------------------------------------------------

void free_string_array(StringVector *array) {
    if (array != NULL) {
        for (int i = 0; i < array->len; i  ) {
            free(array->array[i]);
        }
    }
    free(array->array);
    // Reset all variables in the struct
    array->array = NULL;
    array->len = 0;
    array->elem = 0;
}
// --------------------------------------------------------------------------------

int replace_string_vector_index(StringVector *array, int index, char string[]) {
    if (array->dat != STRING) {
        printf("Array data type must be a STRING");
        return 0;
    }
    if (index > array->len) {
        printf("Index is greater than array length");
        return 0;
    }
    * (char **) ((char *) array->array   index * array->elem) = string;
    return 1;
}
// --------------------------------------------------------------------------------

main.c

#include <stdio.h>
#include "vector.h"
int main(int argc, const char * argv[]) {
    StringVector arr_test = init_string_vector();
    char one[] = "Hello";
    char two[] = "World";
    char three[] = "Hello";
    char four[] = "Goodbye";
    append_string_vector(&arr_test, one);
    append_string_vector(&arr_test, two);
    append_string_vector(&arr_test, three);
    append_string_vector(&arr_test, four);
    // I can free the array at this point 
    free_string_array(&arr_test)

    StringVector arr_test = init_string_vector();
    append_string_vector(&arr_test, one);
    append_string_vector(&arr_test, two);
    append_string_vector(&arr_test, three);
    append_string_vector(&arr_test, four);
    replace_string_vector_index(&arr_test, 1, one);
    // - Once I envoke replace_string_vector_index, free_string_array
    //   no longer works, and I get an invalid pointer error.
    free_string_array(&arr_test);
}

CodePudding user response:

If I understand the requirements for your replace_string_vector_index function, you should first free the memory of array->array[index], then assign the result of strdup(string) to that element.

No casting needed, no complex pointer arithmetic. Just simply:

free(array->array[index]);
array->array[index] = strdup(string);

What happens now (I think) is that you make array->array[index] point to the array that contains the string (i.e. you forget the strdup step). An array that wasn't allocated by malloc, and which can't be passed to free.

Since you will pass it to free as part of free_string_array you will have undefined behavior.

  • Related