【问题标题】:Why I cant print value of the address 0?为什么我不能打印地址 0 的值?
【发布时间】:2012-02-25 03:11:14
【问题描述】:

我正在玩指针以了解它们,所以我想知道为什么我不能打印地址 0(零)的 和其他.

#include <stdio.h>
int main()
{
    int *i = 0;
    int *e = (int*)0x100;

    while (i <= e)
    {
        printf("%d\n", *i);
        i++;
    }

    return 0;
}

这个例子崩溃了。

【问题讨论】:

  • 我建议你尝试用事物的地址初始化指针(例如int *x=&amp;y),而不是给它们分配整数值。将整数转换为指针并不是使用指针的方式。
  • 尝试取消引用 0 地址在任何情况下都是无效的,甚至没有触及访问可能未分配给您的进程的随机内存地址的问题。
  • 您可能想知道这是针对哪个系统的。您的代码在某些系统中非常好,但在其他系统(Windows 等)中不起作用。
  • @ugoren 这取决于代码用于哪个系统。这段代码在某些系统上可能非常好。
  • @Lundin “一元 * 运算符取消引用指针的无效值包括空指针”(6.5.3.2 中的脚注 102)。该代码会引发未定义的行为,在任何系统上都不好。

标签: c pointers


【解决方案1】:

您只能取消引用有效指针。这些是从例如返回的指针。 malloc(),或通过获取某物的地址生成的指针。取消引用无效指针是未定义的行为。

在您的情况下,您的操作系统可能不允许您读取未映射到进程的内存,这就是为什么它会在您尝试时终止进程。

【讨论】:

  • 严格来说并非如此。您可以访问任何您想要的内存(该系统允许您访问)。您应该能够访问(例如)函数二进制代码等。
  • @Vyktor:您只能访问为您的进程分配的内存。函数二进制代码已分配,要访问它,您需要获取此函数的地址,如unwind 所说。
  • 嗯....不,@Vyktor,这根本不是真的。某些地址是禁区。当然,这完全取决于操作系统和体系结构,但在类似 UNIX 的系统上,这将因Bus Error 消息而死。
  • @AndyT 对不起,我误读了展开答案,尽管他写道,您只能访问通过malloc() 分配的内存,当然您只能访问进程的内存(但我认为更笼统地说,它是您的操作系统允许您使用的任何内存,在大多数情况下 = 分配给您的进程的内存。
  • @Vyktor:表示分配给进程的内存的唯一正式有意义的方式是枚举可以获得有效指针的方式。这些是通过malloc,通过地址运算符,通过数组到指针衰减,或者作为标准库中函数的返回(或其他结果)值,该函数产生指向对象的指针,就好像通过以下方式获得的一样malloc 或静态存储持续时间。 (希望我没有错过任何一个。)系统当然可以添加其他方式,例如 POSIX 上的mmap。函数指针的转换不需要产生有效的可访问数据指针。
【解决方案2】:

您可能正在尝试访问您的程序不允许访问的内存,而“崩溃”只是系统阻止“病毒”(您 :))破坏它。

这是一个用 gcc 编译的小 linux 代码:

#include <stdio.h>

int b;

int main() {
    char *ptr = (char*)&b;
    ptr -= 2368;
    int i;

    for( i = 0; i < 3984; i++){
        printf( "%d: %c\n", i, ptr[i]);
    }

    printf( "\n");

    return 0;
}

如果您尝试访问 -2369 字节,您将遇到分段错误(访问冲突)。如果您尝试访问超过第 3984 个字节(第 3983 个包括“零字节”),您将收到相同的错误(这可能是可用于应用程序使用的页面大小)。

也可以直接访问二进制代码:

char *ptr = (char*)&main;
ptr -= 999;
int i;

for( i = 0; i < 3763; i++){
    printf( "%c", ptr[i]);
}

在我的系统上是 b 地址:0x600970

和主地址:0x4004e4

因此您可以看到您可以访问不同范围的内存,但您仅限于这些范围。

【讨论】:

    【解决方案3】:

    访问冲突...

    您无法直接访问所有内存,但有保护区。

    简单地说,只要访问了程序无权访问的内存区域,就会发生访问冲突。

    http://blogs.technet.com/b/askperf/archive/2008/06/03/access-violation-how-dare-you.aspx

    【讨论】:

      【解决方案4】:

      并非地址空间中的所有地址都映射到物理内存模块上的实际内存单元。当您尝试读取地址 NULL(即地址 0 处的单元格)处未映射到任何内容的值时,您的系统会检测到它并使用 segmentation falt 信号或类似的东西终止您的进程。

      【讨论】:

      • 地址 0 不一定是 NULL 指针。见this
      • @Lundin 但是0是空指针常量,它不需要表示地址0,但那是另一回事。
      【解决方案5】:

      0 是一个空指针常量

      (C99, 6.3.2.3p3 ): “值为 0 的整型常量表达式,或这种类型转换为 void * 的表达式称为空指针常量。”

      取消引用空指针是未定义的行为

      (C99, 6.5.3.2.p4) "如果给指针赋值了一个无效值,一元 * 操作符的行为是未定义的。87)"

      87):“一元 * 运算符取消引用指针的无效值包括空指针、与指向的对象类型不恰当对齐的地址,以及对象在其生命周期结束后的地址。 "

      【讨论】:

        【解决方案6】:

        来自 C 标准,第 6.5.3.2/4 段

        "如果给指针分配了无效值,则行为 一元 * 运算符的未定义。”

        无效值的一个例子是空指针。因此,您所做的可能有效,也可能无效。我知道在带有 gcc 4.3.1 的 HP-UX 11.31 上它可以工作并且不会崩溃。在你的情况下它崩溃了。如您所见,该标准在这种情况下没有强加任何特定行为。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-05-06
          • 1970-01-01
          • 2012-06-04
          • 2016-07-21
          • 2012-07-14
          • 2021-03-04
          • 1970-01-01
          相关资源
          最近更新 更多