当前课程知识点:高级语言程序设计 >  指针 >  6.7 指针与二维数组 >  指针与二维数组

返回《高级语言程序设计》慕课在线视频课程列表

指针与二维数组在线视频

指针与二维数组

下一节:为什么要自定义函数

返回《高级语言程序设计》慕课在线视频列表

指针与二维数组课程教案、知识点、字幕

那么数组名是指针

我们看一看

二维数组名那又是一个什么样的指针呢

一维数组名是指针

二维数组名是一个什么样的指针呢

要把这个理解清楚

我们必须通过和一维数组的比较

这样通过比较

我们容易来认识清楚这一点

我们看一看

如果定义的是一个二维数组是这样的

int a[3] [4]

也就是一个三行四列的二维数组

数组名是a

数组元素的类型是int

那么它的内存里面这个存取

对应的矩阵是这样的

它的内存的程序是这样

a[0][0] a[0][1] a[0][2] a[0][3]

a[1][0] a[1][1] a[1][2] a[1][3]

a[2][0] a[2][1] a[2][2] a[2][3]

它对应的矩阵

那么在内存里面存取的时候

我们可以用一个a[0]

那大家注意观察

这个第一行

第一行

这些名称里面有共同的部分a[0]

第二行这些名称里面有一个共同的部分a[1]

第三行这些名称里面有共同的部分a[2]

实际上这个a[0] a[1] a[2]是有意义的

它们是一个指针

今后我们就知道它是称为二维数组

对应的这个矩阵里面的每一行的指针

我们叫行指针

第一行的行指针就是a[0]

第二行的行指针就是a[1]

第三行的行指针就是a[2]

那么a是整个二维数组的首地址

那么我们也可以看出

它是指向a[0] a[1] a[2]这个指针

那么我们把a[0] a[1] a[2]理解称为指针的话

那这个就可以看成是一个指针的数组

是一个一维的指针数组

有三个元素

每一个元素

就是我们这对应的这个一行的行指针

那么a[1]实际上

就相当于是一个指向一个指针数组的指针

指向一个一维指针数组的指针

在C语言中

我们把二维数组中每一行

实际上是当做一个一维数组来处理的

也就是说二维数组

可以理解成为元素是一维数组的一维数组

那a就是指向了我们第一行

因为a在这里相当于a加0

相当于a[0]

所以a是这样

a+1那就指向第二行

a+2就指向第三行

那么对应的存储映射是我们看一看

a就是这个二维数组

这一块连续存储区的首地址

那a+1

根据前面的推理

它实际上就是a[1]的值

那么它就是我们第二行的行指针

它指向第二行的第一个元素a[1][0]

依次类推

a+2就指向第三行的第一个元素

也就是a[2][0]

那么在真正我们经过C语言的翻译编译的时候

是怎么保证a+1恰好移动一行的呢

那么如果我们是把数组名a

二维数组名a[i]

理解成为指针的指针是不行的

没有办法保证的

a+1恰好移动一行

因为根据前面我们所学的指针的运算

a+1是指向同类型的

下一个同类型的

那要a

如果是指向一个int类型的

这个指针的指针的

那a+1那是不行的

如果a是int类型的指针的指针

那a+1就不可能恰好移动一行

那你必须是一个指向一维数组

什么样的一维数组

就恰好是你这一行有几个元素

每一个元素是什么类型

是这样的一个

所以在这里我们就得出来

二维数组a是一个指向一维数组的指针

我们注意这里的元素的个数

必须是我们定义的二维数组的列数

这样我们把二维数组名的是一个什么样的指针

理解清楚了之后

下面我们就用指针来访问

二维数组就好办了

我们就会有针对性的

第一个方法

我们用指针数组加指针的指针来访问二维数组

我们先看这个程序

程序是这样的

#include

#include

#include

int main()

在这里我们定义一个二维数组a三行四列的

数组元素的类型是int的类型

我们给它初始化

第一行分别初始化为1 2 3 4

第二行是5 6 7 8

第三行9 10 11 12

而接着定义int的类型的变量i j

那么我们看一看

我们定义一个指针数组和指针的指针

一个指针数组是P

int *p[3]

p优先和中括号结合

所以p是一个数组

int*是数组中元素的类型

所以p是一个指针数组

逗号 **q

q就是一个指向int类型的指针的指针

我们可以把p的值赋值给q

因为p在这里是一个数组

这个数组已经刚才已经定义了

那么经过系统分配

这个p的值就已经有了

我们把p的值赋值给q

这是允许的

因为p是指向的

这个数组p里面的第一个元素p[0]

它是p[0]的地址

那么它是一个指针

这是一个指针

p[0]是一个指针

p[0]的地址赋值给q

那就是指针的指针类型也一致

for(i=0;i<3;i++)

那么花括号里面我们就可以把a[i]的值送给P[i]

这里由于a是二维数组

a[i]实际上就是行指针

a[i]的值实际上就是a+a[i]

然后在指针运算

那么数组p里面三个元素

分别指向了二维数组a里面的第一行

第二行

第三行

p[0]指向数字a的第一行

p[1]指向数组a的第二行

那么p[2]指向数组a的第三行

for(j=0;j<4;j++)

那么我们就可以用q[i][j]来代替a[i][j]

为什么可以用q[i][j]来代替a[i][j]

刚才我们再来看看上面的代码

我们是把p赋值给了q的

根据我们前面所学的推导的知识

那q[i]就相当于p[i]

不看这个p[j]

q[i]就相当于是p[i]

p[i]就相当于是a[i]

那q[i][j]那当然就相当于a[i][j]

根据我们的推导

因此我们就利用指针的指针q

来实现了对这个二维数组的访问

这里面每一次赋值的时候

大家主要要注意地址的类型匹不匹配

我们可以把这个#include这个头文件带上

在Visio C++里面

我们可以通过puts(typeid(变量名).name());输出来

这个数据的类型

来判断检查一下刚才的类型是不是一致

地址的类型是否不一致

如果地址的类型不一致

也就是指针的类型不一致

那么是不能赋值的

那么赋值的也不会翻译

这是我们的方法1

用指针数组加指针的指针来访问

在指针的指针的时候

我们看一看

刚才用指针数组叫指针的指针的方法来访问了

它实际上是怎样实现的

我们看看这个示意图

这边是二维数组a

它对应的矩阵

那么p[0] p[1] p[2]

当我们把a[i]的值赋给p[i]的时候

那么p[0]就指向了二维数组a的第一行

那p[1]就指向了二维数种a的第二行

p[2]指向了二维数组a的第三行

由于p是指我们是把p赋值给了q

q就是指向这个一维数组

所以我们这个q[i]就相当于p[i]

q[i][j]那当然就相当于a[i][j]

因此我们这个运行结果

大家可以看看

输出来的结果

就和我们用这个数组下标的方法

输出的结果是一样的

1 2 3 4 5 6 7 8 9 10 11 12

恰好是这个二维数组

好这是指针数组加指针的指针的方法

访问这个二维数组

把刚才的这个访问过程我们做一个小结

我们看一看它是怎么来做到访问二维数组的

二维数组a

那么它对应的矩阵是这个样子

我们前面讲了a[0]是第一行的指针

a[1]是第二行的指针

a[2]就是第三行的指针

当我们把a[i]赋值给p[i]的时候

那么p[0]就指向了第一行

p[1]就只成了第二行

p[2]就指向了第三行

也就是p[i]就相当于a[i]

由于q是指向这个一维数组p的指针

q它是指针的指针

但是我们是把p赋值给了q

把p复制q

因为P的值

p是这个一维数组的数组

那么p的值实际上它就是放的

就是指向就是p[0]

因为p指向的是p[0]

所以p就是p中

那q就相当于p[0]

那q[i]就相当于p[i]

所以q[i][j]就相当于a[i][j]

那么过程是这样

q[i]那么等价于跟我们前面学习q+i*

做一次指针运算

那么由于我们把P的值赋给q了

那q+i作指针运算

就相当于p+i作指针运算

那p+i作指针运算

当然它等价于p[i]

前面我们学了p[i]就是p+i组成的

由于我们是把a[i]赋值给p[i]

所以p[i]那就相当于a[i]

那q[i][j]当然就等于a[i][j]

这个推导是这样的

那么这是用指针的数组

加指针的指针来访问二维数组

把刚才的过程我们做个小结

注意在定义运算符的时候

在定义的时候

运算符的结合与指针运算过程中这个类型的变化

运算符的一个作用

在上面数据定义里面

int *p[3]

由于中括号的优先级高于*

*是个单目运算的

中括号和圆括号是同一个优先级

当然高于*

所以p优先于中括号

那p就是一个数组

因为中括号是数组的标志

余下的这个int*就是数组p里面的元素的类型

所以p就是一个长度为3

也就是有三个元素

每一个元素的类型

是int*的这样的一个数组

所以它就是指针数组

这是一个

那么今后我们要判断一个标识符是数组

还是指针

还是函数

我们首先要看定义的时候

标识符是优先和*

还是和中括号

还是先和圆括号结合

如果先和*结合的

那是指针

先和中括号结合就是数组

先和圆括号结合的是函数

那么用运算符的优先级结合方向

我们来判断得先和谁结合

上面这个例子里面q是int*类型

也就是指针的指针变量

q+i仍然是int**的类型

q+i在组指向的对象

也就是q[i]

这个虽然还是指针

但是它指针的类型变成了int*

从指针的指针变成了一个int类型的指针

由于p是数组

它本来是指向一个有三个元素的

每一个元素是指针的

这样的数组

那么由于p是这个数组的首地址

也就是p[0]

它的地址

所以p看这里

当它赋值给q的时候

它就转化成了一个int**的指针

p是p[0]的地址

p[0]本来是一个int*的指针

那么p赋值给q这个类型是匹配的

C语言认为

p[i]的类型是int*

那么p[i][j]的类型就是int

p[i]是int类型的指针

那p[i][j]在做的一次指向的运算

指向对象的运算

也就是一个指针运算

就是int类型

访问的就是a[i][j]

这是我们用的指针数组

加指针的指针的方法访问二维数组

下面我们看看另外一种方法

方法2

用数组指针来访问二维数组

那么数组的指针如何来访问二维数组呢

我们来看看这个例子

程序是这样的

#include

#include

#include

int main()

花括号

a[3][4]

那么和刚才方法1里面是同一个二维数组

那么三行四列

第一行的值是1 2 3 4

第二行的只是5 6 7 8

第三行的只是9 10 11 12

下面我们看一看它怎么用数组的指针来访问的

int i,j

int (*p)[4]

在这里注意到p和*我们加了圆括号

那么p优先和*结合

所以p首先是一个指针

剩下来的int [4]

那就是P指向的对象的类型

因此P是一个指向对象

是一维数组的指针

我们把这样的点简称为数组指针

由于p的类型和a的类型一致

在前面我们讲的时候

我们讲到a

二维数组a的理解的时候

a就是一个int[4]

这个指向这样的一个一维数组的指针

所以p和a是同一个类型

那么我们就可以把a赋值给p

无非p是指针变量

a是指针常量

都是指向一维数组的指针

因此我们可以这样来访问了二维数组元素

a[i][j]

for(i=0j;i<3;i++)

for(j=0;j<4;j++)

调用格式输出函数printf( "%d\t"p[i][j]);printf("\n")

那p[i][j]访问了a[i][j]

因为p和a

无非一个是指针变量

一个是指针常量

p和a是同一个类型

能用a[i][j]输出二维数组中的元素

那当然就可以用p[i][j]来输出了

那么运行结果我们可以看到

恰好就实现了输出的二维数组

1 2 3 4 5 6 7 8 9 10 11 12

那么在这里

大家可以看一看

这个对这个p和a来访问

p和a的这个效果里面

p[i][j]就相当于是a[i][j]

那么大家可以在加深的来理解一下

因为刚才这个意思在这里已经指出来了

p优先与*结合

所以p是一个指针

那么它是一个什么样的指针呢

指向一个一维数组的指针

这个一维数组元素有四个

每一个元素是int类型

它和a是同一个类型

因此p+1就相当于a+1

p[i]就等效于a[i]

p[i][j]接呢就等下a[i][j]

我们把这个用数组的指针的方法

访问二维数组讲完了

谢谢大家

高级语言程序设计课程列表:

程序设计和C语言

-1.1 计算机程序和计算机语言

--计算机程序和计算机语言

--致敬先辈:伟大的C语言之父——丹尼斯·里奇 程序员

-1.2 C程序的构成

--C程序的构成

--当前主流程序设计语言各自都有什么优势?

-1.3 C语言编辑、编译、运行(VC++2010学习版)

--C语言编辑、编译、运行(VC++2010学习版)

-练习题

顺序结构程序设计

-2.1 变量的定义和使用

--变量的定义和使用

-2.2 数据类型

--数据类型简介

--整型数据

--实型数据

-2.3 格式输出和格式输入

--格式输出printf函数

--格式输入scanf函数

--单个字符的输入输出

-2.4 运算符和表达式

--运算符和表达式

-2.5 结构化程序设计入门

--结构化程序设计入门

-练习题

选择结构程序设计

-3.1 为什么要用选择结构解决问题

--为什么要用选择结构解决问题

-3.2 如何正确表示选择结构中的条件

--如何正确表示选择结构中的条件

-3.3 用if语句及if语句嵌套实现选择结构

--用if语句及if语句嵌套实现选择结构

-3.4 用switch语句实现选择结构

--用switch语句实现选择结构

-练习

循环结构程序设计

-4.1 循环的引入

-- 为什么要用循环结构解决问题

-4.1 循环的引入--作业

-4.2 用while语句实现循环

--用while语句实现循环

-4.3 用do-while语句实现循环

-- 用do-while语句实现循环

-4.4 用for语句实现循环

-- 用for语句实现循环

-4.4 用for语句实现循环--作业

-4.5 何时需要用循环的嵌套

--何时需要用循环的嵌套

-4.6 如何提前终止循环和提前结束本次循环

--如何提前终止循环和提前结束本次循环

-习题--作业

数组

-5.1 数组类型的引入

--数组类型的引入

-5.2 一维数组的定义和初始化

--一维数组的定义和初始化

-5.3 一维数组的使用

--一维数组的使用

-5.4 二维数组的定义和初始化

--二维数组的定义和初始化

-5.5 二维数组的使用

--二维数组的使用

-习题--作业

指针

-6.1 什么是指针

--什么是指针

-6.2 指针类型及相关概念

--指针类型及相关概念

-6.3 指针变量的定义、赋值与使用

--指针变量的定义、赋值与使用

-6.4 指针的运算

--指针的运算

-6.5 指针与一维数组

--指针与一维数组

-6.6 指针的指针

--指针的指针

-6.7 指针与二维数组

--指针与二维数组

-习题--作业

函数

-7.1 为什么要自定义函数

--为什么要自定义函数

-7.2 函数的定义

--函数的定义

-7.3 函数的调用

--函数的调用

-7.4 函数参数的传递

--函数参数的传递

-7.5 函数的嵌套调用和递归调用

--函数的嵌套调用和递归调用

-7.6 变量的作用域和存储类型

--变量的作用域和存储类型

-习题--作业

字符串

-8.1 字符串的存储及输入输出

--字符串的存储及输入输出

-8.2 系统字符串处理函数

--系统字符串处理函数

-8.3 自定义字符串处理函数

--自定义字符串处理函数

-习题--作业

结构体和共用体

-9.1 结构体类型的定义

--结构体类型的定义

-9.2 结构体变量及指针变量的定义及使用

--结构体类型变量和指针变量的定义和使用

-9.3 结构体变量和指针变量作函数的参数

--用结构体变量和指向结构体的指针作函数参数

-9.4 结构体数组的定义和使用

--结构体数组的定义和使用

-9.5 共用体类型和枚举类型

--共用体和枚举类型

-习题--作业

动态内存分配

-动态内存分配--习题

文件

-习题--作业

指针与二维数组笔记与讨论

也许你还感兴趣的课程:

© 柠檬大学-慕课导航 课程版权归原始院校所有,
本网站仅通过互联网进行慕课课程索引,不提供在线课程学习和视频,请同学们点击报名到课程提供网站进行学习。