C语言多维数组

文章目录

  • 多维数组
    • 数组名
    • 下标
    • 指向数组的指针
    • 作为函数参数的多维数组
  • 指针数组
  • 小结

多维数组

如果某个数组的维数超过1,它就被称为多维数组,例如,下面这个声明:

int matrix[6][10]

创建了一个包含60个元素的矩阵。但是,它是6行每行10个元素,还是10行每行6个元素?
为了回答这个问题,你需要从一个不同的视点观察多维数组。考虑下列这些维数不断增加的声明:

int a;
int b[10];
int c[6][10];
int d[3][6][10];

a是个简单的整数,接下来的那个声明增加一个维数,所以b就是一个向量,它包含10个整形元素。

c只是在b的基础上再增加一维,所以我们可以把c看做是一个包含6个元素的向量,只不过它的每个元素本身是一个包含10个整形元素的向量。换句话说,c是个一维数组的一维数组。d也是如此,它是一个包含三个元素的数组,每个元素都是包含6个元素的数组,而这6个元素中的每一个都是包含10个整形元素的数组,间接地说,d是一个3排6行10列的整形三维数组。

·

数组名

一维数组名的值是一个指针常量,它指向数组的第一个元素,它的类型是“指向元素类型的指针” 。多维数组也差不多简单,唯一的区别是多维数组第1维的元素实际上是另一个数组。例如,下面这个声明:

int matrix[3][10];

创建了matrix,它可以看做是一个一维数组,包含3个元素,只是每个元素恰好是包含10个整形元素的数组。
matrix这个名字的值是一个指向它第一个元素的指针,所以matrix是一个指向一个包含10个整型元素的数组的指针。

下标

如果要标识一个多维数组的某个元素,必须按照与数组声明时相同的顺序为每一维都提供一个下标,而且每个下标都单独位于一对方括号内。在下面的声明中:

int matrix[3][10];

表达式matrix[1][5]访问下面这个元素
在这里插入图片描述

但是,下标引用实际上只是间接访问表达式的一种伪装形式,即使在多维数组中也是如此,考虑下面这个表达式:

matrix

它的类型是“指向包含10个整型元素数组的指针”,它的值是
在这里插入图片描述
表达式 matrix+1也是一个“指向10个整型元素数组的指针”,但它指向matrix的另一行
在这里插入图片描述
为什么?因为1这个数值根据包含10个整型元素的数组的长度进行调制,所以它指向matrix下一行,如果对其执行间接访问,就如下图随箭头选择中间的这个子数组
在这里插入图片描述
所以表达式*(matrix+1)事实上标识了一个10个整型元素的子数组。数组名的值是个常量指针,它指向数组的第一个元素,在这个表达式中也是如此。它的类型是“指向整型的指针”,我们现在可以在下一维的上下文环境中显示它的值。
在这里插入图片描述
现在请拿稳你的帽子,猜猜下面这个表达式的结果是什么?

*(*(matrix+1)+5)

它所访问的正是那个整型元素。如果它作为右值使用,你取得存储于那个位置的值,如果它作为左值使用,这个位置将存储一个新值。
这个看上去吓人的表达式实际上正是我们的老朋友–下标,我们可以把表达式*(matrix+1)改写成matrix[1],把这个下标表达式带入原先的表达式,我们将得到:

*(matrix[1]+1);

这个表达式完全合法的,matrix[1]选定一个子数组,所以它的类型是一个指向整型的指针,我们对这个指针加上5,然后执行间接访问操作。
但是,我们可以再次用下标代替间接访问,所以这个表达式还可以写出:

matrix[1][5]

指向数组的指针

下面这些声明合法吗?

int vector[10],*vp = vector;
int matrix[3][10],*mp = matrix;

第一个声明是合法的。它为一个整型数组分配内存,并把vp声明一个指向整型的指针,并把它初始化为指向vector数组的第一个元素。vector和vp具有相同的类型:指向整型的指针。但是第2个是非法的。它正确地创建了matrix数组,并把mp声明为一个指向整型的指针。但是mp的初始化是不正确的,因为matrix并不是一个指向整型的指针,而是一个指向整型数组的指针。我们应该怎样声明一个指向整型数组的指针呢?

int (*p)[10];

下标引用的优先级高于间接访问,但由于括号的存在,首先执行的还是间接访问。所以p是个指针,但它指向什么呢?
接下来执行的是下标引用,所以p指向某种类型的数组。这个声明表达式中并没有更多的操作符,所以数组的每个元素都是整数。
声明并没有直接告诉你p是什么,但推断它的类型并不困难,当我们对它执行间接访问操作时,我们得到的是个数组,对该数组进行下标引用操作得到的是一个整型值。所以p是一个指向整型数组的指针

在声明中加上初始化后是下面这个样子:

int (*p)[10] = matrix;

它使p指向matrix的第一行。

作为函数参数的多维数组

作为函数参数的多维数组名的传递方式和一位数组名相同,实际传递的是个指向数组第一个元素的指针。但是,两者之间的区别在于,多维数组的每个元素本身是另外一个数组,编译器需要知道它的维数,以便为函数形参的下标表达式进行求值。这里有两个例子,说明了它们之间的区别:

int vector[10];
... 
func1(vector);

参数vector得我类型是指向整型的指针,所以func1的原型可以是下面两种的任何一种:

void funcl(int *vec);
void func1(int vec[]);

作用于vec上面的指针运算把整型的长度作为它的调整因子。
现在让我们来观察一个矩阵:

int matrix[3][10];
...
func2(matrix);

这里matrix的类型是指向包含10个整型元素数组的指针。func2的原型应该是怎样的呢?你可以使用下面两种形式中的任何一种:

void func2(int (*p)[10];
void func2(int mat[][10]);

在这个函数中,mat的第一个下标根据包含10个元素的整型数组的长度进行调整,接着第2个下标根据整型的长度进行调整,这和原先的matrix数组一样。

在编写一维数组形参的函数原型时,你既可以把它写成数组的形式,也可以把它写成指针的形式。但是,对于多维数组,只有第1维可以进行如此选择。尤其是,把func2写成下面这样的原型是不正确的:

void func2(int**mat);

这个例子把mat声明为一个指向整型指针的指针,它和指向数组的指针并不是一回事。

指针数组

除了类型之外,指针变量和其他变量很相似,正如你可以创建整型数组一样,你也可以声明指针数组。这里有一个例子:

int *api[10];

为了弄清楚这个复杂的声明,我们假设它是一个表达式,并对它进行求值。

下标引用的优先级高于间接访问,所以在这个表达式中,首先执行下标引用。因此,api是某种类型的数组,元素个数为10。在取得一个数组元素之后,随机执行的是间接访问操作,这个表达式不再有其他操作,所以它的结果是一个整型值。
那么api到底是什么东西?对数组的某个元素执行间接访问操作后,我们得到一个整型值,所以api肯定是个数组,它的元素类型是指向整型的指针。

小结

一维数组的数组名指向第一个元素,类型是指向元素类型的指针。
二维数组的数组名是也指向它第一个元素,类型是指向数组的指针。
指针的指针是指向某种类型指针的指针,它和指向数组的指针并不是一回事。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/379546.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ubuntu路由器联网_路由器及其协议简介| 联网

ubuntu路由器联网路由器简介 (Introduction to Router) Routers are network layer devices. Data on the network layer is known as packets. Routers work to forward packets from one network to another. Routers also maintain the address table. 路由器是网络层设备。…

XPath学习:轴(5)——descendant-or-self

XPath 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历。 XPath 是 W3C XSLT 标准的主要元素,并且 XQuery 和 XPointer 同时被构建于 XPath 表达之上。 推荐一个挺不错的网站:http://www.zvon.org/xxl/XPathTutorial…

linux设备驱动开发---平台设备驱动程序

文章目录1 平台驱动程序2 平台设备2.1 资源和平台数据1 设备配置---废弃的旧方法资源平台数据声明平台设备2 设备配置---推荐的新方法3 设备、驱动程序和总线匹配OF风格ACPIID表匹配匹配平台设备的名字和平台驱动的名字平台设备和平台驱动程序如何匹配4 Platfrom架构驱动程序有…

标题:乘积尾零

标题:乘积尾零 如下的10行数据,每行有10个整数,请你求出它们的乘积的末尾有多少个零? 5650 4542 3554 473 946 4114 3871 9073 90 4329 2758 7949 6113 5659 5245 7432 3051 4434 6704 3594 9937 1173 6866 3397 4759 7557 3070…

Robots.txt指南

Robots.txt指南当搜索引擎访问一个网站时,它首先会检查该网站的根域下是否有一个叫做robots.txt的纯文本文件。Robots.txt文件用于限定搜索引擎对其 网站的访问范围,即告诉搜索引擎网站中哪些文件是允许它进行检索(下载)的。这就是大家在网络上常看到的“…

fwrite函数的用法示例_C语言中的fwrite()函数(带有示例)

fwrite函数的用法示例C中的fwrite()函数 (fwrite() function in C) Prototype: 原型: size_t fwrite(void *buffer, size_t length, size_t count, FILE *filename);Parameters: 参数: void *buffer, size_t length, size_t count, FILE *filenameRetu…

标题:递增三元组

标题&#xff1a;递增三元组 给定三个整数数组 A [A1, A2, … AN], B [B1, B2, … BN], C [C1, C2, … CN]&#xff0c; 请你统计有多少个三元组(i, j, k) 满足&#xff1a; 1 < i, j, k < NAi < Bj < Ck 【输入格式】 第一行包含一个整数N。 第二行包含N个整…

伙伴算法、slab机制、内存管理函数

文章目录1 伙伴算法页框操作alloc_pages()2 slabslab机制要解决的问题使用高速缓存3 内存管理函数kmallockzallocvmallocvzalloc区别参考文章内核使用struct page结构体描述每个物理页&#xff0c;也叫页框。内核在很多情况下&#xff0c;需要申请连续的页框&#xff0c;而且数…

eval 函数 代替函数_eval()函数以及JavaScript中的示例

eval 函数 代替函数eval()函数 (eval() function) eval() function is a predefined global function in JavaScript and it is used to evaluate (execute) an expression, which is passed to the function as a parameter. It can also evaluate any JavaScript code. eval(…

F# ≥ C#(活动模式 和枚举)

F#提供了一个叫"活动模式"的有趣功能。它把输入的数据转换成其他不同的东西。 一个有趣的使用实例就是代替枚举。但我编程枚举的时候&#xff0c;我总不高兴去链接枚举项到它的定义。例如&#xff0c;下面的枚举定义了 数字枚举&#xff0c; enum Numbers{Odd,Even,}…

关于java的classpath设置

今天晚上实验室的另一个人在编译一个java程序&#xff0c;需要用到一个jar文件&#xff0c;所以在命令行编译的时候需要添加jar的路径&#xff0c;例如&#xff1a; java -classpath demo.jar hello 但是设置了path之后java就不会搜索当前目录&#xff0c;也就是所如果hello在当…

C语言uthash的用法

文章目录1 定义一个哈希表键值UT_hash_handle2 哈希操作声明添加查找删除获取哈希表中元素个数迭代排序3 案例键的使用官网解释&#xff1a;https://troydhanson.github.io/uthash/userguide.html 在使用之前&#xff0c;我们必须包含uthash.h的头文件&#xff0c;你需要将该头…

Javascript Paste Keyboard Shortcuts Hijack

author : kj021320 team : I.S.T.O 这样的攻击手段也算是极其无耻 猥琐之极! 所以防御措施一定要做好 首先说一下通过Javascript Paste Keyboard Shortcuts Hijack能做什么???能够读取你本地机器任何文件! 没错!也就是说 你中了任何一个XSS 加上你按了粘贴快捷键后,你就有可…

python 生成器表达式_Python中的列表理解与生成器表达式

python 生成器表达式The list is a collection of different types of elements and there are many ways of creating a list in Python. 该列表是不同类型元素的集合&#xff0c;并且有许多方法可以在Python中创建列表。 清单理解 (List Comprehension) List comprehension…

Javaweb---监听器

1.什么是监听器 监听器就是监听某个对象的状态变化的组件。 事件源&#xff1a;被监听的对象 ----- 三个域对象 request session servletContext 监听器&#xff1a;监听事件源对象 事件源对象的状态的变化都会触发监听器 ---- 62 注册监听器&#xff1a;将监听器与事件源进行…

Linux中的Ramdisk和Initrd

Ramdisk简介先简单介绍一下ramdisk&#xff0c;Ramdisk是虚拟于RAM中的盘(Disk)。对于用户来说&#xff0c;能把RAM disk和通常的硬盘分区&#xff08;如/dev/hda1&#xff09;同等对待来使用&#xff0c;例如&#xff1a;redice # mkfs.ext2 /dev/ram0mke2fs 1.38 (30-Jun-200…

slab下kmalloc内核函数实现

文章目录kmalloc的整体实现获取高速缓存高速缓存获取index总结https://blog.csdn.net/qq_41683305/article/details/124554490&#xff0c;在这篇文章中&#xff0c;我们介绍了伙伴算法、slab机制和常见的内存管理函数&#xff0c;接下来&#xff0c;我们看看kmalloc内核函数的…

PHP array_merge_recursive()函数与示例

PHP array_merge_recursive()函数 (PHP array_merge_recursive() function) array_merge_recursive() function is used to merge two or more arrays, it returns a new array with merged elements. The only difference between array_merge() and array_merge_recursive() …

标题:三羊献瑞

标题&#xff1a;观察下面的加法算式&#xff1a; 其中&#xff0c;相同的汉字代表相同的数字&#xff0c;不同的汉字代表不同的数字。 请你填写“三羊献瑞”所代表的4位数字&#xff08;答案唯一&#xff09;&#xff0c;不要填写任何多余内容。 思路分析&#xff1a; 首先…

hdu 1069

地址&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid1069 题意&#xff1a;给定若干个木块长宽高&#xff0c;长宽高可以自己调整&#xff0c;求堆积起来最高的高度。 mark&#xff1a;枚举所有木块长宽高可能情况&#xff0c;简单dp。 代码&#xff1a; #include <…