为何十进制内存地址递减、十六进制内存地址递增?C程序观测疑问
嘿,我来帮你理清这个困惑!首先得敲个重点:地址本身的数值趋势是固定的,十进制和十六进制只是同一数值的不同写法,不可能一个递增一个递减——你看到的差异肯定是打印方式或者代码逻辑出了小问题。
先搞懂数组内存的基本逻辑
不管是int、float还是double数组,元素在内存里都是连续挨在一起存储的。比如你定义int arr[5],第一个元素arr[0]的地址是最低的,往后每个元素的地址都会比前一个大(大多少取决于数据类型的字节数,比如int占4字节,那&arr[1]就比&arr[0]大4),所以地址数值本身是严格递增的——这个规律和用十进制还是十六进制表示没关系。
你看到矛盾趋势的核心原因
最可能的两种情况:
1. 用错了地址打印的格式符
在C语言里,地址是无符号的指针类型,必须用%p格式符打印(它会输出十六进制的地址,通常带0x前缀)。如果你图省事用%d(有符号十进制整数)打印地址,麻烦就来了:
- 当地址的数值超过有符号整数的最大值(比如32位系统里是
2^31-1),会被强制解析成负数。 - 假设你的数组地址刚好落在这个负数区间,那么原本递增的地址数值,用
%d打印出来就会是一串从“小负数”到“大负数”的数,视觉上可能和你预期的“递增”不符;而用%p打印的十六进制是正确的无符号值,看起来是正常递增,这就会让你误以为两种表示的趋势相反。
2. 遍历数组的顺序搞反了
比如你写循环的时候,从数组的最后一个元素(arr[4])往第一个(arr[0])遍历,那打印出来的地址数值本身就是递减的。但如果你的代码里,十进制地址是逆序打印,十六进制地址却不小心写成了正序打印,就会出现“一边递减一边递增”的矛盾——这纯粹是代码逻辑的小失误。
正确的打印姿势,帮你解决困惑
要准确打印地址的十进制和十六进制形式,建议这么写代码:
#include <stdio.h> #include <stdint.h> // 要包含这个头文件才能用uintptr_t int main() { int arr[5] = {10, 20, 30, 40, 50}; printf("十进制地址\t十六进制地址\t存储数值\n"); for (int i = 0; i < 5; i++) { // 把地址转成uintptr_t(无符号整数类型),用%lu打印十进制 printf("%lu\t\t%p\t\t%d\n", (uintptr_t)&arr[i], &arr[i], arr[i]); } return 0; }
运行这段代码你会发现,十进制和十六进制地址的趋势完全一致——都是稳稳递增的,因为数组元素的地址本身就是按这个顺序排列的。
再总结下
地址的数值是固定的,十进制和十六进制只是不同的“写法”,不存在趋势相反的情况。你看到的问题,要么是用错了打印格式符把无符号地址当成有符号数输出,要么是循环遍历的顺序搞反了。按照上面的正确写法调整代码,就能看到一致的地址趋势啦!
内容的提问来源于stack exchange,提问作者8TrackRobot

