指针是 C 语言中的一个重要概念,也是 C 语言的一个重要特色。在 C 语言中,指针被广泛使用,它和数组、字符串、函数间数据的传递等有着密不可分的联系。可以说,没有掌握指针就没有掌握 C 语言的精华。
指针可以对内存中各种类型的数据进行快速、直接的处理,也可以为函数间的数据传递提供简洁、便利的方法。正确熟练地使用指针有利于编写高效的程序,但指针使用不当也容易导致严重错误。指针很灵活,也很危险。
指针变量(简称指针)就是存放地址的变量。其声明形式与一般变量声明相比只是在变量名前多一个星号*
,接下来看两个例子。
例1:
int *p;
该例中声明了变量 p 为指向整型值的指针(即变量 p 中可以存放某个整型变量的地址)。这里的*
在声明语句中,是指针说明符,表示声明的变量是指针变量。
例2:
float *xPtr, *yPtr, f;
该例子中声明了两个指向浮点型值的指针 xPtr 和 yPtr 以及一个浮点型变量 f 。
① 指针可以赋值为 NULL 或某个地址。具有值 NULL 的指针不指向任何地址;
② 指针是具有特定属性的地址。光有地址只是知道数据存储在内存的某个位置,但怎么访问该位置的数据(即访问多少位,以什么方式访问)还需要指针类型来明确;
例如:使用 int 类型的指针访问其所指向的数据时,会一次性读取32位( int 类型的数据是32位),并使用整型数据的格式访问该数据。所以指针不仅仅是一个地址,还必须有特定的属性(类型)。
③ 数组名可以看成是一个特殊的地址,首先数组名是地址(数组的首地址),其次数组名有属性(数组元素的类型),所以可以把数组名赋值给同类型的指针变量。
例如:
char s[10] = "China";
char *sptr = s;
第二条语句赋值后 sptr 拥有和 s 同样的值,即数组的首地址,也就是存储字符‘C’的单元的地址。
④ 要访问指针所指向的单元可以使用间接引用运算符*
(不同于前面声明语句中的*
,这里的*
在表达式中,是运算符),*
也被称为复引用运算符,它返回其操作数(指针)所指向的对象;
例如:
char s[10] = "China";
char *sptr = s;
cout << *sptr;
将输出指针 sptr 所指的单元中存储的字符(因为 sptr 是 char 类型的指针),也就是输出字符‘C’。
⑤ 可以通过指针的复引用修改指针所指向的单元;
例如:
char s[10] = "China";
char *sptr = s;
*sptr = 'c';
上述代码会将该存储单元中大写字符的‘C’修改为小写字符的‘c’。
请注意前面代码的输出语句和下面的代码语句的区别:
char s[10] = "China";
char *sptr = s;
cout << sptr;
这条语句将输出字符串“China”。之前学习字符数组时应该知道,语句cout << s;
会输出数组 s 中存储的整个字符串,实际上 C++ 在使用 cout 输出 char 类型指针时,不是输出字符指针的值(地址),而是输出从该地址开始的字符串(逐个输出一个个字符,直到碰到 ‘\0’ 为止)。所以cout << sptr;
和cout << s;
的作用一样,都是输出字符串“China”。
⑥ 访问一个字符串一般也是使用该字符串的首字符的地址;
⑦ 指针也可以参与算术运算。指针加上或减去一个整数 n,其运算结果是指向指针当前指向变量的后方或前方的第 n 个变量。
例如:之前 sptr 指向字符‘C’的存储单元,执行语句sptr++;
后 sptr 则指向字符‘h’的存储单元。如下语句:
char s[10] = "China";
char *sptr = s;
sptr++;
cout << sptr;
int a[10];
int *p = a, *q = &a[1];
if(p > q) cout << "p>q" << endl;
else cout << "p<=q" << endl;
上述代码中指针 p 中存放的是 a 的值,也就是 a[0] 的地址,q 中存放的是 a[1] 的地址,而数组元素是按序连续存储的,所以 q 的值要比 p 的值大,程序输出p<=q
。