C语言 第八章 指针(上)

第八章 指针(上)

地址和指针的基本概念

内容可变,地址不可变

有了变量的地址,存取变量就可以通过两种方式

  1. 通过变量名
  2. 通过变量的地址
1
2
3
4
5
// 指针变量
int *p;

// 变量类型 int *; 变量名为 p
// 指针变量一律占4个字节

基类型

指针变量所指向的变量的类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int a = 1;
double b = 8.2;

int *p;
double *q;
void *r;

// p为int *型,只能指向int型
p = &a;
// q为double *型,只能指向double型
q = &b;
// r为void *型,可以指向任何类型
r = &a;
r = &b;

指针变量的赋值

指针变量值为0(地址值为0)时,表示什么也不指向 - 空指针。【地址值为NULL也表示空指针】

1
2
int a = 1;
int *p;

赋值语句的方法

1
p = &a;

定义指针变量时初始化(定义时赋初值)

1
2
int b = 2;
int *q = &b;

允许指针变量之间赋值,但另两个指针变量必须基类型相同

1
2
3
q = p;
int *r;
r = q;

特殊情况

1
2
3
4
5
int *p;
// 下面两种情况都表示空指针
p = 0;
// NULL(全大写),系统定义的宏 #define NULL 0
p = NULL;

两运算符(&, *)

&取地址运算符

获取变量的地址,用法:&变量名

*指针运算符(间接访问运算符)

获取或改写以p为地址的内存内容

*p*不是获得或改变指针变量本身的值,而是获得或改写它所指向单元的值。

int *p*运算只能用于指针变量,不能用于普通变量(如*a错误);

&*互为逆运算

1
2
3
4
5
6
7
8
9
10
11
int *p = &a;

p == &a;

*p == *&a == a;

&*p == p;

&*&*&*p == p;

*&*&*&p == a;

数组的指针

指针变量的运算

指向向前或向后移动n个单元,

p+n=p中的地址编号 + (每元素字节数*n)

p-n=p中的地址编号 - (每元素字节数*n)

概运算应只针对指向数组的指针变量进行,否则毫无意义

1
2
3
4
5
6
7
8
int a[5] = {1,2,3,4,5};
int *p;
p = &a[1];
// p++运算后与&a[2]相等
p++;

// p+=2 运算后与&a[4]相等
p+=2;

每个 char 型变量占1个字节,对基类型为char的指针变量+n,恰好是地址+n

1
2
char c[4] = {'a', 'b', 'c', 'd'}
char *p = &c[2];

void 类型的指针不能做+(-)n的运算(也不能++, –的运算)

指针的变量相减

两指针变量的加减乘除运算时没有意义的。

p1 - p2 = (p1中的地址编号 - p2中的地址编号)/镁元素字节数

关系运算

该运算一般只对指向同一数组的元素的两个指针变量进项,表示他们所指向元素的先后位置

1
2
3
4
5
6
7
8
// 表示p1和p2指向数组的同一个元素
p1 == p2

// 表示p1所指元素位于p2所指元素之后;
p1 > p2

// 表示p1所指元素位于p2所指元素之前;
p1 < p2
1
2
3
4
5
6
7
8
9
// 与0和NULL比较

// 表示p为空指针
p == 0;
p == NULL;

// 表示p不是空指针
p != 0;
p != NULL;
数组元素的地址转换为元素下标
1
2
3
4
5
6
int a[5] = {1,2,3,4,5};
int *p, *q;
q = &a[0];
p = &a[2];

p - a 则得2

两个重要公式

语法糖

编译时编译系统将a[i]全部变为*(a+i).

a[i]就是语法糖,便于我们理解而设计的成为语法糖。

1
2
3
4
5
int a[5] = {1,2,3,4,5};

a + i == &a[i];

a[i] == *(a+i)
指针变量可写为数组的形式
1
2
3
4
5
int *p = x[0];

x[i] == *(x+i);

&x[i] == x+i;

指针变量与一位数组名的统一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int a[5];
int *p;

p = a;
p = &a[0];

p[0] == *p == a[0];

p[i] == a[i];
*(p+i) == *(a+i);

p 和 a 不能互相转换
p的值(地址)可被修改,a的值(地址)不能被修改
p是变量,a是假想的“指针变量”(是常量)

指针运算的优先级

&, *的优先级和++, --相同,都非常高,仅次于()

++, --统计运算时,从右至左结合

二维数组的指针

1
2
3
4
5
// 行指针
int (*q)[4];

int a[3][4];
q = a;

一个表格、两句法则

草稿写法±1效果定义
二级指针[[]]移动一行int (*q)[4]; int b[3][4]; 中的b
二级指针[[]]必移动4字节int **r; int *s[3]; 中的s
一级指针[]移动一个单位(int型4字节,char型1字节…)int *p; int a[2]; 中的a
普通变量变量值±1int x;

法则:

  1. 定义变量时:一个*或一个[]升一级
  2. 使用时:一个*或一个[]降一级;一个&升一级

两个重要公式

二维数组元素的写法 a[i][j]*(*(a+i)+j)的语法糖

1
2
3
4
5
6
7
8
9
10
11
x[i] == *(x+i);

&x[i] == x+i;

a[i] == *(a+i) == q[i] == *(q+i);

q[i][j] == *(a[i]+j) == *(*(a+i)+j)==q[i][j] == *(q[i]+j) == *(*(q+i)+j);

特殊的 i=0,j=0
a[0][0] == **a;
&a[0][0] == *a;