指针归纳
2.1:指针的自述
2.1.1:指针的告白
首先,理解一下下面几个定义:
内存的地址:
在程序运行时,操作系统要为代码和程序所需的数据分配特定的内存空间,在程序运
行过程中:对数据的访问就是对数据所分配的内存空间的访问,为了便于管理内存,每个
储存单元都有一个唯一的编号,这些单元的编号称为内存单元的地址,就像门牌号一样。
变量的地址:
在 C 语言程序定义一个变量,根据变量类型的不同,系统会为其分配一定字节数的存
储空间,所分配的存储空间的第一个存储单元的地址即为该变量的地址。
直接寻址与间接寻址:
直接寻址:在执行 scanf(“%d”,&a)时,若从键盘输入 6,则 6 将被送往例如起始地址
为 20 的 21,22,23 四字节的内存空间中,在执行 printf(“%d”,a);语句时,系统根据变量
名和地址的对应关系找到地址 20,然后从 20 开始的四个字节中取出整数 6. 间接寻址:定义一个特殊的变量 p,这个变量可以存放变量 a 的地址,如果通过变量 p
存取 a 的值的过程:首先找到存放变量 p 的地址,然后在这个地址里找到 a 的地址,再从 a
的地址里找到 a 的值。
实质:变量的地址就是指针
C 语言允许定义专门用来存放地址的特殊变量,称为指针变量。一个变量的地址称为
该变量的指针。指针变量的值就是(地址)指针
2.1.2:指针变量的定义和初始化
1.指针变量的定义
C 语言规定所有变量都必须先定义再使用,指针亦如此
注意:一个指针变量只能指向同一数据类型的变量,原因:不同数据类型的数据需要存储
的字节数可能是不同的。
2.指针变量的初始化
说明:
和普通变量一样,如果指针变量是非静态局部变量且未初始化,那么它的值是不确定的。
指针变量初始化的一般格式
注意:
1》用于初始化的变量必须已定义且类型一致
2》可以使用已初始化的指针变量给另一个相同数据类型的指针变量做初始值。
3》不能用 0 以外的常量作为指针变量的初值,可以初始化为一个空指针
和普通变量一样,对于外部或静态指针变量若未初始化,则自动被初始化未 NULL,
它的值为零
局部指针变量若未初始化,则它的值是不确定的,因而指向了一个不确定的单元,若
这时引用指针变量,可能会产生不可预料的后果(影响操作系统的工作)。
4》不能用一个自动(auto)型的变量的地址去初始化一个 static 型的指针
5》void *类型指针表示无类型指针,可以指向任意类型的数据(在被任意类型数据指
向时需要强制转化),无需强制类型转换
2.1.3:指针的运算
指针运算的实质就是地址的运算;
1.指针的赋值运算
(1)将变量的地址赋值给指针变量,使指针指向该变量
**(2)指针变量间的赋值
类型一致的指针变量可以相互赋值
例如:
int a=&c;
int b=NULL;
b=a;
2.通过取内容运算符,访问目标变量
p=a;//将变量 a 的值赋给以 p 的值为地址的存储区域
c=pb;//将 pb 内存区域里的数据赋给 c
3.指针的加减运算
(1).在指针变量指向数组的第一个元素,n 为一个整数,则 p+n 表示指向下标为 n 的元素
改变 nsizeof(指针的数据类型)个字节的距离
(2).两个指针变量在一定条件下,可以减法运算
当两个指针变量 p 和 q 指向同一个数组,则 p-q 的绝对值表示 p 所指数组元素与去所值数
组元素之间相差的元素个数,为 1 表示相邻,除数组外,其他减法无意义
4.指针的关系运算
只有相同类型的指针才能进行关系运算;另外指针变量还可以和数值 0 进行关系运算的相
等或不等的运算,和其他的不能
2.1.4:一级指针的说明
1.一维数组与指针
实际上,数组名就是一个指针,是数组在内存中的起始地址(数组的指针),即第 0 号元
素的地址,是一个地址常量(指针常量)。数组元素的指针是指数组元素在内存里的地址
案例:
int a[10];
int *p=a;
已知 p 是指向一个 int 型的指针,而 a 是一个数组名。为什么能把数组名赋给一个指针变量
呢?原因是数组名 a 是数组在内存分配到的空间的首地址。在这里,a 是一个指向数组 a 的
第一个元素的指针。或者说,a 也是一个指向 int 类型的指针,与 p 属于同一类型。只不过,
a 是一个指针常量,它的值是不可改变的,而 p 是指针变量。
*p=a[0]=p[0]
*(p+1)=a[1]=p[1]; *(p+2)=a[2]=p[2]; (p+3)=a[3]=p[3]; (p+4)=a[4]=p[4];
注意:
(1)数组名 a 是指针常量,不能作为指针变量使用,像 a++就不行
(2)在使用数组引用数组元素时,系统不做下标越界检查。所以需要注意指针访问越界
(3)p++相当于(p++)。因为和++同优先级(p++)表示先取“*p”,再使 p 加
1。
引用一维数组的方法:
(1)下标法,a[i],简单直观
(2)用指针访问各元素“*P”,效率高,其他不介绍
牢记:数组名是一个常指针,它的值是无法改变
2.二维数组与指针
首先,理解一下二维数组:就是一个一维数组的元素又是一个一维数组
形如:int a[2][3]={{1,2,3},{1,2,3}};
所以在一维数组里理解,a 在这里是指向一维数组的指针常量
形如:int()[4];
这样 a 则代表第 0 行的首地址
(1)&a[i]和 a+i 表示第 i 行的首地址,
(2)该行的其他元素地址可以用数组名加序号就行。如:(a[i]+1),(a[i]+2);//???
注意:
(1):a+i、&a[i]、(a+i)、&a[i][0];的值相等,但含义不同
(2):a+i 和&a[i]表示第 i 行的首地址,指向行
(3):a[i]、*(a+i)、&a[i][0]表示第 i 行第零列元素地址,指向列
区分二维数组的三种表现形式:
a[i][j], *(a[i]+j), ((a+i)+j)。
也可以定义一个一维数组的指针变量
形如:
int a[2][4]={0};
int (*p)[4]=a;//定义 p 为指向一个有 4 个 int 元素的一维数组的指针变量
注意:这里的 p 为指向一维数组的行指针
2.指针形式的字符串操作
字符指针定义格式
char *指针变量名
char *from=“zhaokexue”
Printf(“%s”from);
3.区分指针数组和数组指针
指针数组:是相同类型指针变量的集合,即数组的每一个元素都使指针且具有相同的存
储类别,并指向相同的数据类型
Char p[5]={“sgvfgh”,”sdgsdhhs”};//[]的优先级比的高
数组指针:
指向数组的指针
int a[10];
int *p=a;
p 是指向数组的指针
4.指向结构体变量的指针变量
2.1.5:指针与函数
(1):指针作为函数参数
1》函数实参形参都为指针变量
使用原因:早期的使用值传递方式,形参值的改变无法回传给实参。
而使用指针作实参和形参,实现了“址传递”可以将在改变形参的值的同时改变实参
划线部分实参做地址
(2):区分指针函数和函数指针
指针函数:函数的返回值为指针的函数
定义格式:
int *p(int *,int *)
{
函数体部分;
}
函数指针:指向函数的指针
解释:在 C 程序在编译时,每个函数都有一个入口地址(函数名),其值是函数的首条命
令的地址。把一个函数名赋值给指针变量,该指针变量就是指向函数的指针,此后通过指
针调用函数,就如同用指针引用普通变量一样。
函数指针有两个用途:(1):调用函数(2):做函数的参数。
C++程序实例:
int swap(int *p1,int *p2,int *p3)
int (*p)(int *
,int *
, int *)(swap);// 此为函数指针声明加初始化(C++中)
c 程序实例:
int max(int x,int y)
{
}
int (*ptr)(int x,int y);//声明函数指针
Ptr=max;//将函数的入口地址赋值给指针变量 ptr
注意:要赋给函数指针的函数应该和函数指针所指的函数类型一致
2.1.6:二级指针的说明
指针的表现形式是地址,核心是指向关系指针,运算符“*”的作用是按照指向关系访问所
指向的对象.如果存在 A 指向 B 的指向关系,则 A 是 B 的地址,“*A”表示通过这个指向关
系间接访问 B.如果 B 的值也是一个指针,它指向 C,则 B 是 C 的地址,“*B”表示间接访
问 C 如果 C 是整型、实型或者结构体等类型的变量或者是存放这些类型的数据的数组元素,
则 B(即 C 的地址)是普通的指针,称为 一级指针,用于存放一级指针的变量称为 一级指针
变量。
A(即 B 的地址)是指向指针的指针,称为 二级指针,用于存放二级指针的变量称为 二
级指针变量.根据 B 的不同情况,二级指针又分为指向指针变量的指针和指向数组的指针
二级指针的分类
(1)指向指针变量的指针
在如上的 A 指向 B、B 指向 C 的指向关系中,如果 A、B、C 都是变量,即 C 是普通变
量,B 是一级指针变量,其中存放着 C 的地址,A 是二级指针变量,其中存放着 B 的地址,
则这 3 个变量分别在内存中占据各自的存储单元,它们之间的相互关系下图所示,相互之
间的前后位置关系并不重要.此时,B 是一级指针变量,B 的值(即 C 的地址)是一级指针数
据;A 是二级指针变量,A 的值(即 B 的地址)是二级指针数据.
(2)指向数组的指针
在 C 语言中,数组与其它变量在使用上有很大的不同.无论是字符型、整型、实型变
量,还是结构体类型或者指针类型的变量,语句中出现变量名都代表对该变量所在内存单元
的访问,变量名代表整个变量在内存中的存储单元,可以向该变量赋值,也可以从中取出数
据使用.但是定义一个数组之后,数组名并不代表整个数组所占据的内存单元,而是代表数
组首元素的地址