【问题标题】:why the *P from malloc return an adress?为什么 malloc 中的 *P 返回地址?
【发布时间】:2021-08-29 04:26:02
【问题描述】:

我试图理解为什么 *ptr 返回一个地址,以及当我尝试指向该地址的指针时。 代码不起作用!我想知道那个地址是什么意思,或者它只是堆里的一些垃圾?

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int* ptr = (int*)malloc(sizeof(int));
    printf("%d %d\n", *ptr, ptr);
}

这就是它所显示的: 1315264432 1315247120

【问题讨论】:

  • malloc返回的内存初始值未指定。
  • "*ptr 返回地址" 您是如何确定它是地址的?我看到的只是一个数字,它很可能是一个常规整数而不是指针。
  • 那个数字看起来像一个地址!
  • 是什么让您认为这是一个地址?顺便说一句,使用%d 打印实际地址(例如ptr 的内容)具有未定义的行为。它应该是%p 并且指针转换为(void*)ptr。
  • 请解释一下“不持有值”是什么意思。

标签: c++ c pointers malloc


【解决方案1】:

15.3 32 位内存寻址

  • 386、486 和 Pentium 处理器使用能够寻址 4 GB 内存的 32 位地址空间。
  • 这些处理器仍然能够使用段寄存器,但 Windows 保持它们不变,并使用 32 位平面寻址空间。
  • Windows 使用的 32 位地址不是物理地址。应用程序正在使用虚拟地址。
  • 虚拟地址通过页表转换为物理地址。
  • 物理内存被划分为 4096 字节页面。每个页面地址都以低 12 位为零的地址开始。
  • 每个进程都有自己的目录页,最多可包含 1024 个 32 位条目。存储当前目录页的物理地址 在处理器 CR3 寄存器中,当处理器改变 在进程之间切换控制。
  • 虚拟地址的结构:
  • 高10位:指定目录页1024项之一
  • 目录条目的结构:
  • 高20位表示页表的物理地址。 (底部 12 位为零。)这引用了另一个目录页 最多 1024 个条目。
  • 中间 10 位:引用第二个目录页的 1024 条目之一。该条目引用了一个页框,它是一个 物理地址。
  • 底部12位:指定页框内的物理位置。 d:目录页条目 p:页表条目 o:偏移量虚拟地址: dddd-dddd-ddpp-pppp-pppp-oooo-oooo-oooo CR3的内容 寄存器:rrrr-rrrr-rrrr-rrrr-rrrr (20 bits) 起始物理 进程当前目录页地址: rrrr-rrrr-rrrr-rrrr-rrrr-0000-0000-0000 (32 bits) 第一个处理器 访问(目录页):rrrr-rrrr-rrrr-rrrr-rrrr-dddd-dddd-dd00 63 此位置包含一个 20 位表条目:tttt-tttt-tttt-tttt-tttt 页表的起始物理地址: tttt-tttt-tttt-tttt-tttt-0000-0000-0000 下一个处理器访问 (页面入口):tttt-tttt-tttt-tttt-tttt-pppp-pppp-pp00 这个位置 包含一个 20 位的页框值:ffff-ffff-ffff-ffff-ffff 最后 32位物理地址:ffff-ffff-ffff-ffff-ffff-oooo-oooo-oooo

http://eik.bme.hu/~csurgai/Mswin_en/WinProg.pdf

指针值与虚拟地址相同

【讨论】:

    【解决方案2】:

    %d 是 int* 的错误格式说明符(事实上,int* 根本没有正确的格式说明符)。如果你对错误的类型使用格式说明符,那么程序的行为是不确定的。

    分配的内存未初始化。那里没有任何对象,并且试图像有对象一样访问它会导致未定义的行为。

    未定义的行为从语言的角度解释了您可以(并且需要)了解的有关您观察到的行为的所有信息。

    【讨论】:

    • 关于“未定义的行为解释了您观察到的行为的一切”:未定义的行为不是解释;这只是缺乏 C 标准的控制。说“未定义的行为”解释了一些事情,就像 19 世纪有人说水星的岁差是由他们不知道支配它的物理学这一事实来解释的一样,没有什么意义。这是缺乏知识,而不是知识。
    • it is merely a lack of control by the C standard. 缺乏控制说明没有控制。你观察到一些行为,这是一种行为,它可能是另一种行为,因为当你再次运行程序时它可能是另一种行为 - 就语言而言。
    • @EricPostpischil 关于天文学的一点是,我们都生活在一个共享的宇宙中(除非你问哲学家),所以我们可以通过观察来学习。我看到的水星就是你看到的水星。 C++ 不是这样的。程序以不同的语言实现在不同的机器上运行。您无法通过观察行为来预测未定义的行为,因为当您在另一台机器上运行程序时,无法保证这些观察结果完全适用。
    • @eerorika,我们可以放心地假设 OP 正在使用三分之一的流行 c 或 c++ 编译器进行编译。有了这些信息,我们可以为观察到的行为找到比单独依赖 c 标准更好的解释。
    • @HAL9000 我们可以猜测,但我们不能假设。我们还需要知道目标 CPU 和编译选项……最好是生成的程序集,以确保我们在同一系统上分析同一程序,但答案将是关于程序集。这个问题没有用汇编语言标记,而是用 C++ 标记,所以这就是为什么我的答案的上下文是 C++ 语言(尽管恰好适用于 C)。一旦我们知道了 UB,就没有必要再进一步了。虽然我不会说这完全没有价值……但它确实没有太多好处。
    【解决方案3】:

    试试这个:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        int* ptr = (int*)malloc(sizeof(int));
        *ptr = 42; // Or any integer value you like
        printf("%d %08lx\n", *ptr, ptr);
    }
    

    首先,分配内存,然后将其初始化为所需的任何值。

    【讨论】:

    • %08lx 不是指针的适当转换规范,仅显示更正的代码不是解释,因此不是一个好的答案。要打印指针,请将其转换为 void * 并使用 %p。
    • 正确地说,这个程序还应该使用free(ptr);释放分配的内存
    • @EricPostpischil 这个答案显示了更正的代码,并解释了它为什么存在。我不会争论 printf 说明符;我同意,但根据我的经验,并非所有实现都支持%p。
    猜你喜欢
    • 2012-02-27
    • 2019-10-08
    • 2011-03-07
    • 2017-10-08
    • 1970-01-01
    • 1970-01-01
    • 2011-03-30
    • 2014-09-02
    • 2018-03-09
    相关资源
    最近更新 更多