释放在另一个循环中调用的函数中的alloated内存

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了释放在另一个循环中调用的函数中的alloated内存相关的知识,希望对你有一定的参考价值。

我试图释放用户定义函数中分配的内存。我计划在嵌入式设备上运行代码,STM32F303k8具有64Kb闪存和16KB 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;
}
答案

您的代码中有两个无效的免费

一个在这里:

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和记忆的数组,看起来很奇怪,在拆分其他拆分不返回可用的结果,必须在调用函数中完成,例如添加以下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)
另一答案

这对我来说完全没有意义:

    // 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_gprmcchar []类型的变量,有一些大小,这里没有说明。您在数组中使用for(int k=....)循环进行迭代。表达式str_gprmc[k]从数组中提取k-th字符,并将其作为第一个参数传递给split()函数,该函数需要将char指针作为第一个参数。

这意味着char类型数据的数字表示被解释为指针(const char *)的数字表示。因此,您可以在初始120字节内存中的随机地址上有效地运行split(),这取决于NMEA消息中字符的数值(ASCII代码) - 但您肯定不会处理消息本身。

以上是关于释放在另一个循环中调用的函数中的alloated内存的主要内容,如果未能解决你的问题,请参考以下文章

在另一个并行循环中调用函数时,函数中的“pragma omp parallel for”无效

Alamofire 呼叫在循环内不起作用

等到 for 循环内的所有函数调用结束其执行 - Javascript

C - 如何释放在其节点中具有链表的链表?

如何从Python中的另一个函数调用函数内的函数? [重复]

jsp页面函数中如何获取sevlet传过来的List