Как минимизировать динамически размещенный строковый массив в C? - PullRequest
0 голосов
/ 28 апреля 2020

Как уменьшить размер динамически размещаемого строкового массива?

int main(){
    char **a = malloc(sizeof(char *)*5);
    for (int i = 0; i < 5; i++){
        a[i] = malloc(sizeof(char) * 10);
    }
    strcpy(a[0], "apple");
    strcpy(a[1], "cat");
    strcpy(a[2], "dog");
    strcpy(a[3], "sun");
    strcpy(a[4], "moon");
    //Now I want to get rid of dog and resize the array to 5
}

Я попытался создать новый динамический c строковый массив следующим образом:

char **temp_storage = malloc(sizeof(char *) * 4);
for (int i = 0; i < 4; i++){
    temp_storage[i] = malloc(sizeof(char) * 10);
}

Затем скопировать все элемент от 'a' до 'temp_storage', кроме 'dog'. После того, как все завершено, я освобождаю весь элемент в 'a'

for (int i = 0; i < 5; i++){
    free(a[i]);
    a[i] = NULL;
}

Затем я возвращаю c a к размеру 4. И копирую весь элемент из 'temp_storage' в 'a'.

Но я продолжаю получать ошибку AddressSanitizer.

1 Ответ

0 голосов
/ 28 апреля 2020

Вам не нужен еще один временный массив, если вы просто хотите удалить одну запись. Все, что вам нужно сделать, это:

  1. Найдите запись, которую вы хотите удалить (возможно, у вас уже есть индекс или вы можете искать контент).
  2. Освободите эту запись .
  3. Переместить все остальные записи назад на одну позицию (или просто переместить последнюю на место той, которая была удалена, если вам не нужен порядок, это намного быстрее).
  4. Перераспределите с realloc(), чтобы изменить размер массива.

Вот пример:

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

#define ENTRY_SIZE 10

int main(void) {
    size_t size = 5;
    char **arr, **tmp;
    size_t i;

    arr = malloc(sizeof(char *) * size);
    if (arr == NULL) {
        perror("malloc failed");
        return 1;
    }

    for (i = 0; i < size; i++) {
        arr[i] = malloc(sizeof(char) * ENTRY_SIZE);
        if (arr[i] == NULL) {
            perror("malloc failed");
            return 1;
        }
    }

    strcpy(arr[0], "apple");
    strcpy(arr[1], "cat");
    strcpy(arr[2], "dog");
    strcpy(arr[3], "sun");
    strcpy(arr[4], "moon");

    // Search for "dog" and remove it if found
    for (i = 0; i < size; i++) {
        if (!strcmp(arr[i], "dog")) {
            free(arr[i]);
            break;
        }
    }

    // If "dog" was found and removed
    if (i < size) {
        // Move all elements after "dog" back one position
        for (; i < size - 1; i++)
            arr[i] = arr[i + 1];

        // Resize the array
        size--;
        tmp = realloc(arr, sizeof(char *) * size);
        if (tmp == NULL) {
            perror("realloc failed");
            return 1;
        }

        arr = tmp;
    }

    // Print everything to show the results
    for (i = 0; i < size; i++)
        printf("%d: %s\n", i, arr[i]);

    // Free everything
    for (i = 0; i < size; i++)
        free(arr[i]);
    free(arr);

    return 0;
}

Результат:

0: apple
1: cat
2: sun
3: moon

Если вас не волнует порядок элементов, вам не нужно перемещать все из них, просто переместите последний вместо удаленного:

    if (i < size) {
        arr[i] = arr[size - 1];

        size--;
        tmp = realloc(arr, sizeof(char *) * size);

        // Same as above...
    }

Результат:

0: apple
1: cat
2: moon
3: sun
...