◆指针可以称得上是C语言的灵魂,正因为有了指针这一强大的功能,让C语言操作的灵活度能够达到一个更高的层次,同时使得C语言在各类编程语言中拥有不可取缔的地位。初学时感到C语言中的指针的相关知识点很繁琐,也很绕,进而许多概念极易混淆,特此整理指针的初级相关知识点。
1. ★指针的概念
地址与指针?
地址:C程序中的变量在占有一个可标识的存储区,每一个存储区是由若干字节组成,而每一个字节都有自己的地址,而一个存储区的地址则为该存储区第一个字节的地址。(&)
存储区访问:存储区的访问方式有直接访问和间接访问两种,直接访问顾名思义就是通过变量名或地址访问变量的存储区,间接访问则为一个变量的地址存放在另一个变量中。如:将X的地址放到P中,访问X时先找到P,再由P中存放的地址找到X。
指针:一个变量的指针则为该变量的地址(指针在某种程度上就是地址),而指针变量就是存放变量地址的变量,用来指向另一个变量。
2. ★指针变量的引用:
指针运算符(*)
例:p和*p。p与*p不同,p是指针变量,p的值是p所指向的变量的地址。*p是p所指向的变量,*p的值是p所指向的变量的值。
C中函数调用是按值传递的,传入参数在子函数中只是一个初值相等的副本,无法对传入参数作任何改动。但实际编程中,经常要改动传入参数的值。这一点我们可以用传入参数的地址而不是原参数本身,当对传入参数(地址)取(*)运算时,就可以直接在内存中修改,从而改动原想作为传入参数的参数值。如下该例:
#include<stdio.h> void fun(int *val) { (*val)++; } Int main() { Int a=3; fun(&a); printf(“%d”,a); return 0; }
注:在执行inc(&a);时,系统在内存分配表里增加了一行”fun中的val”,其地址为新地址,值为&a。操作*val,即是在操作a 了。
3. ★*和&运算
“*”运算:(*p)操作是这样一种运算,返回p 的值作为地址的那个空间的取值。”&”运算:(&p)则是这样一种运算,返回当时声明p 时开辟的地址。显然可以用赋值语句对内存地址赋值。
※注:两个地方要注意:在程序声明变量的时候的*,只是表明“它是一个无符号整数,这个整数指向某个内存地址,一次访问sizeof(type)长度”,这点不要和(*)操作符混淆;在C++程序声明变量的时候的&,只是表明“它是一个引用,这个引用声明时不开辟新空间,它在内存分配表加入新的一行,该行内存地址等于和调用时传入的对应参数内存地址”,与(&)操作符不同。
4. ★指针的初始化
对指针进行初始化或赋值只能使用以下四种类型的值:
①.0值常量表达式,例如,在编译时可获得0值的整型 const对象或字面值常量0。
②.类型匹配的对象的地址。
③.另一对象末的下一地址。
④.同类型的另一个有效指针。
注:把int型变量赋给指针是非法的,尽管此int型变量的值可能为0。但允许把数值0或在编译时可获得0值的const量赋给指针。
5. ★指针数组,数组指针,函数指针
①指针数组:就是一个由指针组成的数组,那个数组的各个元素都是指针,指向某个内存地址。char *p[10]中p是一个指针数组。指针数组的运用可以作为函数的参量使用,使用方式与普通数组类似。并且指针数组常适用于指向若干字符串,这样使字符串处理更加灵活方便。
②数组指针:数组名本身就是一个指针,指向数组的首地址。注意这是一个常数。char (*p)[10]中p是一个数组指针。其本质为指针(这个指针存放的是数组首地址的地址,相当于2级指针,这个指针不可移动)。例如:
{ int a[4][5]; int (*p)[5]=a; }
※注:这里a是个二维数组的数组名,相当于一个二级指针常量;p是一个指针变量,它指向包含5个int元素的一维数组,此时p的增量以它所指向的一维数组长度为单位;*p+i是二维数组a[0][i]的地址;*(p+2)+3表示a[2][3]地址(第一行为0行,第一列为0列),*(*(p+2)+3)表示a[2][3]的值。
※对于二维数组来说:二维数组:如char str[10][10]只要定义了一个二维数组,无论赋不赋值,系统都会给他分配相应空间,而且该空间一定是连续的。其每个元素表示一个字符。我们可以通过指定下标对其元素进行修改。而指针数组:如char *str[5]系统至少会分配5个连续的空间用来存储5个元素,表示str是一个5个元素的数组,每个元素是一个指向字符型的一个指针。
总结:相比于比二维字符数组,指针数组有明显的优点,一是指针数组中每个元素所指的字符串不必限制在相同的字符长度;二是访问指针数组中的一个元素是用指针间接进行的,效率比下标方式要高。 但是二维字符数组却可以通过下标很方便的修改某一元素的值,而指针数组却无法这么做。
③函数指针:本身是一个指针,指向一个函数入口地址,通过该指针可调用其指向的函数,使用函数指针可实现回调函数。 常见的函数体中其本身是一个函数,其返回值是一个指针的形式。
6. ★指针与引用(C++风格)
不同点:
①.指针是一个实体,而引用仅是个别名。
②.引用使用时无需解引用(*),指针需要解引用。
③.引用只能在定义时被初始化一次,之后不可变;指针可变;引用“从一而终”。
④引用没有const,指针有const,const的指针不可变。
⑤引用不能为空,指针可以为空。
⑥引用是类型安全的,而指针不是(引用比指针多了类型检查)。
⑦“sizeof引用”得到的是所指向的变量(对象)的大小,而“sizeof指针”得到的是指针本身(所指向的变量或对象的地址)的大小。
相同点:两者都是属于地址范畴的概念,指针指向一块内存,它的内容是所指内存的地址;引用是某块内存的别名。