关于 C 中的 malloc() 和 free()
我有以下 C 代码:
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int a;
}node;
int main()
{
node * n;
printf("\n%d\n",n->a);
n = (node *) malloc ( sizeof( node ));
printf("\n%d\n",n->a);
n->a = 6;
printf("\n%d\n",n->a);
free(n);
printf("\n%d\n",n->a);
n->a = 4;
printf("\n%d\n",n->a);
return 0;
}
获得的输出是:
1314172
0
6
0
4
我的问题是即使在 free(n) 之后,为什么 n->a = 0 我们如何将它重新分配给任何值,例如 n->a = 4 ?
free不是会让n指向的内存块无效吗??
I have the following C-code:
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int a;
}node;
int main()
{
node * n;
printf("\n%d\n",n->a);
n = (node *) malloc ( sizeof( node ));
printf("\n%d\n",n->a);
n->a = 6;
printf("\n%d\n",n->a);
free(n);
printf("\n%d\n",n->a);
n->a = 4;
printf("\n%d\n",n->a);
return 0;
}
Output obtained is :
1314172
0
6
0
4
My question is even after free(n) , why does n->a = 0
and how can we also reassign it to any value like n->a = 4
?
Doesn't free make the memory block pointed to by n invalid ??
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
调用未定义的行为。
那是因为未定义的行为意味着任何事情都可能发生。你不能依赖这一点。
PS:不要写这样的代码。
编辑:
正如Jonathan注意到你的代码在你
释放之前很久就调用了未定义的行为()
,然后取消引用n
。Invokes Undefined Behaviour.
Thats because Undefined Behaviour means anything can happen. You can't rely on that.
P.S : Don't write such code.
EDIT :
As Jonathan noticed your code invokes Undefined Behavior long before you
free()
and then dereferencen
.重新使用释放的指针类似于复制您租用的汽车的钥匙,归还汽车,然后在将汽车归还到租赁地点后尝试使用该钥匙进入汽车。你也许能够逃脱惩罚,但你不应该这样做,而且很多时候它会给你带来麻烦。
Reusing a freed pointer is similar to making a copy of a key for a car you rented, returning the car, and then trying to use that key to get in the car after you have returned the car to the rental place. You might be able to get away with it, but you shouldn't be doing it and very often it will get you in trouble.
不,free 可能会也可能不会对关联的内存执行任何操作。但引用它是无效的。其他进程/您的进程可能已覆盖内存,或者如果您不幸的话,数据可能与您留下的一样。
您需要确保不引用已释放的内存。
No, free may or may not do anything to the associated memory. Referencing it is invalid though. Other processes/your process may have overwritten the memory, or if you're unlucky, the data might be just as you'd left it.
It's up to you to make sure you don't reference free'd memory.
当您取消引用指向未分配内存的指针时,行为是未定义的。这意味着它可以做任何事情。它可能会触发错误,或者可能会执行其他操作。
在大多数情况下,如果您
释放
一些内存,该内存不会立即重新使用,也不会立即被操作系统回收。这意味着您的应用程序仍然可以访问该内存,并且仍然包含其以前的值。您通常可以毫无错误地读取或写入它,但您不能依赖此行为。如果您在许多不同的环境中运行此代码,您会发现在某些环境中它总是有效,在某些环境中它总是触发错误,但在许多其他环境中它“大部分时间”都有效。这使得 C 调试起来相当困难! :)
When you dereference a pointer to unallocated memory, the behaviour is undefined. This means that it could do anything. It might trigger an error, or it might do something else.
In most cases, if you
free
some memory, that memory is not immediately re-used, and is not immediately reclaimed by the Operating System. This means that the memory is still accessible to your application and will still contain its previous values. You can often read or write to it without errors, but you must not rely on this behaviour.If you ran this code in a number of different environments, you would find that in some environments it always works, in some it always triggers an error, but that in many others it works ‘most of the time’. This makes C quite difficult to debug! :)
内存块被释放。这并不意味着您不能写入它;而是意味着您不能向它写入数据。这意味着您不能写入它。机器不会阻止你这样做(通常,有一些工具,例如电围栏,可以阻止它),
正如你将来会发现的;你最终会经常不小心这样做;通常会发生坏事
the memory block is released. That doesnt mean that you cannot write to it; it means that you must not write to it. The machine will not stop you doing it (usually, there are some tools like electric fence that will prevent it)
As you will find in the future ; you will end up doing this accidentally a lot; and usually Bad Things (tm) will happen
在大多数针对具有 MMU 的硬件(例如 x86)的操作系统上,实际获得内存读取错误的唯一方法是应用程序地址未映射。由于 MMU 没有一个条目告诉它在物理内存中哪里可以找到与应用程序请求的逻辑地址相关的数据,因此它会导致中断,操作系统接管并对此进行处理。
但大多数操作系统不会为应用程序做太多管理内存的工作,只是为其提供所需大小的连续内存块。操作系统也不允许应用程序在 MMU 中乱搞,因为大多数 MMU 不够智能,无法让应用程序安全地执行操作而不会对其他程序产生负面影响(无论是意外还是恶意)。
因此,当您
malloc()
某项内容时,如果您的应用程序还没有地方可以将其放入其现有地址空间中,它会向操作系统请求更多信息,但当您稍后free 时()
它,除非它恰好位于应用程序地址空间的最末端,否则您无法将其返回给操作系统以使该内存区域在您尝试读取它时导致错误。有一些方法可以实现这一点,例如使用
mmap()
,但这并不是使用该函数的正确原因。On most operating systems targeted at hardware with an MMU (such as x86), the only way to actually get an error for a memory read is if the application address is unmapped. Since the MMU doesn't have an entry that tells it where to find in physical memory the data associated with the logical address the application asked for, it causes an interrupt and the operating system takes over, to do something about it.
But most operating systems don't do much to manage memory on behalf of the application, except to give it a contiguous chunk of memory of the desired size. The operating system doesn't allow the applications to muck about in the MMU, either, since most MMU's aren't quite smart enough to let applications do things safely without affecting other programs negatively (either by accident or malice).
So when you
malloc()
something, if your app doesn't already have a place to put that in its existing address space, it asks the operating system for more, but when you laterfree()
it, unless that happens to be at the very end of the address space for your app, you can't give it back to the operating system to make that memory area cause an error when you try to read it.There are some ways to get that, for instance, with
mmap()
, but that's not really the right reason to use that function.大多数操作系统都会分配一定的最小空间,该最小空间将等于或大于您请求的空间。
一旦您调用 free,该空间将不会返回到操作系统,而是保留给您以供将来重用。因此,您可以摆脱上面所写的内容。
但严格来说,这被归类为“未定义”行为。但大多数时候你都可以逃脱惩罚。只是不要养成习惯;)
Most of the OS will allocate a certain minimum space that will be equal to or greater than the space you requested.
Once you call free, this space will not go back to the OS, instead kept with you for future reuse. Hence, you can get away with something like what you have written above.
But on a strict note, this is categorized as "Undefined" behavior. But you can get away with it most of the times. Just don't make a habit off it ;)