09指针

09指针

1.指针的概念和变量的地址

  • 变量的内存地址

    内存中的每个字节都有唯一的编号(地址)地址按字节编号,其字长一般与主机相同32位机使用32位地址,最多支持2^32字节内存(4G)

    • 地址是一个无符号整数,从0开始,依次递增。在表达和交流时,通常把地址写成十六进制数,如0x0037b000
  • 直接寻址:按变量的地址直接访问:&a

  • 间接寻址:通过存放变量地址的其他变量访问该变量

    • 指针(Pointer)类型

      • 指针变量——具有指针类型的变量

      • 变量的指针←→变量的地址

      • 保存32位地址值的指针变量占4个字节的内存,这4个字节中保存了一个地址

      • 从这个地址开始多少个字节内的数据是有效的呢?用什么数据类型去理解这些数据呢?

        • 指针的基类型就是回答这个问题的
      1
      2
      int *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=&aint *pa=&a; 后者等价于:

    1
    2
    3
    int 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
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
27
28
29
30
void Fun(int x, int y, int (*f)(int, int));
int Max(int x, int y);
int Min(int x, int y);
int Add(int x, int y);

int main()
{ int a, b;
scanf("%d,%d", &a, &b);
Fun(a, b, Max);
Fun(a, b, Min);
Fun(a, b, Add);
return 0;
}
void Fun(int x, int y, int (*f)(int, int))
{ int result;
result = (*f)(x, y) ;
printf("%d\n", result);
}
int Max(int x, int y)
{ printf("max=");
return x>y? x : y;
}
int Min(int x, int y)
{ printf("min=");
return x<y? x : y;
}
int Add(int x, int y)
{ printf("sum=");
return x+y;
}

6.指针与一维数组间的关系

int a[5];

int *p = a;

数组名是数组的首地址

int *p = &a[0];

&a[0]是整型元素的地址

p是整型指针    a[0]的类型和p的基类型相同

  • 数组元素的等价引用形式:a[i] ↔ *(a+i)

7.指针与二维数组间的关系

  • 数组法及其变式
1
2
3
4
5
6
7
8
9
//数组法1
a==a+0==&a[0]; *a==*(a+0)==a[0];
a+1==&a[1]; *(a+1)==a[1];
//数组法2
a[0]+1==&a[0][1]; *(a[0]+1)==a[0][1];
//数组法3
*(a+1)+2==&a[1][2]; *(*(a+1)+2)==a[1][2];
//数组法4
(*(a+1))[2]==a[1][2];
  • 列指针法
1
2
3
4
5
6
7
8
9
10
11
12
//列指针的定义方法
int *p;

//初始化方法
//初始化:指向第一个元素:(以下三个方法等价)
p=a[0] ; p=*a ; p=&a[0][0];
//初始化:指向任意一个元素:
p=a[i][j];p=a[2][1];

//列指针的使用方法:(a为m行n列的一个二维数组)
*(p+i*n+j)==a[i][j]; p+i*n+j==&a[i][j];
p[i*n+j]==a[i][j];
语法 样例 说明
指向任意元素 指针变量=&数组名[下标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
2
3
4
5
6
7
8
9
10
11
//行指针的定义
int (*p)[4];

//行指针的初始化(a为某数组)(二者任选其一即可)
p=a; p=&a[0];

//行指针应用公式
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];

二维数组的名字默认是行指针

表示方法 说明 指针类型
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.指针数组及其应用

  • 形参声明为二维数组的行指针,列数须为常量

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