关于malloc()和free()在C中

时间:2022-02-17 21:00:33

I have the following C-code:

我有以下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

1314172

0

0

6

6

0

0

4

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 ?

我的问题是,即使在*(n)之后,为什么n->a = 0,我们又如何将它重新赋值为n->a = 4 ?

Doesn't free make the memory block pointed to by n invalid ??

难道free不使指向n的内存块无效吗?

7 个解决方案

#1


15  

free(n);
n->a = 4; // is not guaranteed to work, might crash on some implementations

Invokes Undefined Behaviour.

调用未定义的行为。

why does n->a = 0 and how can we also reassign it to any value like n->a = 4 ?

为什么n->a = 0,我们如何将它重新赋值为n->a = 4 ?

Thats because Undefined Behaviour means anything can happen. You can't rely on that.

那是因为没有定义的行为意味着任何事情都可能发生。你不能指望它。

P.S : Don't write such code.

P。S:不要写这样的代码。

EDIT :

编辑:

As Jonathan noticed your code invokes Undefined Behavior long before you free() and then dereference n.

就像乔纳森注意到你的代码在你*()之前很久就调用了未定义的行为,然后是dereference n。

node * n; //n is not initialized
printf("\n%d\n",n->a);  //dereferencing a wild pointer invokes UB.

#2


13  

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.

重复使用一个释放的指针,就像复制一辆你租的车的钥匙,把车还回去,然后在你把车还到租车的地方后,再试着用那把钥匙上车。你可能可以侥幸逃脱,但你不应该这么做,而且这经常会给你带来麻烦。

#3


4  

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.

不,free可能也可能不会对关联的内存做任何事情。但是引用它是无效的。其他进程/进程可能覆盖了内存,或者如果您不走运,数据可能与您留下的数据一样。

It's up to you to make sure you don't reference free'd memory.

由您来确保您没有引用*内存。

#4


4  

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! :)

如果您在许多不同的环境中运行此代码,您会发现在某些环境中它总是有效的,在某些环境中它总是触发一个错误,但在许多其他环境中,它“大多数时候”都是有效的。这使得C很难调试!:)

#5


1  

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

正如你将来会发现的;你会经常不小心这样做;通常坏事会发生

#6


0  

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.

在大多数针对具有MMU(如x86)的硬件的操作系统中,真正获得内存读取错误的唯一方法是应用程序地址没有映射。由于MMU没有一个条目告诉它如何在物理内存中找到与应用程序请求的逻辑地址相关联的数据,因此它会导致一个中断,操作系统会接管它,从而对其进行处理。

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).

但是,大多数操作系统并不会为应用程序管理内存,除了为其提供所需大小的连续内存块。操作系统也不允许应用程序在MMU中混日子,因为大多数MMU的应用程序都不够智能,不能让应用程序在不影响其他程序的情况下安全地执行任务(无论是意外还是恶意)。

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 later free() 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.

所以当你malloc(),如果您的应用程序已经没有地方放,在其现有的地址空间,它要求更多的操作系统,但是当你以后免费(),除非是在最后的地址空间为您的应用程序,你不能把它还给操作系统内存区域导致一个错误当你试图阅读它。

There are some ways to get that, for instance, with mmap(), but that's not really the right reason to use that function.

有一些方法可以达到这个目的,例如使用mmap(),但是这并不是使用这个函数的正确理由。

#7


0  

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.

大多数操作系统将分配一定的最小空间,该空间将等于或大于您所请求的空间。一旦您调用free,这个空间将不会返回到OS,而是保留在您的空间中以便将来重用。因此,你可以从上面写的东西中侥幸逃脱。

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 ;)

但严格地说,这被归类为“未定义的”行为。但大多数时候你都能侥幸逃脱。不要改掉这个习惯;

#1


15  

free(n);
n->a = 4; // is not guaranteed to work, might crash on some implementations

Invokes Undefined Behaviour.

调用未定义的行为。

why does n->a = 0 and how can we also reassign it to any value like n->a = 4 ?

为什么n->a = 0,我们如何将它重新赋值为n->a = 4 ?

Thats because Undefined Behaviour means anything can happen. You can't rely on that.

那是因为没有定义的行为意味着任何事情都可能发生。你不能指望它。

P.S : Don't write such code.

P。S:不要写这样的代码。

EDIT :

编辑:

As Jonathan noticed your code invokes Undefined Behavior long before you free() and then dereference n.

就像乔纳森注意到你的代码在你*()之前很久就调用了未定义的行为,然后是dereference n。

node * n; //n is not initialized
printf("\n%d\n",n->a);  //dereferencing a wild pointer invokes UB.

#2


13  

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.

重复使用一个释放的指针,就像复制一辆你租的车的钥匙,把车还回去,然后在你把车还到租车的地方后,再试着用那把钥匙上车。你可能可以侥幸逃脱,但你不应该这么做,而且这经常会给你带来麻烦。

#3


4  

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.

不,free可能也可能不会对关联的内存做任何事情。但是引用它是无效的。其他进程/进程可能覆盖了内存,或者如果您不走运,数据可能与您留下的数据一样。

It's up to you to make sure you don't reference free'd memory.

由您来确保您没有引用*内存。

#4


4  

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! :)

如果您在许多不同的环境中运行此代码,您会发现在某些环境中它总是有效的,在某些环境中它总是触发一个错误,但在许多其他环境中,它“大多数时候”都是有效的。这使得C很难调试!:)

#5


1  

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

正如你将来会发现的;你会经常不小心这样做;通常坏事会发生

#6


0  

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.

在大多数针对具有MMU(如x86)的硬件的操作系统中,真正获得内存读取错误的唯一方法是应用程序地址没有映射。由于MMU没有一个条目告诉它如何在物理内存中找到与应用程序请求的逻辑地址相关联的数据,因此它会导致一个中断,操作系统会接管它,从而对其进行处理。

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).

但是,大多数操作系统并不会为应用程序管理内存,除了为其提供所需大小的连续内存块。操作系统也不允许应用程序在MMU中混日子,因为大多数MMU的应用程序都不够智能,不能让应用程序在不影响其他程序的情况下安全地执行任务(无论是意外还是恶意)。

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 later free() 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.

所以当你malloc(),如果您的应用程序已经没有地方放,在其现有的地址空间,它要求更多的操作系统,但是当你以后免费(),除非是在最后的地址空间为您的应用程序,你不能把它还给操作系统内存区域导致一个错误当你试图阅读它。

There are some ways to get that, for instance, with mmap(), but that's not really the right reason to use that function.

有一些方法可以达到这个目的,例如使用mmap(),但是这并不是使用这个函数的正确理由。

#7


0  

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.

大多数操作系统将分配一定的最小空间,该空间将等于或大于您所请求的空间。一旦您调用free,这个空间将不会返回到OS,而是保留在您的空间中以便将来重用。因此,你可以从上面写的东西中侥幸逃脱。

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 ;)

但严格地说,这被归类为“未定义的”行为。但大多数时候你都能侥幸逃脱。不要改掉这个习惯;