目录
[1.1 指针的使用](#1.1 指针的使用)
[1.2 地址](#1.2 地址)
[1.3 指针](#1.3 指针)
[1.1 概述](#1.1 概述)
[1.2 声明](#1.2 声明)
[1.3 赋值](#1.3 赋值)
[1.4 指针占几个字节?](#1.4 指针占几个字节?)
[1.4 算术运算](#1.4 算术运算)
[2.1 遍历一维数组](#2.1 遍历一维数组)
[2.1.1 练习使用](#2.1.1 练习使用)
[2.1.2 疑难点](#2.1.2 疑难点)
[2.2 指针与二维数组](#2.2 指针与二维数组)
[2.2.1 回顾二维数组](#2.2.1 回顾二维数组)
[2.2.2 二维数组的三种形式](#2.2.2 二维数组的三种形式)
[2.2.3 行指针](#2.2.3 行指针)
1.指针概述
1.1 指针的使用
使用指针可以
① 使程序简洁、紧凑、高效
② 有效地表示复杂的结构
③ 动态分配内存
④ 得到多于一个的函数返回值
1.2 地址
在计算机内存中,每一个字节(即 8 比特,1 Byte = 8 Bit),都有一个编号,即地址。
即内存以字节为单位进行编号

1.3 指针
1.1 概述
指针就是内存单元的地址(即 内存以字节为单位进行编号,这个编号就叫做地址)
专门用来存放地址的变量即指针变量,相当于编号
1.2 声明
声明格式为:存储类型 数据类型 *指针变量名;
<下图是指针的声明,可以借鉴整型的声明;

<下图代码验证 p = &a;

指针变量也要占据存储空间

于是,可以这样理解:

引入指针时,注意程序中三种表示方法的不同意义:

<以下代码

1.3 赋值
给指针变量赋值,值必须是地址常量(如 数组名) / 指针变量 /0
不能是普通的整数
即只可以
①将一个已有地址值的指针变量赋给具有相同数据类型的另一个指针变量
②把一个数组的地址赋给具有相同数据类型的指针
③ 0

1.4 指针占几个字节?
64 位操作系统指针占 8 个字节
32 位操作系统指针占 4 个字节
与指针的数据类型无关

1.4 算术运算
指针运算的实质是对地址的操作
仅包括 赋值运算,算术运算,关系运算
(1):+ 与 - ;

① px + / - n :px + / - sizeof( px 的类型) * n ;
<下图是验证:

② px - py :两指针相减表示相隔数据的个数;

③ 指针++,++指针
指针++:先赋值再运算;
++指针:先运算再赋值;
<下图是验证:稍微简单的 指针++

<下图是验证:指针++ 之后再复制;

2.指针遍历
2.1 遍历一维数组
a[i] p[i] *(p+i) *(a+i) 具有完全相同的功能:访问数组第 i 个元素;
有以下说明:
① p + i :这是指针与常量的算术运算,结果为地址:( p + 该数据类型所占字节 * i )
*( p + i ) 则是 p + i 所指地址的内容;
对于 *( a + i ):
p 是一个地址,可以参与算术运算
a 也是一个地址,当然也可以参与算术运算
且 p = a;
只不过 a 是常量, p 是变量,且 a 参与算数运算过程中并没有改变自身的值;
其他可由 p = a ,亦可推导而来;
② 这并不违反数组地址是常量不可修改。
a 是数组名,是数组起始地址,是地址常量,不可更改;
在 *( a + i ) 中, (a + i ) 并不等于 a = (a + i),只是借助 a 的地址进行运算,并没有修改 a 的地址
③ a 与 p 在使用上是相同的,但也存在一些区别:
如 a 是数组名,是一个常量,不可以 a++,a--
p 是指针变量,是一个变量,可以进行任何算数运算,包括 ++ ,--

<以下代码是验证上述四种形式的表达是否一致:

2.1.1 练习使用
-
<以下 数组与指针的联合使用 恰恰体现了指针灵活方便 的优点:
-
首先注意输入与输出的格式;
-
其次注意第十行,若没有该行代码,则结果不正确;
原因如下:第九行结束时 pa = & a [ 6 ],若不重新置为 a [ 0 ],接下来 *pa++ 要输出
a[6] 到 a[11] 数组元素的值,但 C 语言没有对数组溢出报错,结果会随机赋值;
- 第 9 行:pa++ 相当于 &a[ i ++ ] ;
第 12 行 *pa++,++ 的优先级远远大于 *,相当于 *(pa++);

- 该题较好的考察其知识点;

- 数组逆序输出
<以下是数组的逆序输出:
循环判断条件:p < d;

2.1.2 疑难点
<如下,p[ 1 ] = 5,不等于 3;
博主暂时没有明白,若有告知,请留言

2.2 指针与二维数组
2.2.1 回顾二维数组
首先回顾一下二维数组:
二维数组元素连续存储 ,以行优先;
如下,在计算机中的存储如右图所示,但为了方便,我们一般按照左图书写

2.2.2 二维数组的三种形式
方式一:一般思维,将二维数组 int a [ m] [ n ] 含有 m*n 个元素按平常方法遍历出来;
在遍历二维数组之前须搞懂一个问题:p = a 合适吗?

从结果看,并不合适;
p = &a[0][0] 才是正确的;
据此遍历:

方式二:二维数组的地址是连续的
如 int a [ 3 ][ 2 ] 可以看作六个地址连续的元素,即长度为 6 的一维数组,数组名即起始地址;

我们来验证一下,a【0】是什么?

可以看到,a[0] 是看作 "一维数组" 的起始地址
a[ 0 ] + 1 ,地址指向下一位,而非下一行;
<据此遍历,代码如下:

方式三:行指针遍历二维数组(见 2.2.3);
二位数数组由多个一维数组组成;
数组名 + 1,移动一行元素;
因此,二维数组名( a[ 0 ] , a[ 1 ],a[ 2 ])常被称为行地址

<以下是重要代码:

2.2.3 行指针
行指针即数组指针;
存储行地址的指针变量,叫做行地址变量;
在 int a[ 2 ][ 3 ] ;int ( *p )[ 3 ] 中,p = a 就合情合理了;
<代码验证如下:a == p; a + 1 == p + 1 ;该两行可证

行指针遍历二维数组:
