free() 在这种情况下如何工作?

How does free() works in this case?

假设一个函数为字符串分配内存并 return存储它。 调用该函数的变量,其中存储了它的 return 字符串,是指向已经动态分配的 char 的指针数组。 我的疑问是,当我释放变量的内存时,它是否会同时释放变量内存和函数内字符串内存,或者函数内分配的内存是否与变量一成为一体?

char *function() {
    //allocates memory for <string>
    return <string>
}

int main() {
    //<variable> declaration
    //<variable> allocation
    <variable> = function();
    free(<variable>);
    return 0;
}
   

出于实际原因,我省略了//函数声明部分

感谢您的关注与帮助!

有两种可能的情况:

  1. 函数使用动态内存分配分配内存,100% 正确
char *func(void)
{
    char *x = malloc(100);
    /* some code */
    return x;
}

void foo(void)
{
    char *y = func();
    free(y);
}

  1. 其他分配内存的方法。当您尝试 free 它们时,它们都会调用未定义的行为。此外,当指向自动变量的指针在其定义的范围之外使用时,还有另一个 UB。
char w[100];

char *func(void)
{
    char x[100];
    /* some code */
    return x;
}

char *func1(void)
{
    static char x[100];
    /* some code */
    return x;
}

char *func2(void)
{
    return w;
}


void foo(void)
{
    char *y = func();
    y[0] = 'a';       //UB
    free(y);          //UB

    y = func1();
    y[0] = 'a';
    free(y);        //UB

    y = func2();
    y[0] = 'a';
    free(y);        //UB
}

The variable, that calls that function, in which is stored its return string is an array of pointers to char already dynamically allocated.

表示函数返回的指针只能赋值给动态分配数组的一个元素。

例如

char **s = malloc( 10 * sizeof( char * ) );

s[0] = function();

因此您可以释放函数中分配的内存以及分配给元素 s[0] 的指针,例如

free( s[0] );

之后,您可以使用其他动态分配的字符串的地址重新分配指针。

但是这个调用不会释放为整个指针数组分配的内存s。要释放它,你必须写

free( s );

我在这里发布了一个完整的例子:

My doubt is, when I'll free the variable's memory, is it going to free both the variable memory and the in-function string memory or does the in-function allocated memory became one with the variable one?

请运行那里提供的程序,因为它会做这个:创建和销毁一个指向char的指针块,就像argc/argv块每个main() 函数在 C

中免费获取

我在那里发布的程序展示了如何动态构建一个字符串块以及如何使用它,以块为单位分配内存并在最后修剪它以获得确切的使用大小

但这里我将提供一个 20 行的示例,以相同的方式构建指针数组

你的函数

char *function() 
{
   //allocates memory for <string>
   return <string>
}

return只是一个指向 char 的指针。你可以写

char one_char = *function();

事实就是如此。 C实际上没有字符串。如果 functionchar* 那么 *function 就是 char.

在函数内部你可以 malloc() 一个块和 return 函数中的地址,在 1MB 块的开头使用方便的 '[=25=]' 就可以了。

为了让这个东西起作用,我们需要仔细构建它

事实是,通常我们想要的是

typedef struct
{
    int     argc;
    char** argv;
}   stringArray;

就像熟悉的 main() 原型一样。

这是为什么?

好吧,我们想要一个指向 char 的指针数组,因为像 argv[0]argv[1]...[=45 这样的普通数组一样可以方便地遍历 hem =]

但是argc是必不可少的东西。如

char** argv;

我们无从知晓*argv指向的区域中有多少个指针。 我们只知道

  • argvchar**
  • *argvchar*,一个指向char
  • 的指针
  • **argv 是一个 char,单个字符

我们必须按照我们需要的方式构建块,或者只是希望有人在我们使用之前轻轻地这样做。 如果*argv处有一百个字符串,那是因为有人分配了100个指向char的指针,并将地址放在argv中。然后使用一百个指针分配了 100 个不知道大小的字符串。然后确保字符串都是 null-terminated.

这就是它的工作原理。

下面的代码构建了一个示例 10 字符串块,为了好玩,字符串按照我们在此处看到的方式构建:

we got 10 strings:

'0' [len: 1]
'01' [len: 2]
'012' [len: 3]
'0123' [len: 4]
'01234' [len: 5]
'012345' [len: 6]
'0123456' [len: 7]
'01234567' [len: 8]
'012345678' [len: 9]
'0123456789' [len: 10]

End of list

然后在 main() 中,整个块从内到外被破坏。

这是代码

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

typedef struct
{
    int     argc;
    char** argv;
}   stringArray;

stringArray* get_the_block(void);

int main(void)
{
    stringArray* string_array = get_the_block();
    printf("we got %d strings:\n\n", string_array->argc);

    char** array = string_array->argv; // just for readability

    for (int i = 0; i < string_array->argc; i += 1)
        printf("'%s' [len: %zd]\n", array[i], strlen(array[i]));

    printf("\nEnd of list\n");

    // free() the block
    // since string_array is also a pointer we have 3 levels

    // 1st free() the strings
    for (int i = 0; i < string_array->argc; i += 1)
        free(array[i]);

    // 2nd free() the block of pointers
    free(string_array->argv);

    // 3rd free() the control structure
    free(string_array);
    return 0;
};  // main()

stringArray* get_the_block(void)
{
    // this is an useless example
    // it builds a 10-string block and
    // return it
    const char* text = { "0123456789" };

    // building the block of strings
    // "0", "01", "012" ... "123456789"
    char** string = (char**)malloc(10 * sizeof(char*));
    for (int i = 0; i < 10; i += 1)
    {
        string[i] = malloc((1 + 1 + i) * sizeof(char));
        memcpy(string[i], text, 1 + i);
        string[i][i + 1] = 0; // strings are null-terminated
    };

    // builds the struct to return, just like the system
    // does for main()
    stringArray* block = (stringArray*)malloc(sizeof(stringArray));
    block->argc = 10;
    block->argv = string;

    return block;
};