我已经为特定数据类型的指针分配了一些随机地址。然后我在该特定地址中存储了一个值。当我运行程序时,它突然终止。
char *c=2000;
*c='A';
printf("%u",c);
printf("%d",*c);
我可以打印c
第一个printf
语句中的值。但是我无法通过第二个地址获取存储在该地址中的值。我已经在 Cygwin GCC 编译器和在线 ideone.com 编译器中执行过。在 ideone.com 编译器中,它显示运行时错误。这背后的原因是什么?
当您将地址分配给2000
指针c
时,您假设这将是一个有效地址。但是,一般来说,它不是一个有效的地址。您不能随机选择地址并期望编译器(和操作系统)已分配该内存供您使用。特别是内存的第一页(通常为 4 KiB,通常至少为 1 KiB)是完全不受限制的;所有读取或写入那里的尝试通常都表明错误而不是故意行为,并且 MMU(内存管理单元)被配置为拒绝访问该内存的尝试。
如果您使用的是嵌入式微处理器,则规则可能会有所不同,但在带有 Cygwin 的 Windows 等通用操作系统上,0x1000 (4 KiB) 以下的地址通常是禁止的。
您可以打印地址(您这样做不可靠,但大概您的编译器没有警告您;我会警告我使用 4 字节整数格式来打印 8 字节地址)。但是您不能可靠地读取或写入地址处的数据。可能有机器(通常是大型机)仅仅读取无效地址(即使没有访问它指向的内存)会产生内存故障。
因此,正如Acme在他们的回答中所说,您调用了未定义的行为。您已从编译器那里承担了为指针分配有效地址的责任,但您选择了无效值。崩溃是您错误决定的结果。
char *c=2000;
将整数值分配(和初始化)给指针是实现定义的行为。
ISO C 标准在第 3.4.1 节中将实现定义的行为定义为:
未指定的行为,其中每个实现都记录了如何做出选择
示例 实现定义行为的一个示例是当有符号整数右移时高位的传播。
任何依赖于实现定义行为的代码只能保证在特定平台和/或编译器下工作。便携式程序应尽量避免此类行为。