Освобождение памяти в функции, вызванной в другом цикле - PullRequest
0 голосов
/ 29 марта 2019

пытаюсь освободить память, выделенную в определенной пользователем функции. Я планирую запустить код на встроенном устройстве, STM32F303k8, которое имеет 64 КБ флэш-памяти и 16 КБ SRAM. Я не опробовал код, но боюсь, что он не будет делать то, что должен делать. Он исчерпает память из-за невозможности освободить память, назначенную

Я попытался освободить память в моей специальной программе под названием split. Тем не менее, он даже не компилируется и всегда вылетает в функции free ().


        //This happens somewhere in the main function     
        // str_gprmc is a string thats trying to be split 
        // "$GPRMC,130133.00,A,5741.6029848,N,01158.3855831,E,11.522,170.0,270319"

    for (int k = 0; k < ARRAY_SIZE(str_gprmc); k++)
    {
        char **arr = NULL;

        // Now do the splitting please
        split(str_gprmc[k], ',', &arr);
    }´

        // and the split function
int split(const char *ptr_original_string, char delimiter, char ***ptr_main_array)
{
    // This variable holds the number of times we think we shall iterate through our array once its split
    int count = 1;

    // This variable holds the number of characters we have to iterate through for each split string
    int split_string_len = 1;

    // This variable helps us iterate through collections
    int i = 0;

    // Points to the first character of the whole string
    char *ptrTemp_string_holder;

    // Points to the first character of a split string from the main string 
    char *t;

    ptrTemp_string_holder = ptr_original_string;

    // First we count the number of times the delimiter is occurring in the string we want to split
    // Iterate through the string until we reach either the Courage Return character CR : '\r', the Line Feed LF : '\n' or the NULL : '\0'
    while (*ptrTemp_string_holder != '\0')
    {
        if (*ptrTemp_string_holder == delimiter)
            count++;
        ptrTemp_string_holder++;
    }

    // allocate size in memory for our array. Size of a character is 1 byte * count
    *ptr_main_array = (char**)malloc(sizeof(char*) * count);
    if (*ptr_main_array == NULL) {
        exit(1);
    }

    ptrTemp_string_holder = ptr_original_string;

    // Now start iterating through the whole unsplit string as long as we're not at the end
    while (*ptrTemp_string_holder != '\0')
    {
        // If the pointer points to a delimiter, i.e a comma, that means we are starting to read a new string
        if (*ptrTemp_string_holder == delimiter)
        {
            // Now allocate a memory size for a pointer to a pointer of the new string to be built
            (*ptr_main_array)[i] = (char*)malloc(sizeof(char) * split_string_len);

            // If its null, like some GPRMC or GPHDT results that come back empty, just exit and return back to main
            if ((*ptr_main_array)[i] == NULL) 
            {
                exit(1);
            }

            // Reset the token length and just move the hell on
            split_string_len = 0;
            i++;
        }
        ptrTemp_string_holder++;
        split_string_len++;
    }

    // If we are not at a delimiter however, we just allocate a size based on our token length to a pointer of a pointer
    // Or if you want, call it a pointer to an array
    (*ptr_main_array)[i] = (char*)malloc(sizeof(char) * split_string_len);


    // If for some unknown reason it was null, just stop the crap and return back to main...after all we got a shitty GPS device
    if ((*ptr_main_array)[i] == NULL) exit(1);

    i = 0;
    ptrTemp_string_holder = ptr_original_string;
    t = ((*ptr_main_array)[i]);

    // Now that we got what we need, we rebuild back everything to formulate a pointer to a pointer of character strings
    // I think then the rest is straight forward
    while (*ptrTemp_string_holder != '\0')
    {
        if (*ptrTemp_string_holder != delimiter && *ptrTemp_string_holder != '\0')
        {
            *t = *ptrTemp_string_holder;
            t++;
        }
        else
        {
            *t = '\0';
            i++;
            t = ((*ptr_main_array)[i]);
        }
        ptrTemp_string_holder++;
    }

    // Free the space that was allocated to this pointer
    free(ptr_main_array);

    // We return back the number of times we need to iterate to get the split components of the original string
    return count;
}

Ответы [ 2 ]

1 голос
/ 29 марта 2019

В вашем коде два недопустимых свободных номера

Один здесь:

char *ptrTemp_string_holder;

// Points to the first character of a split string from the main string 
char *t;

   free(ptrTemp_string_holder );

, в то время как ptrTemp_string_holder еще не инициализирован

секунда перед концом:

// Free the space that was allocated to this pointer
free(ptr_main_array);

потому что вы пытаетесь освободить локальную переменную arr в вызывающей функции

Эти два свободных должныбыть удаленным.

Обратите внимание, что определение ptrTemp_string_holder должно быть

const char *ptrTemp_string_holder;

, потому что оно получает значение ptr_original_string


Это происходитиз-за невозможности освободить выделенную память

Вам необходимо освободить *ptr_main_array и запомненный массив, кажется странным делать это в split else split не возвращает полезный результат, который должен быть выполнен в функции вызывающей стороны, например, добавление следующего main :

int main()
{
  char **arr = NULL;
  int count = split("aze,qsd", ',', &arr);

  if (arr != NULL) {
    for (int i = 0; i != count; ++i)
      free(arr[i]);

    free(arr);
  }
}

Компиляция и выполнениепод valgrind :

pi@raspberrypi:/tmp $ gcc -pedantic -Wall -Wextra -g s.c
pi@raspberrypi:/tmp $ valgrind --leak-check=full ./a.out
==10755== Memcheck, a memory error detector
==10755== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==10755== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==10755== Command: ./a.out
==10755== 
==10755== 
==10755== HEAP SUMMARY:
==10755==     in use at exit: 0 bytes in 0 blocks
==10755==   total heap usage: 3 allocs, 3 frees, 16 bytes allocated
==10755== 
==10755== All heap blocks were freed -- no leaks are possible
==10755== 
==10755== For counts of detected and suppressed errors, rerun with: -v
==10755== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)
0 голосов
/ 29 марта 2019

Это совершенно бессмысленно для меня:

    // str_gprmc is a string thats trying to be split 
    // "$GPRMC,130133.00,A,5741.6029848,N,01158.3855831,E,11.522,170.0,270319"

    for (int k = 0; k < ARRAY_SIZE(str_gprmc); k++)
    {
        char **arr = NULL;

        // Now do the splitting please
        split(str_gprmc[k], ',', &arr);
    }´

    // and the split function
int split(const char *ptr_original_string, char delimiter, char ***ptr_main_array)

Если я правильно понял, str_gprmc - это переменная типа char [] с некоторым размером, не указанным здесь.Вы повторяете цикл for(int k=....) по всему массиву.Выражение str_gprmc[k] извлекает k -й символ из массива и передает его в качестве первого параметра в функцию split(), которая ожидает указатель на символ в качестве первого параметра.

Это означает, что числовое представление данных типа char интерпретируется как числовое представление указателя (const char *).В результате вы эффективно запускаете split() для данных со случайными адресами в начальных 120 байтах памяти или около того, продиктованных числовыми значениями (кодами ASCII) символов в вашем сообщении NMEA - но, безусловно, вы делаете , а не обработать само сообщение.

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