第八章
指针的概念:
变量与地址:内存中每个字节都有一个编号,这个编号就叫做地址。编译或函数调用时会为变量分配空间单元。
指针:一个变量的地址
指针变量:专门存放变量地址的变量
定义指针变量的一般形式:
类型名 *指针变量名
也就定义的时候需要在变量名前加一个*号,做一个区分,告诉编译器是一个什么类型什么名字的指针变量,在后续使用指针变量的时候就不用在加一个*了
&与*运算符
&(取地址运算符)的含义就是获得变量的地址,单目运算符,自右向左结合
*(取内容运算符)的含义就是去指针所指向的变量的内容,单目运算符,自右向左结合。
例如:int *p;那么p就是一个指针变量,他的内容就是一个地址量,*p就是指针的目标变量,他的内容是数据,&p是指针变量占用内存的地址(二级指针)。
直接访问:按变量地址存取变量值。
间接访问:通过存放变量地址的变量去访问变量。
K=i; 直接访问
K=*i_pointer; 间接访问
指针变量与所指向的变量之间的关系:
*i_pointer <==>i
&i< == > i_pointer
i=3< == >*i_pointer=3;
注意:
1、int *p1, *p2(p1与p2均是指针型变量); 与 int *p1, p2(只有p1是指针变量,p2是普通的整型变量);
2、指针变量名是p1,p2 ,不是*p1,*p2
3、指针变量只能指向定义时所规定类型的变量,定义的是int类型的指针变量,就只能存储int类型的变量的地址。
4、指针变量定义后,变量值不确定,应用前必须先赋值,否则系统将会存在崩溃的风险,而且必须用已经初始化过的指针变量做初值
指针变量的初始化:
一般形式:[存储类型] 数据类型 *指针名=初始地址值;
如:int i; int i;
int *p=&i; int *p=&i;
int *q=p;(用已经初始化过的指针变量作为初值)
指针变量必须先赋值再使用。
下面那幅图中上面那串代码
零指针与空类型指针
零指针(空指针)表示指针变量的值为0 int * p=0;p指向地址为0的单元,系统表示该单元不做他用,表示该指针变量的值没有意义。P=0与未对0赋值不同,用途:可以避免指针变量的非法引用,也可以在程序中作为状态比较,
void *类型指针,表示为void *p;使用时要进行强制类型转换
指针变量作为函数参数——地址传递
特点:共享内存,“双向传递”
几道经典例题:
第一个是因为形参的内存空间在swap函数执行完之后就被释放了
第二个是对的
第三个是因为
第四个是因为这是一个假的地址传递,需要仔细甄别,与第二个做对比,二者的相似度极高。
指针与数组
指向数组元素的指针变量,
例 int array[10];
int *p;
p=&array[0]; //Û p=array;
或 int *p=&array[0];
或 int *p=array;
数组名其实就是数组首地址的地址常量,地址常量无法被改变,如本例中的不能有array++这样的式子
指针的运算:
指针变量的赋值运算
p=&a; (将变量a地址Þp)
p=array; (将数组array首地址Þp)
p=&array[i]; (将数组元素地址Þp)
p1=p2; (指针变量p2值Þp1)
不能把一个整数Þp,也不能把p的值Þ整型变量
指针的算术运算:
指针变量的关系运算:
【若p1和p2指向同一数组,则
p1<p2 表示p1指的元素在前
p1>p2 表示p1指的元素在后
p1==p2 表示p1与p2指向同一元素
若p1与p2不指向同一数组,比较无意义
p==NULL或p!=NULL
[ ]实际上叫做变址运算符a[i]ó*(a+i)
指针法和下标法两种方法来表示数组元素
int *p=a;
a[i] Û p[i] Û *(p+i) Û*(a+i)
其中数组名是地址常量,严禁出现a++,这样的写法
指针变量可以指到数组后的内存单元,假如说
int a[5];
int *p=a;
利用指针可以访问到*(p+6)的值
数组名作为函数参数
数组名作为函数参数,是地址传递,下图是实参和形参的对应关系
一级指针变量与一维数组的关系
int *p 与 int q[10]
数组名是指针(地址)常量
p=q; p+i 是q[i]的地址
数组元素的表示方法:下标法和指针法, 即若p=q, 则 p[i] Û q[i] Û *(p+i) Û *(q+i)
形参数组实质上是指针变量,即int q[ ] Û int *q
在定义指针变量(不是形参)时,不能把int *p 写成int p[];
系统只给p分配能保存一个指针值的内存区(一般2字节);而给q分配2*10字节的内存区
指针与二维数组
对于一维数组来说:
数组名a就是数组的首地址,就是a[0]的地址
数组名a是地址常量
a+i是元素a[i]的地址
a[i] Û *(a+i)
在二维数组里面有行指针与列指针两种概念
int a[3][4],对于二维数组来说a是数组名,包括三个元素a[0],a[1],a[2]
每个元素a[i]又是一个一维数组,包括4个元素。
对于二维数组int a[3][4],有:
a 二维数组的首地址,就是第0行的首地址 行指针
a+i 第i行的首地址 行指针
a[i] Û *(a+i)------第i行第0列的元素地址 列指针
a[i]+j Û *(a+i)+j -----第i行第j列的元素地址
*(a[i]+j) Û *(*(a+i)+j) Û a[i][j]
a+i=&a[i]=a[i]=*(a+i) =&a[i][0],
值相等,含义不同
a+i Û &a[i],表示第i行首地址,指向行
a[i] Û *(a+i) Û &a[i][0],表示第i行第0列元素地址,指向列
行取内容就是列,列取地址就是行
如何用指针表示二维数组的某个元素
(1)a[1][2]
(2)*(a[1]+2)
(3)*(*(a+1)+2)
(4)*(&a[0][0]+1*4+2)
二维数组的指针作函数参数
用指向变量的指针变量
用指向一维数组的指针变量
用二维数组名
指针与字符串
字符串的表现形式可以利用字符数组,也可以利用字符指针,不再赘述里用字符数组的方法,着重介绍利用字符指针的的方法
字符指针的初始化,就是把字符串的首地址赋给string
char *string;
string=”I love neu!”;
字符指针作为函数参数,举一个字符串拷贝的例子。
字符指针变量与字符数组
char *cp; 与 char str[20];
str由若干元素组成,每个元素放一个字符;而cp中存放字符串首地址
char str[20]; str=“I love China!”; (´)
char *cp; cp=“I love China!”; (ü)
str是地址常量;cp是地址变量
cp接受键入字符串时,必须先开辟存储空间
字符串与数组关系
字符串用一维字符数组存放
字符数组具有一维数组的所有特点
数组名是指向数组首地址的地址常量
数组元素的引用方法可用指针法和下标法
数组名作函数参数是地址传递等
区别
存储格式:字符串结束标志
赋值方式与初始化
输入输出方式:%s %c
指针与函数
函数指针:函数在编译时被分配的入口地址,用函数名表示
指向函数的指针变量
定义形式: 数据类型 (指针变量名)();
数据类型就是函数的返回值类型
指针变量名就是专门存放函数入口地址,可指向返回值相同的不同函数
小括号不能省略 int(*p)()与int *p ()不同
函数指针变量赋值:如p=max;函数指针变量指向的函数必须有函数说明
函数调用形式:c=max(a,b);,óc=(*p)(a,b)óc=p(a,b)
对函数指针变量p+n,p++毫无意义
指针变量名=函数名;
指针数组和多级指针
用于处理二维数组或者是多个字符串
指针数组
定义:数组中的元素为指针变量
定义形式:[存储类型] 数据类型 *数组名[数组长度说明];例 int *p[4];
指针变量所指向的数据类型
二维数组与指针数组的区别
二维数组的空间固定,字符指针数组相当于可变列长的二维数组,分配的内存单元=数组维数*2+个字符串长度
多级指针:
指向指针的指针
一级指针:指针变量中存放目标变量的地址
二级指针:指针变量中存放一级指针变量的地址
定义形式:[存储类型] 数据类型 **指针名;数据类型就是最终目标变量的数据类型
例 int **p1;
int *p2;
int i=3;
p2=&i;
p1=&p2;
**p1=5;
例如:int I,**p;
P=&i; p是二级指针,不能用变量的地址为其赋值
指针的数据类型: