утечка памяти при конкатенации строк в массив - PullRequest
0 голосов
/ 29 января 2019

У меня есть одна функция alloc_str, которая принимает указатель на строку и массив указателей.Он динамически увеличивает размер массива на единицу и добавляет строку в массив.Я запустил отладчик GDB и выделил утечку памяти и ошибку const ниже.

Мой ожидаемый ввод / вывод:

array = alloc_str(array, "test_1");
array = alloc_str(array, "test_2");
array = alloc_str(array, "test_3");
--> ["test_1", "test_2", "test_3"]

Моя функция alloc_str:

char **alloc_str(char **existing, const char *add)
{
    int length = 0; //find the length of the array
    for (; existing[length]; length++)
    {
    }
    //allocate memory to copy array array
    char **existing_c = (char **)calloc(length + 2, sizeof(char *));

    for (int i = 0; i < length; i++) //copy original array into new array
    {
        existing_c[i] = existing[i];
    }

    //possible memory leak error
    strncat(existing_c, add, sizeof(existing_c) - strlen(existing_c) - 1);
    existing_c[sizeof(existing_c)-1] = '\0';
    //possible memory leak error
    strncpy(existing, existing_c, sizeof(existing - 1));
    s_copy[sizeof(destsize)-1] = '\0'; //error here

    free(existing);
    return existing_c;
}

void free_array(char **strings) //free's data in array, should be fine
{
    int length = 0;
    for (; strings[length]; length++)
    {
    }
    strings = (char **)calloc(length + 2, sizeof(char *));
}

Моя основная функция:

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

int main(){ //should be fine
    char **array = NULL;
    char **test;

    array = (char **)calloc(1, sizeof(char *)); //array has no strings yet

    array = alloc_str(array, "test_1");
    array = alloc_str(array, "test_2");
    array = alloc_str(array, "test_3");


    for (test = array; *test; test++)
    {
        printf("%s\n", *test);
    }

    free_array(array);
}

Моя ошибка:

Subscript of pointer to function type 'void (const void *, void *, size_t)' (aka 'void (const void *, void *, unsigned long)')

Ответы [ 2 ]

0 голосов
/ 29 января 2019

Существует несколько проблем:

char **alloc_str(char **existing, const char *add)
{
    int length = 0; //find the length of the array
    for (; existing[length]; length++)
    {
    }
    //allocate memory to copy array array
    char **existing_c = (char **)calloc(length + 2, sizeof(char *));

    for (int i = 0; i < length; i++) //copy original array into new array
    {
        existing_c[i] = existing[i];
    }

    ////////////////////////////////////
    //possible memory leak error
    strncat(existing_c, add, sizeof(existing_c) - strlen(existing_c) - 1);
    existing_c[sizeof(existing_c)-1] = '\0';
    //possible memory leak error
    strncpy(existing, existing_c, sizeof(existing - 1));
    s_copy[sizeof(destsize)-1] = '\0'; //error here
    ////////////////////////////////////

    free(existing);
    return existing_c;
}

Часть, отмеченная ////////////////////////////////////, не имеет особого смысла.

Вы выделили массив указателей.Не относитесь к этому как к строке.Это не строка.Вместо этого просто назначьте новый указатель на конец массива и снова добавьте терминатор.

    existing_c[length] = add;
    existing_c[length+1] = NULL;

С этим терминатором вы можете использовать обычный malloc вместо calloc, поскольку вы все равно назначаете все элементы массива.

Помимо проблемы с выделением, у вас есть еще одна утечка памяти:

void free_array(char **strings) //free's data in array, should be fine
{
    int length = 0;
    for (; strings[length]; length++)
    {
    }
    strings = (char **)calloc(length + 2, sizeof(char *));
}

Вы передаете указатель на массив указателей.Этот массив занимает некоторую память, которую вы выделили с calloc ранее.Затем вы выделяете немного больше памяти и присваиваете адрес локальной переменной string.

Это имеет две проблемы:

  1. Память, которая была выделена ранее, не освобождается.
  2. Память, которую вы выделяете в этой функции, недоступна за пределами этой функции.

В конце ваша функция free_array ничего не освобождает, но потребляет больше памяти.

Другая проблема может присутствовать со строками, которые вы храните в этом массиве.В вашем примере вы используете строковые литералы.Это статические объекты, и их не нужно освобождать.

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

0 голосов
/ 29 января 2019

strncat() работает с буфером памяти, содержащим строку, определенную NUL (он же "C"):

char buf[10] = {'a', 'b', 'c', '\0'};
strncat(buf, "def", sizeof(buf) - strlen(buf) - 1);
assert(strcmp(buf, "abcdef") == 0);  // buf now equals to "abcdef"

(Ну, использование strlen() вроде как убило преимущество strncat() по сравнению с добрым старым strcat(), но это другая история ...)

Так что это сильно отличается от того, что вы хотите сделать в своемупражнение.Вам на самом деле не нужно ни strncat(), ни strncpy().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...