在动态内存分配方面,我是新手。当我们使用内存释放内存时void free(void *ptr)
,内存被释放但指针的内容没有被删除。这是为什么?最近的 C 编译器有什么不同吗?
5 回答
计算机不会像这样“删除”内存,它们只是停止使用对该内存单元的所有引用,并忘记那里存储了任何有价值的东西。例如:
int* func (void)
{
int x = 5;
return &x;
}
printf("%d", *func()); // undefined behavior
一旦函数完成,程序停止保留存储的内存位置,x
程序的任何其他部分(或者可能是另一个程序)都可以自由使用它。所以上面的代码可以打印 5,或者打印垃圾,甚至可能使程序崩溃:引用不再有效的内存单元的内容是未定义的行为。
动态内存也不例外,并且以相同的方式工作。一旦你调用free()
了 ,那部分内存的内容就可以被任何人使用。
另外,请参阅这个问题。
问题是在内存被释放后访问内存是未定义的行为。不仅内存内容未定义,访问它们可能会导致任何事情。至少有些编译器在构建代码的调试版本时,实际上确实会更改内存的内容以帮助调试,但在发布版本中通常没有必要这样做,因此内存保持原样,但无论如何,这不是您可以安全依赖的东西,不要访问已释放的内存,这是不安全的!
在 C 中,参数是按值传递的。所以free
不能改变ptr
.
它所做的任何更改只会更改free
函数中的值,并且不会影响调用者的变量。
此外,更改它不会有太大帮助。可以有多个指针指向同一块内存,释放时它们都应该被重置。该语言无法跟踪所有这些,因此它让程序员来处理指针。
这是很正常的,因为释放后清除内存位置是一种开销,通常没有必要。如果您有安全问题,可以将 free 调用包装在一个函数中,该函数在释放之前清除该区域。您还会注意到,这需要知道分配大小,这是另一个开销。
实际上,C 编程语言规定,在对象的生命周期之后,即使指向它的任何指针的值都变得不确定,即您甚至不能依赖指针来保留原始值。
这是因为一个好的编译器会尝试积极地将所有变量存储到 CPU 寄存器而不是内存中。所以它看到程序流程调用了一个以参数命名free
的函数ptr
后,它可以将free的寄存器标记ptr
为其他用途,直到它被再次分配,例如ptr = malloc(42);
。
在这两者之间,可以看到更改值,或将其与其原始值进行比较,或其他类似行为。这是一个可能发生的例子。