一、一级指针
1.1 基本结构
一级指针变量名:存储普通变量的地址
指针:指针就是地址
指针变量:用于存放地址的变量
格式:存储类型 数据类型 *指针变量名 int *p
- 数组名也是变量的首地址,是地址常量,不能为左值(=左边),不能被重新赋值。
- p 和 a不同的是,p是指针变量,而 a是个常量,所以可以用等号给 p赋值,但是不能给 a赋值,
int a=5;
int *p=&a; // a的地址赋给指针p,p里面储存的是a的地址
a 与 *p 输出值一样,都是变量的值;&a 与 p 输出值一样,都是地址。
如果在一行中定义多个指针变量,每个指针变量前面都需要加 * 来修饰,
1.2 指针操作符
*:取地址里边的内容
&:取地址符: 取变量的地址
*&a:=== a
&*a:错误
1.3 初始化
- 指针在使用前要先定义,同时初始化,
- 未初始化的指针变量不能随便使用,会产生野指针
- 可以先定义一个空指针,后边可以重新赋值
- 指针 p指向变量 a, *p可以访问到 a的值,
- 可以通过 *p间接修改变量 a的值
- 把数组的首地址赋值给指针变量
- 将指针变量里面保存的地址赋值给另一个指针变量
1.4 指针运算
1.4.1 算术运算
p++, p--
p++: 指针向高地址方向移动一个数据单位(int 4字节;char 1字节),指向下一个元素
指针的指向发生改变
单纯输出 p+1:暂时访问高地址,只是暂时访问,没有移动,实际指向的地址不变
同一个数组,两个地址之间的差值 = 相差元素个数
1.4.2 关系运算
< > ==
- 在同一个数组下
- 相同类型的指针
- 高地址 > 低地址(前面的指针 小于 后面的指针)
1.4.3 赋值运算
- 同类型的指针可以相互赋值(void 除外)
- 如果不同类型的指针想要相互赋值,必须进行强制类型转换
1.4.4 指针的大小
32位操作系统 ,指针大小为4字节 1字节==8位
8位 16进制 4*8=32位二进制 = 4字节
64位操作系统 ,指针大小为8字节
16位 16进制 4*16=64位二进制 = 8字节
交换字符串,倒序输出
回文数判断
输入字符,输出数字
1.5指针修饰
const 常量化 转换为只读
1.5.1 修饰普通变量
int const a = 5;
修饰普通变量,不能直接对变量名进行修改
可以通过指针进行修改,通过修改指针来间接修改变量
1.5.2修饰指针 *p
int const *p = &a;
指针指向的内容不能修改;但是指针的指向可以修改
1.5.3 修饰 地址 p
int * const p=&a
指针的指向不能改,指针指向的内容可以改
const int *const p 既修饰指针指向的内容,又修饰指向,无法进行修改。
二、二级指针
2.1 二级指针
一级指针存放普通变量的地址,二级指针存放一级指针的地址
格式:存储类型 数据类型 **指针变量名
int **p;
三、指针和数组
3.1 指针和一维数组
数组名字取地址,变成 数组指针
一维数组名字 取地址,变成一维数组指针,加一即跳过一个一维数组 a[10]
a与 a+1 跳一个整形元素,a+1是 a[1]的地址,地址相差一个元素,四个字节
&a 就变成了一个一维数组指针,是 int (*p)[10] 类型
&a 与 &a +1 相差一个拥有十个元素的一维数组,地址相差40个字节
3.2 访问
3.2.1 直接访问:通过数组名
- 数组名也是变量的首地址,是地址常量,不能为左值(=左边),不能被重新赋值。
- p 和 a不同的是,p是指针变量,而 a是个常量,所以可以用等号给 p赋值,但是不能给 a赋值,
地址 | 数组 | 元素 | ||
a | &a[0] | 2 | a[0] | *a |
a+1 | &a[1] | 3 | a[1] | *(a+1) |
a+2 | &a[2] | 4 | a[2] | *(a+2) |
a+3 | &a[3] | 5 | a[3] | *(a+3) |
a+4 | &a[4] | 6 | a[4] | *(a+4) |
3.2.2 间接访问:通过指针
地址 | 数组 | 元素 | ||||||
&p[0] | p | a | &a[0] | 2 | a[0] | *a | *p | p[0] |
&p[1] | p+1 | a+1 | &a[1] | 3 | a[1] | *(a+1) | *(p+1) | p[1] |
&p[2] | p+2 | a+2 | &a[2] | 4 | a[2] | *(a+2) | *(p+2) | p[2] |
&p[3] | p+3 | a+3 | &a[3] | 5 | a[3] | *(a+3) | *(p+3) | p[3] |
&p[4] | p+4 | a+4 | &a[4] | 6 | a[4] | *(a+4) | *(p+4) | p[4] |
3.3 指针和二维数组
- 一维数组的名字是数组的首地址,是的第一个元素的地址,是一个常量,数组名加 1表示下一个元素
二维数组的数组名表示第一行的首地址,数组名 加 1表示第二行的首地址
int a[2][3]={2,3,4,5}; // a:第一行的首地址 a+1:第二行的首地址
a是行地址,如果想访问其中的列(行地址和列地址级别不同,一行可以有多列),需要对他降级处理加 *
- a: 第一行的首地址
- a+1: 第二行的首地址
- *a: 第一行第一列的地址
int a[2][3]={2,3,4,5,6,7};
- printf("%p\n", a); //第一行的首地址
- printf("%p\n", *a); //第一行第一列的地址
- printf("%p\n", *a+1); //第一行第二列的地址
- printf("%d\n", *(*a+1)); //取第一行第二列的内容
- printf("%p\n", a+1); //第二行的首地址
- printf("%p\n", *(a+1)); //第二行第一列的地址
- printf("%p\n", *(a+1)+1); //第二行第二列的地址
- printf("%d\n", *(*(a+1)+1)); //取第二行第二列的内容
地址 | 元素 | |||||
a[0] | *a | a | 2 | a[0][0] | **a | *a[0] |
a[0]+1 | *a+1 | 3 | a[0][1] | *(*a+1) | *(a[0]+1) | |
a[0]+2 | *a+2 | 4 | a[0][2] | *(*a+2) | *(a[0]+2) | |
a[1] | *(a+1) | a+1 | 5 | a[1][0] | *(*(a+1)) | *a[1] |
a[1]+1 | *(a+1)+1 | 6 | a[1][1] | *(*(a+1)+1) | *(a[1]+1) | |
a[1]+2 | *(a+1)+2 | 7 | a[1][2] | *(*(a+1)+2) | *(a[1]+2) |
3.4 数组指针
本质是指针,指向一个数组变量
格式:存储类型 数据类型 (*指针变量名)[列数]
p可以代替 a进行元素访问,但是本质不同
int a[2][3]={2,3,4,5,6,7};
int (*p)[3]=a;
地址 | 元素 | |||||||
p[0] | *p | a[0] | *a | a | 2 | a[0][0] | **a | *a[0] |
p[0]+1 | *p+1 | a[0]+1 | *a+1 | 3 | a[0][1] | *(*a+1) | *(a[0]+1) | |
p[0]+2 | *p+2 | a[0]+2 | *a+2 | 4 | a[0][2] | *(*a+2) | *(a[0]+2) | |
p[1] | *(p+1) | a[1] | *(a+1) | a+1 | 5 | a[1][0] | *(*(a+1)) | *a[1] |
p[1]+1 | *(p+1)+1 | a[1]+1 | *(a+1)+1 | 6 | a[1][1] | *(*(a+1)+1) | *(a[1]+1) | |
p[1]+2 | *(p+1)+2 | a[1]+2 | *(a+1)+2 | 7 | a[1][2] | *(*(a+1)+2) | *(a[1]+2) |
3.5 指针数组
指针和数组的关系:
- 指针可以保存数组元素的 地址
- 可以定义一个数组,数组中有若干相同类型的指针变量,这个数组被称为指针数组
概念:若干 相同类型的指针变量 构成的集合 本质是数组
定义:类型说明 * 数组名 [元素个数]
p :数组元素的地址,指针中元素的地址
p[ ] : 数组元素的内容(存放的是地址)
p[2] 与 *(p + 2) 是等价的,都表示指针数组中的第三个元素
p[2] 指针数组中的第三个元素
p 为数组名,为数组首地址,也是第一个元素的地址
p+2 为数组中第三个元素的地址,*(p+2) 为第三个地址的内容,也就是第三个元素的内容。
大小:sizeof(p)= 数组数据类型的单位元素大小 * 数组元素个数
int 类型指针数组,一个元素占 4 个字节 ,,char 类型指针数组,一个元素占 1 个字节
- p[0] 为数组第一个元素,p 为数组名,为数组首地址
- p[0] = &a; 把变量 a的地址赋给 p[0], p[0] 指向变量 a的地址,*p[0]为数组p[0] 指向的地址的值,也就是变量 a 的值。
- b[2] 为数组 b的第三个元素,p[1] 为指针数组 p的第二个元素
- p[1] = &b[2]; 数组 b的第三个元素的地址赋给 指针数组 p的第二个元素,p[1] 指向变量 b[2]的地址,*p[1] 是指向地址的变量值,也就是b[2]中变量的值。
- p为指针数组名,为指针首地址,也是第一个元素的地址,p+1 为指针数组的第二个元素的地址,*(p+1) 位第二个地址存放的内容,也就是b[2]的地址,**(p+1)也就是第二个元素地址存放的内容的内容,也就是b[2]的内容
- 字符串类型的指针数组中,元素储存的是字符串中首个字符的地址
- 打印字符串 只需要找到字符串的首地址。
- 在文字常量区开辟了一段空间存放字符串,
- 将字符串的首地址赋给指针变量
指针数组 name中,第一个元素储存的是 hello中 h的地址,第二个元素储存的是 world中 w的地址
四、 运算方法
(1)* 和 ++ 都是单目运算符,优先级相同
(2)单目运算符从右向左运算
- (*p)++:先算(*p)取内容,对内容++
- *p++:先算p++,由于++在后,对p取*,最后再 p++
- *(p++) :同上
- ++*p :先算*p得到内容,再去 ++内容
- ++(*p):同上
- *++p :先算++p, 由于++在前,p先自加,对自加后的地址取内容
- *(++p) :同上