不带malloc或calloc的free()函数

rryofs0p  于 2023-01-16  发布在  其他
关注(0)|答案(6)|浏览(146)

快速提问
你能使用free()函数而不需要事先调用malloc吗?
哎。

void someFunc( void )
{
   char str[6] = {"Hello"};

   //some processing here ....

   free(str);
}

我没有得到编译错误,但这是否工作或它是正确的吗?
谢谢你,

eufgjt7s

eufgjt7s1#

这是完全不正确的:
1.不能释放静态数组,如char str[6]

  1. free()应该只在您分配的内存(或NULL)上调用。
0ve6wy6x

0ve6wy6x2#

当您调用malloc时()或任何其他分配函数,内存将被分配到 heap 上。这是唯一可以释放的内存。当你声明一个静态字符串时,就像你在例子中所做的那样,这个字符串在编译时被分配到另一个内存段中。同样的道理也适用于str指针本身,它被分配到 stack 上,因此也不能被释放。

hmae6n7t

hmae6n7t3#

在非malloc'd变量上使用free通常会导致Segfault。例如:

#include <stdlib.h>

int main()
{
  char str[6] = {"Hello"};
  free(str);
}

$gcc测试. c-o测试
$./测试
分段故障

rslzwgfq

rslzwgfq4#

free()使用已分配块前面的数据来管理堆。如果指向的内存不是由堆分配函数(如malloc()或calloc())分配的,则块前面的数据作为堆管理数据将毫无意义。
一些库会检测到无效的堆数据并产生运行时错误,否则行为是未定义的。通常这种错误的后果会一直被忽略,直到你稍后试图分配更多的内存。这会使调试这种错误非常困难。
编译器不会出错,因为它不是语法错误,在编译时也检测不到,编译器不知道库函数的语义,它只知道malloc()返回一个void*,free()接受一个void*;在编译时没有办法知道指针是否指向一个动态分配的块,因为内存是在运行时分配的。同样,指针可以在运行时被修改以指向任何内存类型,或者可以被别名-复制到另一个指针,然后通过第二个指针释放。如果你期望一个错误消息,你期望编译器的很多;然而,一些静态分析工具可能能够警告是否可能发生这样的错误,并且诸如Valgrind的动态分析工具可以在测试期间当错误实际发生时以及如果错误实际发生时检测到错误。

mwecs4sa

mwecs4sa5#

没有

free(3)函数接受一个void *参数,所以你可以传递任何类型的指针给它而不会发生编译时错误,但是如果指针不是malloc(3)最初返回的,也从来没有返回给free(3),那么就会发生不好的事情。

q0qdq0h2

q0qdq0h26#

你不能,但你不需要这样做。当你在一个函数中声明一个变量时,它被称为“自动变量”,因为它会在函数结束时被“自动”删除(释放内存)。
如果你想限制一个 * 自动变量 * 的生存期,你可以使用{}来引入一个作用域,如下所示:

void someFunc( void )
{
    // do some stiff here ...

    { // <- introduce a temporary scope

        char str[6] = {"Hello"}; // this is local to your new scope

        // some processing here ...

    } // <- your array str[] is destroyed here

    // do some more stuff here, str[] has disappeared

}

没有为清楚起见而添加的注解:

void someFunc( void )
{
    // do some stiff here ...

    {

        char str[6] = {"Hello"};

        // some processing here ...

    }

    // do some more stuff here ...

}

在函数中引入一个新的作用域是一个 * 常见的习惯用法 *,用于清除更大范围的无关变量(潜在的bug来源),同时也利用RAII的强大功能。
例如,当锁定一个 mutex 以同步函数代码的一小部分时。

相关问题