在学校期间学习 C 语言,当时学的确实是一头雾水,数组都没学明白,就更别提指针了。现在翻开这些知识,看过一遍后才真正明白了指针原来是这么回事!
指针是 C 语言中的精华,正确灵活的运用指针,可以表示复杂的数据结构,动态分配内存,方便使用字符串和数组,调用函数返回多结果,直接处理内存单元等等。
一、地址的概念
地址就是内存的编号,如果拿旅店作为内存,那么每个房间号其实就相当于地址了。
当程序编译时,就会对变量分配内存单元,分配时按变量类型分配大小。经过编译后,程序中的变量都转换为其对应的内存地址,以后对变量的存取都是通过地址进行的,这种方式称为“直接方式”。
二、指针和指针变量的概念
一个变量的地址就称为该变量的指针。
存放地址的变量,也就是存放指针的变量,就称为指针变量。指针是一个地址,而指针变量是一个变量,它也有自己的地址(指针)。
将一个变量的地址存放在另一个变量中,也就是指针变量中,通过指针变量来访问原变量的方式,称作“间接方式”。
三、定义指针变量
形式:基类型 * 指针变量名;
C 语言规定所有变量使用前必需先定义,也就是指定其类型,好根据类型分配内存单元的大小。指针类型也不例外,必需定义其类型为指针类型,用“*”表示,但指定为指针类型还不够,需根据所要指向的变量类型定义其基类型,编译时按基类型分配内存空间。
- 举例:
- int * p1, * p2;
- int a=100, b=200;
- p1=&a;
- p2=&b;
- 那么,
- *p1为100,也就是a
- *p2为200,也就是b
- & * p1为&a
- * &a为a
- (* p1)++为a++
四、指针变量作为函数参数
在函数调用时,将实参变量的值传送给形参变量,依然是“值传递”方式。由于是单向的值传递,指针变量作为参数也得守这一规矩。不可能通过调用函数改变实参指针变量的值,但可以改变实参指针变量所指向的变量值。
五、数组与指针
1. 数组元素的指针就是数组元素的地址。
2. 引用数组元素可以用下标法,也可以用指针法,但指针法占用内存少,运行速度快,即目标程序质量很高。
3. C 语言规定数组名代表该数组首元素的地址,它是一个指针常量,在程序运行期间是固定不变的。
4. 输出数组中的元素有三种方法,分别是下标法、通过数组名找到元素地址并找出值、指针变量指向数组元素。前两种方法的执行效率是相同的,费时较多,第三种方法最快。
5. 函数名作函数参数时,编译时都是将形参数组名作为指针变量来处理。
6. 形参数组名实际上是一个指针变量,可以不指定数组元素的个数,并不真正开辟数组空间。但定义数组就需要指定数组大小,因为要开辟空间。
7. 指向二维数组的指针变量中,在指向行的指针前面加一个 "*",就转换为指向列的指针。反之,在指向列的指针前面加 "&",就成为指向行的指针。
六、字符串与指针
1. 字符串的访问可以有两种形式,一种是用字符数组存放一个字符串,另一种就是用字符指针指向一个字符串。
2. 字符串在内存中存放时,会在末尾自动加一个‘\0’来表示字符串的终止位置。
3. 指向数组的指针是个变量,可以进行自增运算。虽然数组名也可以表示数组的首地址,但它是个常量,不能进行自增运算。
七、指向函数的指针
1. 任何函数在编译时会被分配给一个入口地址,这个地址就称为函数的指针。
2. 每一个函数都占用一段内存单元,都有一个起始地址,而函数名就代表该函数的起始地址,即入口地址。
3. 指向函数的指针变量的定义形式:
数据类型 (* 指针变量名)(函数参数表列)
4. 在程序中,一个指针变量可以先后指向同类型的不同函数。
5. 给函数指针赋值时,只需给出函数名而不必给出函数参数。
6. 在用函数指针调用函数时,只需将原来调用方式中的函数名换成 (* p) 即可。
7. 对指向函数的指针变量,不能进行运算,无意义!
8. 指向函数的指针作为形参用于在函数中调用的函数是不固定的情况下。
八、返回指针值的函数
定义形式:类型名 * 函数名(参数表列)
九、指针数组
定义形式:类型名 * 数组名[数组长度]
1. 在定义一个二维的字符串数组时,用指针数组可以节省内存单元,因为不需要按最长的字符串定义数组列数。另外,移动指针变量的值,也就是地址时要比移动字符串所花的时间少的多。
2. 指针数组做main函数的形参
一般写成:void main()
带参数时:void main(int argc, char * argv[])
main函数是由操作系统调用的,当处于操作命令状态下时,输入main所在的文件名,操作系统就会调用main函数。参数值是和命令一起给出的,命令行的一般形式为:
命令名 参数1 参数2 … 参数n
argc 指命令行中参数的个数,需要注意的是文件名也算做一个参数。
argv 是一个指向字符串的指针数组,命令行参数应当都是字符串,这些字符串的首地址构成这个指针数组。
main函数中的形参名不一定命名为argc和argv,可以任意,只是已经习惯用这两个名而已。
十、指针总结
- int i; //定义整形变量i
- int * p; //p为指向整形数据的指针变量
- int a[n]; //定义整形数组a,它有n个元素
- int * p[n]; //定义指针数组p,塔由n个指向整形数据的指针元素组成
- int (*p)[n]; //p为包含n个元素的一维数组的指针变量
- int f(); //f为返回整形函数值的函数
- int * p(); //p为返回一个指针的函数,该指针指向整形数据
- int (*p)(); //p为指向函数的指针,该函数返回一个整型值
- int **p; //p是一个指针变量,它指向一个指向整形数据的指针变量
指针变化莫测,拿准它,还需要多做实验,否则也会导致不可预料的后果!