Как правильно заменить день в динамически выделенном массиве C

Я работаю над базовой структурой для динамического выделения массива с помощью языка C. Я создал функцию для создания массива строк под названием init_string_vector. Данные могут быть добавлены в массив с помощью функции append_string_vector, а данные могут быть удалены из кучи с помощью функции free_string_array. В настоящее время я работаю над функцией под названием replace_string_vector_index, которая позволяет пользователю передавать индекс массива в функцию, а также указатель на массив строк. Если массив типизирован как массив STRING и индекс не выходит за пределы, функция должна заменить существующие данные строкой, которую пользователь передает функции.

Функция replace_string_vector_index работает правильно и заменяет строку в индексе другой строкой, которую пользователь передал функции. Однако функция free_string_array больше не работает после того, как я использовал функцию replace_string_vector_index для работы с массивом. Это заставляет меня думать, что процесс внутри функции вызывает проблему, но я не могу понять, как это сделать. Пример показан ниже. Когда функция free_string_array дает сбой, я получаю следующую ошибку: free(): invalid pointer.

вектор.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[]);
// --------------------------------------------------------------------------------

вектор.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);
}

🤔 А знаете ли вы, что...
C имеет богатую стандартную библиотеку, включающую функции для работы с файлами, строками, памятью и другими задачами.


37
1

Ответ:

Решено

Если я понимаю требования к вашей функции replace_string_vector_index, вы должны сначала освободить память array->array[index], а затем присвоить результат strdup(string) этому элементу.

Нет необходимости в приведении, нет сложной арифметики указателей. Просто:

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

Теперь (я думаю) происходит то, что вы указываете array->array[index] на множество, который содержит строку (т. е. вы забываете шаг strdup). Массив, который не был выделен malloc и который не может быть передан free.

Поскольку вы передадите его free как часть free_string_array, у вас будет неопределенное поведение.