指针
了解C语言中指针的作用,如何声明和解引用指针,以及指针大小带来的影响。
指针是C语言中最为强大但也最令人畏惧的特性之一。这种恐惧和不安部分源于指针在C语言中可能被以极其晦涩的方式使用。许多C语言教程或课程在讲解指针时,会让学生去解析一些看起来怪异的指针语法组合——而这些用法在实际编程中极少出现。你可能已经见过类似的语法(也可能会再次见到),但通常情况下,指针并不需要被用得异常复杂。事实上,它们的使用相当直接。
基本概念是:指针是C语言中一种特殊的数据类型,它存储的是内存中某个位置的地址。可以把指针想象成一根指向内存块的箭头,而该内存块中存放着我们关心的实际数据。这与电话号码或家庭住址的概念非常相似。
下面有一个代码示例,能更清晰地说明这一点。
指针的作用
指针使我们能够操作堆上动态分配的内存块。我们也可以用指针处理栈变量,但在大多数情况下这并非必要。
由于指针可以手动且直接访问内存块,因此它们常用于字符串和结构体。试想一下,将一个大型内存块(比如包含大量数据的结构体)传递给函数时,如果按值传递,就需要将所有数据复制到栈上。相比之下,传递该内存块的地址更加高效——无需复制,只需传递地址,函数结束后也不必删除副本。通过传递变量的地址使其在函数中可访问,这种方式称为传引用;而通过创建新的局部变量并复制其值来传递,则称为传值。
一个实际例子
要使用指针,我们需要掌握如何声明指针、将内存地址存入其中,并利用它访问对应的内存位置。
声明指针
以下是声明指针并存储地址的方法:
1#include <stdio.h> 2 3int main(void) 4{ 5 int age = 30; 6 int *p; 7 p = &age; 8 printf("age = %d\n", age); 9 printf("p = %p\n", p); 10 printf("*p = %d\n", *p); 11 printf("sizeof(p) = %ld\n", sizeof(p)); 12 *p = 40; 13 printf("*p = %d\n", *p); 14 printf("age = %d\n", age); 15 return 0; 16}
我们先从第5到第7行开始,通过图示理解其执行过程,再详细解释代码中指针的声明与使用方式。
-
第5行:我们声明了一个整型变量
age,并初始化为30。 -
第6行:我们声明了一个变量
p,其类型为指向整型的指针。星号
*的语法用于声明一个变量为指向特定类型的指针。通常,我们必须明确指针所指向的具体类型,唯一的例外是所谓的空指针(void pointer),即指向未知类型的指针。目前不必担心空指针。此时,我们有了一个指向整型的指针变量
p,但它尚未指向任何地方。我们只是在内存中预留了存储指针的空间。 -
第7行:我们为指针
p赋值,将其设置为变量age的地址。在C语言中,当
&操作符出现在变量名前时,会获取该变量的内存地址。此时程序的状态如下:
- 变量
age的值是整数30。 - 变量
p的值是age变量所在的内存地址。 p所指向的内存位置中的值也是30。
- 变量
-
第9行:打印指针
p的值。运行程序后,输出是一串长而奇怪的字母与数字组合。这实际上是十六进制形式的内存地址。
解引用指针
访问指针所指向的值,称为解引用指针。可以通过在指针名称前加星号 * 来实现(注意:这不是在声明时使用)。例如,在上述代码中:
- 第10行:使用
*p语法来访问指针p所指向的值。此时,p是一个整型变量的地址,而*p是该地址所对应变量的值。 - 第12行:再次使用解引用,但这次是修改
p所指向变量的值为40。由于p指向age变量,因此相当于将age变量对应的内存位置的值设为40。
指针的大小
从上面代码的第11行及其输出可以看出,我们的指针 p 占用8字节。
记住,1字节等于8位,因此一个4字节的指针最多可表示 32 位,即 个不同的地址,也就是最多访问 4 GB 的内存空间。若需访问超过 4 GB 的内存,则需要更大的指针!在64位系统中,指针占8字节,支持 个不同的内存地址。理论上这意味着计算机可拥有高达16艾字节(约10亿GB或100万TB)的内存——这在可预见的未来都难以实现。
指针的另一个强大用途是支持与数组的交互。