在这种情况下,free如何工作? 那是为什么?

问题描述

让我们说一个函数为一个字符串分配内存并返回它。 调用该函数的变量(其返回字符串存储在该变量中)是指向已动态分配的char的指针数组。 我的疑问是,当我释放变量的内存时,它是要释放变量内存还是函数内字符串内存,还是函数内分配的内存与变量1成为一体?

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
}

,

我在此处发布了完整的示例:https://stackoverflow.com/a/63756135/11234199

我的疑问是,当我释放变量的内存时,它是要同时释放变量内存和函数内字符串内存,还是函数内分配的内存变成变量1?

请运行此处提供的程序,因为它将执行以下操作:创建并销毁指向char的指针块,就像argc/argv块一样,每个main()函数都可以免费获得C

我在此处发布的程序显示了如何动态构建一个字符串块以及如何使用它,以块为单位分配内存,并在末尾修剪它以精确使用大小

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

您的功能

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

仅返回一个指向char的指针。你可以写

char one_char = *function();

这就是事实。实际上,C中没有字符串。如果functionchar*,那么*functionchar

在该函数内部,您可以malloc()一个块并在函数中返回地址,在一个1MB块的开始处使用方便的'\0',就可以了。

要使此功能正常运行,我们需要仔细构建它

事实是,总的来说我们想要这样的东西

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

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

那是为什么?

好吧,由于要方便地遍历下摆,因此我们需要一个指向char的指针数组,就像argv[0]argv[1] ...这样的普通数组一样。

但这对argc至关重要。如

char** argv;

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

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

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

这是它的工作方式。

下面的代码构建了一个示例的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;
};
,

调用该函数的变量,其返回值存储在该变量中 字符串是指向已经动态分配的char的指针的数组。

这意味着从函数返回的指针只能分配给动态分配的数组的一个元素。

例如

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

s[0] = function();

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

free( s[0] );

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

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

free( s );

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...