1.1 定义
在计算机内部存储器(简称内存)中,每一个字节单元,都有一个编号,称为地址。在C语言中,内存单元的地址称为指针,专门用来存放地址的变量,称为指针变量(pointer variable)。在不影响理解的情况下,把地址、指针、指针变量,都叫指针。
1.2 指针类型
1.2.1 构成
目标类型 *
-------- -
| |
| +----->数据为地址
+----------->任何类型
1.2.2 编码结构;无符号整数
1.2.3 长度:与机器位数有关
1.2.4 字面常量:NULL (void *)0 //表示指针变量中存的内容为0
注意: izeof(指针)一定是等于计算机的位数,与目标类型无关。
1.3 定义指针变量
1.31 定义指针变量的方法:
(1) 确定目标(变量)类型:char
(2) 确定指针类型:char *
(3) 定义指针变量:char *p;
实例:
实例:针对c[2][3]
1.3.2 认识指针变量
认识指针变量类型 ---> 认识目标类型
1.3.3 语法原理(注意观察)
变量 变量的指针类型 指向变量的指针变量定义
int a; int * int *pl
int a[3]; int (*)[3] int (*pr)[3];
char *a[3] char *(*)[3] char *(*p)[3];
1.4 取地址运算
语法:
&a(变量, 数组, 函数)
1.5 赋值运算
1.5.1 语法:p = a;
1.5.2 操作数类型:a和p类型相同
1.5.3 运算法则
(1) a的类型和p不相同时,编译器尝试自动转换:
a的类型转为p类型, 但p最好是void * 所有的编译器都行
(2) a--->p
1.5.4 结果:p的值,结果的类型是a的类型。
1.5.5 写运算的思路
(1) 确定运算符
(2) 确定操作数(类型)
1.5.6 看运算的思路:
(1) 确定操作数类型
(2) 确定运算法则
1.6 求目标
1.6.1 语法:*p
1.6.2 操作数类型:p必须为指针类型,但不能是void*。
1.6.3 法则:如果p = &a; 则 *p 就是a
1.6.4 结果:a
总结:px — 指针变量,它的内容是地址量。
*px — 指针所指向的对象,它的内容是数据。
&px — 指针变量占用的存储区域的地址,是个常量。
1.7 移动指向
1.7.1语法
p + n
p - n
p++, p--, ++p, --p
实例:
1.7.2操作数类型
p:p必须为指针,最好为非void*类型,gcc允许对void*的指针进行移动指向,但是其他编译器不一定可以
n:n必须为整数
1.7.3 运算法则
p + n
向地址增加方向移动n个目标, 即: p中的地址 + sizeof(目标类型也就是*p) * n
注意:sizeof(p)的大小一直为4.注意是sizeof(*p)
gcc允许p为void*,p + n表示将p中的地址加n
p - n
向地址减小方向移动n个目标, 即: p中的地址 - sizeof(目标类型) * n
p++
取p的值,作为结果,然后p = p + 1
++p
p = p + 1,然后取p的值,作为结果
p—
取p的值,作为结果,然后p = p - 1
--p
p = p – 1,然后取p的值,作为结果
注意:函数类型的指针不能做加减运算。
实例:
1.8 求指针之间的目标个数
1.8.1 语法
p1 - p2
1.8.2 操作数类型
p1和p2必须为相同类型的指针
如果p1和p2的类型都为void * 运算前都会被自动转换为long类型
1.8.3. 运算法则
(1) p1和p2类型为非void * 时
(p1中的地址 - p2中的地址) / sizeof(目标类型)
(2) p1和p2的类型为void *时(可能会有编译器不支持)
p1中的地址 - p2中的地址
1.8.4 结果
目标个数
实例:
1.9 关系运算
>, >=, <, <=, ==, !=
都可以用到指针类型数据, 但通常只用== 和 !=
1 语法
p1 == p2
2. 操作数类型
p1和p2类型相同
3. 运算法则
比较p1和p2中的地址
4. 结果
布尔值
注意:指针的[]运算
1.语法:p[n]
2.操作数类型:p 必须为指针或数组,n 必须为整数
3.运算法则:p[n] <==> *(p + n)
1.10指针常量
1.10.1定义:只读的指针变量
例子:
int a = 0;
int * const p1 = &a;(1)
const int *p2 = &a; (2)
int const *p3 = &a; (3)
const int * const p4 = &a; (4)
(1)中p1锁定,不能p++,或者p=p+1等操作
(2)中 int被锁定,a的值不能被修改,但p可以操作
(3)同(1)
(4)同(1)+(2)
注意:const int i;
int *const p = &i;//出现警告,因为是常量,但p认为,他的目标是可读可写,权限增加
1.11 数组 vs 指针
1.11.1 概念
指针数组: int * pa[5]; //实质是数组,数组的元素是指针
数组指针: int (*pa)[5]; //实质是指针,目标类型是个数组
数组的指针:数组的指针是指数组在内存中的起始地址,即第一个数组元素的地址。
1.11.2 一维数组 vs 指针
(1) 数组名, 在运算中(定义和声明除外都其他情况都是运算,但sizeof和&运算外), 可以被理解成指向第1个元素的指针(常量)
(2) a[n] 等价于 *(a + n)
(3) &a[n] 等价于 a + n
总结:数组类型和指针类型都可以做[]运算
指针变量和数组在访问数组中元素时,一定条件下其具有相同的形式,因为指针变量和数组名都是地址量。但指针变量和数组的指针(或叫数组名)在本质上不同,指针变量是地址变量,而数组的指针是地址常量
理解:由a[n]是一维数组可以得到:
(1) &a[n][0] 等价于 a[n]
即: a[n], 在运算中, 可以被理解成a[n][0]的指针
即: int *pl = a[n]; 语法正确
(2) a[n][m] 等价于 *(a[n] + m)
1.12字符指针与字符串
初始化字符指针是把内存中字符串的首地址赋予指针,并不是把该字符串复制到指针中。
注意:在C编程中,当一个字符指针指向一个字符串常量时,不能修改指针指向的对象的值。
补充:多级指针:指向指针的指针