释放指向“双”的指针。值

时间:2014-05-05 18:12:17

标签: c pointers memory-management double free

我能找到的所有东西都指的是释放' double'指针指的是释放指针的指针,这不是我所说的。我已经想出了如何做到这一点。

它可能根本不是一件大事,但我注意到当我free() intcharfloat指针时,该值被删除或者用垃圾值替换,但是当我free() double指针时,值保持不变。

这是我测试过的代码:

int main()
{
  int *p_a = malloc(sizeof(int));
  *p_a = 1;

  char *p_b = malloc(sizeof(char));
  *p_b = 'b';

  float *p_c = malloc(sizeof(float));
  *p_c = 3.565;

  double *p_d = malloc(sizeof(double));
  *p_d = 7.77;

  printf("Before 'free()':\n");
  printf("A: %p\t%d\n", p_a, *p_a);
  printf("B: %p\t%c\n", p_b, *p_b);
  printf("C: %p\t%g\n", p_c, *p_c);
  printf("D: %p\t%g\n", p_d, *p_d);

  free(p_a);
  free(p_b);
  free(p_c);
  free(p_d);

  printf("\nAfter 'free()':\n");
  printf("A: %p\t%d\n", p_a, *p_a);
  printf("B: %p\t%c\n", p_b, *p_b);
  printf("C: %p\t%g\n", p_c, *p_c);
  printf("D: %p\t%g\n", p_d, *p_d);

  return 0;
}

这产生了以下输出:

Before 'free()':
A: 0x8f2e008    1
B: 0x8f2e018    b
C: 0x8f2e028    3.565
D: 0x8f2e038    7.77

After 'free()':
A: 0x8f2e008    0
B: 0x8f2e018
C: 0x8f2e028    1.46175e-33
D: 0x8f2e038    7.77

这是正常的吗?我对malloc()free()如何工作的理解是,当你malloc()指针时,你会为指针指向一些内存字节。这是放在heap上,无法访问它,并且在heap或计算机上触发内存清理之前它不会离开free(),这不受用户控制。因此,当您free()指针时,您基本上摆脱了指针与其指向的地址之间的关联,允许稍后使用该内存。

鉴于这一切,为什么double指针仍然指向相同的值?

现在我考虑一下,为什么指针在free()之后根本就有一个地址?

由于我是C的初学者,所以非常感谢任何智慧和知识。感谢您的时间。

编辑:经过进一步的测试和干预后,我发现如果你输入一个数字超过6位的数字并在最后一个数字(例如777.7777)上为{{1}在它double之后,它就会失去它的四舍五入。

举例说明:

free()

这支持@ rodrigo的假设(在评论中),因为Before 'free()': D: 0x8f2e038 777.778 After 'free()': D: 0x8f2e038 777.777 是8个字节 - 而不是doubleintchar 4个字节 - float仅修改前4个字节,因此不会丢失所有数据。

感谢大家的帮助!

2 个答案:

答案 0 :(得分:7)

  

我对malloc()和free()如何工作的理解是,当你指向malloc()时,你需要为指针指向一些内存字节。

你没有指向一个指针。你malloc一块内存。 malloc返回的值是指向该内存的指针。所以,让我们改一下。

  

我对malloc()和free()如何工作的理解是当你使用malloc()一块内存时,你会留出一些字节的内存;返回的指针指向该内存块的开头。

正确。

  

这个[内存块]放在堆上

正确;将堆视为长期随机存取存储。

  

无法访问的地方

这是错误的或荒谬的。哪些什么无法访问,以及由谁?

  

它[内存块]在释放之前不会脱离堆()d

malloc分配的内存块保留供您的程序使用,直到调用free为止。要释放块,可以调用free并传递最初从malloc返回的指针,是的。

  

或计算机上触发内存清理,不受用户控制

这又是不连贯的。现代操作系统使用虚拟内存。当一个进程被销毁时,整个虚拟地址空间就会消失。

  

当你释放()指针时,你基本上摆脱了指针和它指向的地址之间的关联,允许稍后使用该内存。

不不不不不。这是你误解的关键。

通过将malloc最初返回的指针传递给free来释放内存块。这释放了内存块,然后如果进程中的其他代码要求内存,则允许malloc再次将其移出。

但是free不会改变指针指向的地址!指针继续指向一个地址;该地址现在无效!取消引用指向无效内存的指针称为"未定义的行为"在C中,字面上任何都可能发生。你的程序会崩溃。您可以获得以前的价值。您的密码可以通过电子邮件发送给北极秘密巢穴中的黑客。 任何都可能发生,所以不要那样做

(巧合的是,我今天早些时候写了一篇关于这个主题的博客文章,该文章将于周三发布,所以请关注我的博客了解详情。)

  

鉴于这一切,为什么双指针仍然指向相同的值?

未定义的行为意味着任何事情都可能发生。仍然指向相同值的指针正在发生,发生的事情是发生的任何事情的一个子集。

  

现在我想一想,为什么指针在free()之后根本就有一个地址?

指针存储在变量中。 您没有更改变量的值。变量会保留其值,直到您更改它们为止。

  

我在哪里可以阅读更多内容?

您可能会对这个高度相关的问题感兴趣。

Can a local variable's memory be accessed outside its scope?

该问题与您的问题相同,除非在给定的问题中指针指向堆栈,而不是指向堆。但逻辑是相同的:取消引用指向弹出堆栈帧的指针是未定义的行为,就像取消引用指向空闲块的指针是未定义的行为一样。任何事情都可能发生。

答案 1 :(得分:2)

基本上,一旦释放指针,就不应再使用它指向的数据了。

malloc 为您分配一些您负责编写和读取的内存。那块“属于”你,但它只是一个租金!

释放该块之后,它又回到了系统中。如上所述,使用该数据是未定义的行为:预期结果(好像没有免费),错误的结果,崩溃......

根据双重问题,尝试将释放(D转换为A)反转,看看会发生什么......(无论如何, malloc 不认识你打算在那个空间放一个 double