指针入门
指针是一种复合数据类型;定义数组时使用下标运算符[]与其它单一变量进行类型区别;类似的,指针变量使用'*'号加以区别。
// 定义整型指针pi,赋值为0,表示它不指向(持有)任何整型对象。
int *pi = 0;
// 定义字符型指针,赋值为NULL(其实就是0),表明它未指向任何char型对象。
// '*'号紧邻char,强调pc是一个char型指针。(重点在于强调类型)
char* pc = NULL;
// pf是一个float型指针,pf2则一个float型变量,因为它前面没有'*'号。
// '*' 号与类型和变量名分开,突出自身。
// 未初始化的变量值是不确定的,指针pf也一样。
float * pf, pf2;
示例中,*号的位置代表着不同的编码风格,使用哪种完全取决于个人喜好。正如注释所写,从代码审阅的角度讲,不同风格的强调的侧重点不同。变量存在一种从右向左的读法,方法是从变量名(或最后一个修饰词)开始向左阅读,对于第一个变量,可以读作:pi是一个变量,这个变量是一个指针,指针类型是int。连接起来就是:pi是一个指针变量,pi是一个指向整型的指针变量。程序没有为pf进行初始化,是因为我们确信后面会给它进行正确的赋值,如果不确定能做到这一点,建议在定义指针时就初始化为NULL。
取地址
指针变量的值是一段内存区域的地址,为指针赋值,是通过取地址运算符(&)实现的,称为指向了某个变量或地址。
int a = 5;
int *pa = &a; // pa指向了a
double b = 3.0;
double *pb = &b; // pb指向了b
定义一个变量就代表要分配一定字节的内存。
- 对于变量a,系统会分配sizeof(int)个字节的空间以便容纳一个数值。
- 对于指针pa,系统会分配sizeof(int*)个字节的空间以便存储一个地址。
把变量的空间想象成一个盒子,这个盒子有一个编号,此编号就是内存地址。指针的指向(即被赋值)就代表把盒子的地址交给指针的空间存储,即指针的值是盒子的地址。由此可知,指针pa、pb的值有两个特性:
- 首先,pa、pb的值是一个地址,即指针的值是一个地址。
- 指针的值与被指向的变量地址是相同的。(呃,这两条分明是把猫叫了个咪。)
pa = &a | 语句
-----------------------------------------|----------
|
0x001f2a 0x901b30 | 内存地址
+------------+ +------------+ |
| 0x901b30 --|------->| 5 | | 值
+----|-------+ +-----|------+ |
| | |
v v |
值为地址 值为数值 | 值的含义
可以使用%p来打印一个指针的值,地址值通常用16进制表示,为了更清楚的表明这一点,我们在输出值前面加上了0x标志。注意观察结果,pa与&a的值是一样的,表示它们指向同一个值,pb同理。
#include <stdio.h>
int main()
{
int a;
int b = 5;
int *pa = &a;
int *pb = &b;
printf("&a = 0x%p\n", &a);
printf("pa = 0x%p\n", pa);
printf("\n");
printf("&b = 0x%p\n", &b);
printf("pb = 0x%p\n", pb);
return 0;
}

解引用
指向操作让指针持有一个合法的地址值。如果将自己想像成一个指针变量,被指向的对象想像为盒子,指向相当于我们拎起了盒子,盒子的提手就是该盒子的地址,即地址是彼此的连接;盒子中的东西就是你持有的值,至于这个东西是什么,就需要打开盒子去查看。这个打开的动作对应到指针变量上,就叫做解引用指针,通过解引用操作符(*)来实现的。
#include <stdio.h>
int main()
{
int a;
int b = 5;
int *pa, *pb;
// 让指针指向一个地址,相当于拥有一个盒子。
pa = &a;
pb = &b;
// *pa: 相当于打开盒子查看值
// 由于a没有初始化,因此它是一个随机值。
printf("a = %d\n*pa = %d\n\n", a, *pa);
// *pb: 术语化的读法就是:解引用指针pb。
// b初值为5,因此打开盒子pb后你会看到数字5躺在里面。
printf("b = %d\n*pb = %d\n", b, *pb);
return 0;
}

使用未初始化的变量,是一种不确定行为。对于指针变量,如果没有确切的地址可以赋值,则可以将其赋值为NULL,以表示指针指向的地址无效,赋为NULL值的指针被称为空指针。
NULL指针是一个定义在标准库中的值为零的常量。
#define NULL ((void *)0)
在大多数操作系统上,程序不允许访问地址为0的内存,即对空指针进行间接访问是非法的。如果指针为空,则作为条件表达式时求值为假。
#include <stdio.h>
int main()
{
int *pa = NULL;
double *pd = 0; // 等同于NULL,但建议使用NULL。
printf("pa: 0x%p\n", pa);
if (pa)
printf("pointer");
else
printf("pa is NULL");
// 对空指针进行解引用是非法的
int b = *pa;
return 0;
}
