09指针
1.指针的概念和变量的地址
-
变量的内存地址
内存中的每个字节都有唯一的编号(地址)地址按字节编号,其字长一般与主机相同32位机使用32位地址,最多支持2^32字节内存(4G)
- 地址是一个无符号整数,从0开始,依次递增。在表达和交流时,通常把地址写成十六进制数,如
0x0037b000
- 地址是一个无符号整数,从0开始,依次递增。在表达和交流时,通常把地址写成十六进制数,如
-
直接寻址:按变量的地址直接访问:
&a -
间接寻址:通过存放变量地址的其他变量访问该变量
-
指针(Pointer)类型
-
指针变量——具有指针类型的变量
-
变量的指针←→变量的地址
-
保存32位地址值的指针变量占4个字节的内存,这4个字节中保存了一个地址
-
从这个地址开始多少个字节内的数据是有效的呢?用什么数据类型去理解这些数据呢?
- 指针的基类型就是回答这个问题的
1
2int *pa,*pb;//定义了可以指向整型数据的指针变量pa和pb
char *pc;//定义了可以指向字符型数据的指针变量pc告诉编译器,pa是一个指针变量,占4字节内存,需要用一个int型变量的地址给它赋值,但pa并未具体指向某个int型变量
-
-
2.指针变量的定义和初始化
-
指针变量使用之前必须初始化(指针变量只能指向同一基类型的变量)
如果你不知把它指向哪里,那就指向NULL
1
int *pa=NULL;
-
空指针:值为NULL的指针,即无效指针
既然0(NULL)用来表示空指针,那么空指针就是指向地址为0的单元的指针吗?
答案:不一定
每个C编译器都被允许用不同的方式来表示空指针,并非所有编译器都使用0地址。某些编译器为空指针使用不存在的内存地址,硬件会检查出这种试图通过空指针访问内存的方式 -
初始化指针变量
pa=&a或int *pa=&a; 后者等价于:1
2
3int a;
int *pa=NULL;
pa=&a;
3.取地址和间接寻址运算符
- 引用指针指向的变量的值,称为指针的解引用(Pointer Dereference)
4.指针变量作函数参数
-
普通变量作函数参数—按值调用,实参的值不随形参值的改变而改变
-
形参(parameter)← 实参变量的值
-
Fun(arg);
-
-
指针做函数参数—按地址调用,为了在被调函数中修改其无法直接访问的实参的值
-
指针形参(pointer parameter) ← 实参变量的地址
-
Fun(&arg);
-
5.函数指针
-
函数指针(Function Pointer):指向函数的指针变量
-
数据类型 (*指针变量名)(形参列表);
int (*f)(int a, int b); -
函数指针f指向的函数原型为:
int 函数名(int a, int b); -
原理:编译器将不带()的函数名解释为该函数的入口地址,函数指针变量存储的是函数在内存中的入口地址,令
f = Fun,就是让f指向函数fun()
-
1 | void Fun(int x, int y, int (*f)(int, int)); |
6.指针与一维数组间的关系
int a[5];
int *p = a;
数组名是数组的首地址
int *p = &a[0];
&a[0]是整型元素的地址
p是整型指针 a[0]的类型和p的基类型相同
- 数组元素的等价引用形式:
a[i] ↔ *(a+i)
7.指针与二维数组间的关系
- 数组法及其变式
1 | //数组法1 |
- 列指针法
1 | //列指针的定义方法 |
| 语法 | 样例 | 说明 | |
|---|---|---|---|
| 指向任意元素 | 指针变量=&数组名[下标1][下标2] | p=&a[1][2] | p指向的元素为7 |
| 指向首个元素 | 指针变量=&数组名[0][0] 指针变量=*二维数组名 |
p=&a[0][0]或p=*a | p指向首个元素,即数值1所在位置 |
| p | p+1 | p+2 | p+3 |
|---|---|---|---|
| p+4 | p+5 | p+6 | p+7 |
| p+8 | p+9 | p+10 | p+11 |
| 表示方法 | 说明 | 指针类型 |
|---|---|---|
| a[0] | 是一维数组名称,首地址 第0个元素地址(a[0]+0) |
列指针 |
| a[0]+1 | 第0行,第1个元素 | 列指针 |
| a[0]+2 | 第0行,第2个元素 | 列指针 |
| a[0]+3 | 第0行,第3个元素 | 列指针 |
- 行指针法
int (*p)[3]; //行指针,基类型是int[3]
1 | //行指针的定义 |
二维数组的名字默认是行指针
| 表示方法 | 说明 | 指针类型 |
|---|---|---|
| a或a+0 | 指向第0行 | 行指针 |
| a+1 | 指向第1行 | 行指针 |
| a+2 | 指向第2行 | 行指针 |
-
行指针和列指针的联系
-
行指针:指的是一整行,不指向具体元素
-
列指针:指的是二维数组中某一行的某个具体元素。
-
可以将列指针认为是行指针的具体元素,行指针是列指针的地址。
-
两者间的具体转化:
-
*行指针—>列指针
-
&列指针—>行指针
-
| 行指针 | 转换成:列指针 |
|---|---|
| a或a+0 | *a或a[0] |
| a+1 | *(a+1)或a[1] |
| 列指针解引用 | 内容等价表示 | 含义 |
|---|---|---|
| *a[0] | *(*a) | a[0][0] |
| *a[1] | *( *(a+1)) | a[1][0] |
| 某一行的列指针 | 转换成:某一行的行指针 |
|---|---|
| a[0] | &a[0]或&a或&(a+0) |
| a[1] | &a[1]或&(a+1) |
行指针和列指针转换试验结果(uninportant)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 //列指针的定义方法
int *p;
//初始化方法
//初始化:指向第一个元素:(以下三个方法等价)
p=a[0] ; p=*a ; p=&a[0][0];
//初始化:指向任意一个元素:
p=a[i][j];p=a[2][1];
//目前p是列指针是吧 根据:&列指针==行指针 发现只有用[]的方法表示的时候才可以实现
(&p)[i][j]==a[i][j];//试验可行
*(*(&p+i)+j)==a[i][j]; *(&p+i)+j==&a[i][j];//试验不可行
*(&p[i]+j)==a[i][j]; &p[i]+j==&a[i][j];//试验可行
(*(&p+i))[j]==a[i][j];//试验不可行
//行指针的定义
int (*p)[4];
//行指针的初始化(a为某数组)(二者任选其一即可)
p=a; p=&a[0];
//目前p是行指针吧 根据:*行指针==列指针 发现均可以实现
*(*p+i*n+j)==a[i][j]; *p+i*n+j==&a[i][j];//试验可行
(*p)[i*n+j]==a[i][j]; //试验可行
8.指针数组及其应用
-
形参声明为二维数组的行指针,列数须为常量

-
形参声明为二维数组的列指针,列数可为变量
