我们实际使用的变量几乎不可能有100或104这样的地址。不过,变量的地址可以通过打印来确定,如下所示:
int num = 0;
int *pi = #
printf("Address of num: %d Value: %d\n",&num, num);
printf("Address of pi: %d Value: %d\n",&pi, pi);
运行后,会得到下面的输出。在这个例子中我们用了真实的地址,你的地址可能会不一样:
Address of num: 4520836 Value: 0
Address of pi: 4520824 Value: 4520836
printf
函数还有其他几种格式说明符在打印指针的值时比较有用,如表1-2所示。
表1-2:格式说明符
格式说明符 | 含义 |
---|---|
%x |
将值显示为十六进制数 |
%o |
将值显示为八进制数 |
%p |
将值显示为实现专用的格式,通常是十六进制数 |
这些说明符的用法如下:
printf("Address of pi: %d Value: %d\n",&pi, pi);
printf("Address of pi: %x Value: %x\n",&pi, pi);
printf("Address of pi: %o Value: %o\n",&pi, pi);
printf("Address of pi: %p Value: %p\n",&pi, pi);
这样就会显示pi
的地址和内容,如下所示。在这个例子中,pi
持有num
的地址:
Address of pi: 4520824 Value: 4520836
Address of pi: 44fb78 Value: 44fb84
Address of pi: 21175570 Value: 21175604
Address of pi: 0044FB78 Value: 0044FB84
%p
和%x
的不同之处在于:%p
一般会把数字显示为十六进制大写。如果没有特别说明,我们用%p
作为地址的说明符。
在不同的平台上用一致的方式显示指针的值比较困难。一种方法是把指针转换为void
指针,然后用%p
格式说明符来显示,如下:
printf("Value of pi: %p\n", (void*)pi);
void
指针会在null指针和void指针的“void指针”中解释。为了保证示例简单,我们会用%p
说明符,而不把地址转换为void
指针。
虚拟内存和指针
让打印地址变得更为复杂的是,在虚拟操作系统上显示的指针地址一般不是真实的物理内存地址。虚拟操作系统允许程序分布在机器的物理地址空间上。应用程序分为页(或帧),这些页表示内存中的区域。应用程序的页被分配在不同的(可能是不相邻的)内存区域上,而且可能不是同时处于内存中。如果操作系统需要占用被某一页占据的内存,可以将这些内存交换到二级存储器中,待将来需要时再装载进内存中(内存地址一般都会与之前的不同)。这种能力为虚拟操作系统管理内存提供了相当大的灵活性。
每个程序都假定自己能够访问机器的整个物理内存空间,实际上却不是。程序使用的地址是虚拟地址。操作系统会在需要时把虚拟地址映射为物理内存地址。
这意味着页中的代码和数据在程序运行时可能位于不同的物理位置。应用程序的虚拟地址不会变,就是我们在查看指针内容时看到的地址。操作系统会帮我们将虚拟地址映射为真实地址。
操作系统处理一切事务,程序员无法控制也不需要关心。理解这些问题就能解释在虚拟操作系统中运行的程序所返回的地址。
用间接引用操作符解引指针
间接引用操作符(*
)返回指针变量指向的值,一般称为解引指针。下面的例子声明和初始化了num
和pi
:
int num = 5;
int *pi = #
然后下面的语句就用间接引用操作符来显示5,也就是num
的值:
printf("%p\n",*pi); // 显示5
我们也可以把解引操作符的结果用做左值。术语“左值”是指赋值操作符左边的操作数,所有的左值都必须可以修改,因为它们会被赋值。
下面的代码把200赋给pi
指向的整数。因为它指向num
变量,200会被赋值给num
。图1-5说明了这个操作如何影响内存。
*pi = 200;
printf("%d\n", num); //显示200
图1-5:利用解引操作符给内存赋值
评论前必须登录!
注册