《C和指针》笔记31:多维数组的数组名、指向多维数组的指针、作为函数参数的多维数组

文章目录

  • 1. 指向多维数组的数组名
  • 2. 指向多维数组的指针
  • 3. 作为函数参数的多维数组

1. 指向多维数组的数组名

我们知道一维数组名的值是一个指针常量,它的类型是“指向元素类型的指针”,它指向数组的第1个元素。那么多维数组的数组名代表什么呢?

其实也差不多简单。唯一的区别是多维数组第1维的元素实际上是另一个数组。例如,下面这个声明:

int matrix[3][10];

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

在这里插入图片描述

那么下面各个表达式是什么意思呢?如果你能正确说出来,说明你对多维数组的数组名已经了如指掌了~

  1. matrix + 1

这也是一个“指向包含10个整型元素的数组的指针”,但它指向matrix的另一行:

在这里插入图片描述

为什么?因为1这个值根据包含10个整型元素的数组的长度进行调整,所以它指向matrix的下一行。

  1. *(matrix + 1)

如果对其执行间接访问操作,就如下图随箭头选择中间这个子数组:

在这里插入图片描述
事实上它标识了一个包含10个整型元素的子数组。数组名的值是个常量指针,它指向数组的第1个元素,在这个表达式中也是如此。它的类型是“指向整型的指针”。我们现在可以在下一维的上下文环境中显示它的值:

注意间接访问后还是一个指针,间接访问前是一个指向一维整型数组的指针,间接访问后是一个指向整型的指针。

在这里插入图片描述

  1. *( matrix + 1 ) + 5

前一个表达式是个指向整型值的指针,所以5这个值根据整型的长度进行调整。整个表达式的结果是一个指针,它指向的位置比原先那个表达式所指向的位置向后移动了5个整型元素。

在这里插入图片描述

  1. *( *( matrix + 1 ) + 5 )

对其执行间接访问操作,它所访问的正是图中的那个整型元素。如果它作为右值使用,你就取
得存储于那个位置的值。如果它作为左值使用,这个位置将存储一个新值。

  1. *( matrix[1] + 5 )

这个看上去吓人的表达式实际上正是我们的老朋友——下标。我们可以把子表达式matrix[1]改写为*(matrix + 1)

这个表达式是完全合法的。matrix[1]选定一个子数组,所以它的类型是一个指向整型的指针。我们对这个指针加上5,然后执行间接访问操作。

  1. matrix[1][5]

这个就是我们最常见的表达形式了。用下标代替间接访问,其含义和4、5一样。

2. 指向多维数组的指针

下面这些声明合法吗?

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

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

int (*p)[10];

下标引用的优先级高于间接访问,但由于括号的存在,首先执行的还是间接访问。所以,p是个指针,但它指向什么呢?接下来执行的是下标引用,所以p指向某种类型的数组。这个声明表达式中并没有更多的操作符,所以数组的每个元素都是整数。

我们对它执行间接访问操作时,我们得到的是个数组,对该数组进行下标引用操作得到的是一个整型值。所以p是一个指向整型数组的指针。

int (*p)[10] = matrix;

它使p指向matrix的第1行。p是一个指向拥有10个整型元素的数组的指针。当你把p与一个整数
相加时,该整数值首先根据10个整型值的长度进行调整,然后再执行加法。所以我们可以使用这个指针一行一行地在matrix中移动。

不要想当然地认为一维数组的数组名是int *,二维数组是int **,两者还是有明显差别的。

如果需要一个指针逐个访问整型元素而不是逐行在数组中移动,应该怎么办呢?下面两个声明都创建了一个简单的整型指针,并以两种不同的方式进行初始化,指向matrix的第1个整型元素。

int *pi = &matrix[0][0];
int *pi = matrix[0];

增加这个指针的值使它指向下一个整型元素。

如果你打算在指针上执行任何指针运算,应该避免这种类型的声明:

int (*p)[] = matrix;

p仍然是一个指向整型数组的指针,但数组的长度却不见了当某个整数与这种类型的指针执行指针运算时,它的值将根据空数组的长度进行调整(也就是说,与零相乘),这很可能不是你所设想的。有些编译器可以捕捉到这类错误,但有些编译器却不能。所以不要在一个指向未指定长度的数组的指针上执行指针运算

3. 作为函数参数的多维数组

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

  • 一维数组:
int vector[10];
...
func1(vector);

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

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

作用于vec上面的指针运算把整型的长度作为它的调整因子。

  • 多维数组:
int matrix[3][10];
...
func2( matrix );

参数matrix的类型是指向包含10个整型元素的数组的指针。func2的原型应该是怎样的呢?

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

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

这里的关键在于编译器必须知道第2个及以后各维的长度才能对各下标进行求值,因此在原型中必须声明这些维的长度。第1维的长度并不需要,因为在计算下标值时用不到它

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

void func2( int **mat );

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

参考

  1. 《C和指针》

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

[管理与领导-113]:IT人看清职场中的隐性规则 - 10 - 看清人的行动、行为、手段、方法背后的动机与背景条件

目录 前言: 一、冰山模型 1.1 冰山模型,系统思考的工具 1.2 冰山模型:发现人行为背后的动机 二、动机、行为模型 "说一套": "做一套": "演一套": "学一套&quo…

【已解决】 Expected linebreaks to be ‘LF‘ but found ‘CRLF‘.

问题描述 团队都是用mac,只有我自己是windows,启动项目一直报错 Expected linebreaks to be ‘LF‘ but found ‘CRLF‘. 但我不能因为自己的问题去改团队配置,也尝试过该vscode配置默认是LF还是报错 思路 看文章vscode如何替换所有文件的…

深入剖析红黑树:优雅地平衡二叉搜索树

目录 一.红黑树的概念二.插入操作三.与AVL树的比较 一.红黑树的概念 在之前的学习中,我们了解了二叉搜索平衡树,AVL树通过控制每个结点中的平衡因子的绝对值不超过1,实现了一个高性能的树。而相较于AVL的高度平衡,红黑树觉得AVL为…

传输层协议—UDP协议

传输层协议—UDP协议 文章目录 传输层协议—UDP协议传输层再谈端口号端口号范围划分pidofnetstat UDP协议端格式UDP报文UDP特点UDP缓冲区基于UDP的应用层协议 传输层 在学习HTTP/HTTPS等应用层协议时,为了方便理解,可以简单认为HTTP将请求和响应直接发送…

JMeter性能分析实战一:日常登录接口

负载测试 日常需求:负载测试! 对于桥的负载测试:我给你20t的一排车辆,看你能不能撑得住20t! 对于系统的负载测试: 逐步增加负载,便于问题的发现和定位,不要操之过急。逐步增加负载…

Stable Diffusion云服务器部署完整版教程

Stable Diffusion云服务器部署完整版教程 2023年07月04日 22:30 3607浏览 18喜欢 22评论 <span class"bili-avatar-icon bili-avatar-right-icon "></span> </div>薯片_AI 粉丝&#xff1a; 1513 文章&#xff1a; 1 设置分组取消关注 已关注 …

【MySql】3- 实践篇(一)

文章目录 1. 普通索引和唯一索引的选择1.1 查询过程1.2 更新过程1.2.1 change buffer1.2.2 change buffer 的使用场景 1.3 索引选择和实践1.4 change buffer 和 redo log2. MySQL为何有时会选错索引?2.1 优化器的逻辑2.1.1 扫描行数是怎么判断的?2.1.2 重新统计索引信息 2.2 …

C语言中柔性数组的讲解与柔性数组的优势

前言:也许你从来没有听说过柔性数组&#xff08;flexible array&#xff09;这个概念&#xff0c;但是它确实是存在的。C99 中&#xff0c;结构中的最后一个元素允许是未知大小的数组&#xff0c;这就叫做"柔性数组"成员。 目录标题 柔性数组什么是柔性数组呢&#…

【C语言】八大排序算法

文章目录 一、冒泡排序1、定义2、思想及图解3、代码 二、快速排序1、hoare版本2、挖坑法3、前后指针法4、非递归快排5、快速排序优化1&#xff09;三数取中选key值2&#xff09;小区间优化 三、直接插入排序1、定义2、代码 四、希尔排序1、定义2、图解3、代码 五、选择排序1、排…

sheng的学习笔记-【中文】【吴恩达课后测验】Course 2 - 改善深层神经网络 - 第二周测验

课程2_第2周_测验题 目录&#xff1a;目录 第一题 1.当输入从第8个mini-batch的第7个的例子的时候&#xff0c;你会用哪种符号表示第3层的激活&#xff1f; A. 【  】 a [ 3 ] { 8 } ( 7 ) a^{[3]\{8\}(7)} a[3]{8}(7) B. 【  】 a [ 8 ] { 7 } ( 3 ) a^{[8]\{7\}(3)} a…

代码随想录 Day11 二叉树 LeetCode T144,145,94 前中后序遍历 (递归解法)

题解及更详细解答来自于:代码随想录 (programmercarl.com) 前言: 递归三要素 确定递归函数的参数和返回值&#xff1a; 确定哪些参数是递归的过程中需要处理的&#xff0c;那么就在递归函数里加上这个参数&#xff0c; 并且还要明确每次递归的返回值是什么进而确定递归函数的返…

【Redis】基础数据结构-skiplist跳跃表

有序集合Sorted Set zadd zadd用于向集合中添加元素并且可以设置分值&#xff0c;比如添加三门编程语言&#xff0c;分值分别为1、2、3&#xff1a; 127.0.0.1:6379> zadd language 1 java (integer) 1 127.0.0.1:6379> zadd language 2 c (integer) 1 127.0.0.1:6379…

【Java-LangChain:使用 ChatGPT API 搭建系统-2】语言模型,提问范式与 Token

第二章 语言模型&#xff0c;提问范式与 Token 在本章中&#xff0c;我们将和您分享大型语言模型&#xff08;LLM&#xff09;的工作原理、训练方式以及分词器&#xff08;tokenizer&#xff09;等细节对 LLM 输出的影响。我们还将介绍 LLM 的提问范式&#xff08;chat format…

【图像处理】使用各向异性滤波器和分割图像处理从MRI图像检测脑肿瘤(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

实验3.2 分期付款计算器

目录 实验目的‪‬‪‬‪‬‪‬‪‬‮‬‭‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬ 实验内容‪‬‪‬‪‬‪‬‪‬‮‬‭‬‪‬‪‬‪‬…

20231005使用ffmpeg旋转MP4视频

20231005使用ffmpeg旋转MP4视频 2023/10/5 12:21 百度搜搜&#xff1a;ffmpeg 旋转90度 https://zhuanlan.zhihu.com/p/637790915 【FFmpeg实战】FFMPEG常用命令行 https://blog.csdn.net/weixin_37515325/article/details/127817057 FFMPEG常用命令行 5.视频旋转 顺时针旋转…

python爬虫基于管道持久化存储操作

文章目录 基于管道持久化存储操作scrapy的使用步骤1.先转到想创建工程的目录下&#xff1a;cd ...2.创建一个工程3.创建之后要转到工程目录下4.在spiders子目录中创建一个爬虫文件5.执行工程setting文件中的参数 基于管道持久化存储的步骤&#xff1a;持久化存储1&#xff1a;保…

集合(容器)-List接口及实现类

容器的特征&#xff1a;①数据长度可变&#xff1b;②数据保存方式不同。 集合体系概述&#xff1a;JAVA的集合框架是由很多接口、抽象类、具体类组成。都位于java.util包中。 Java中集合类中默认可以存储任意数据类型&#xff0c;Java中的集合提供泛型机制&#xff0c;在定义…

李沐深度学习记录3:11模型选择、欠拟合和过拟合

通过多项式拟合探索欠拟合与过拟合 import math import numpy as np import torch from torch import nn from d2l import torch as d2l#生成数据集 max_degree 20 # 多项式的最大阶数 n_train, n_test 100, 100 # 训练和测试数据集大小 true_w np.zeros(max_degree) # …

园林园艺服务经营小程序商城的作用是什么

园林园艺属于高单价服务&#xff0c;同时还有各种衍生服务&#xff0c;对企业来说&#xff0c;多数情况下都是线下生意拓展及合作等&#xff0c;但其实线上也有一定深度&#xff0c;如服务售卖或园艺产品售卖等。 基于线上发展可以增强获客引流、品牌传播、产品销售经营、会员…