C指针地址操作

C指针地址操作符

地址操作符&会返回操作数的地址。我们可以用这个操作符来初始化pi指针,如下所示:

num = 0;
pi = #

num变量设置为0,而pi设置为指向num的地址:

内存赋值

可以在声明变量pi的同时把它初始化为num的地址,如下所示:

int num;
int *pi = #

有了以上声明,下面的语句在大部分编译器中都会报语法错误:

num = 0;
pi = num;

错误看起来可能是这样的:

error: invalid conversion from 'int' to 'int*'

pi变量的类型是整数指针,而num的类型是整数。这个错误消息是说整数不能转换为指向整数类型的指针。

把整数赋值给指针一般都会导致警告或错误。

指针和整数不一样。在大部分机器上,可能两者都是存储为相同字节数的数字,但它们不一样。不过,也可以把整数转换为指向整数的指针:

pi = (int *)num;

这样不会产生语法错误。不过运行起来后,程序可能会因为试图解引地址0处的值而非正常退出。在大部分操作系统中,在程序中使用地址0是不合法的。我们会在1.1.8节中详细讨论这个问题。

尽快初始化指针是一个好习惯,如下所示:

int num;
int *pi;
pi = #

打印C指针的值

我们实际使用的变量几乎不可能有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函数还有其他几种格式说明符在打印指针的值时比较有用

格式说明符 含义
%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指针会在1.1.8节的“void指针”中解释。为了保证示例简单,我们会用%p说明符,而不把地址转换为void指针。

虚拟内存和指针

让打印地址变得更为复杂的是,在虚拟操作系统上显示的指针地址一般不是真实的物理内存地址。虚拟操作系统允许程序分布在机器的物理地址空间上。应用程序分为页(或帧),这些页表示内存中的区域。应用程序的页被分配在不同的(可能是不相邻的)内存区域上,而且可能不是同时处于内存中。如果操作系统需要占用被某一页占据的内存,可以将这些内存交换到二级存储器中,待将来需要时再装载进内存中(内存地址一般都会与之前的不同)。这种能力为虚拟操作系统管理内存提供了相当大的灵活性。

每个程序都假定自己能够访问机器的整个物理内存空间,实际上却不是。程序使用的地址是虚拟地址。操作系统会在需要时把虚拟地址映射为物理内存地址。

这意味着页中的代码和数据在程序运行时可能位于不同的物理位置。应用程序的虚拟地址不会变,就是我们在查看指针内容时看到的地址。操作系统会帮我们将虚拟地址映射为真实地址。

操作系统处理一切事务,程序员无法控制也不需要关心。理解这些问题就能解释在虚拟操作系统中运行的程序所返回的地址。

指向函数的指针

指针可以声明为指向函数,声明的写法有点难记。下面的代码说明如何声明一个指向函数的指针。函数没有参数也没有返回值。指针的名字是foo:

void (*foo)();

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程