深入理解C/C++二维数组
深入理解C/C++二维数组
前言
本来以为自己对二维数组的理解还可以,没感觉有什么,但是今天小伙伴问了一个问题感觉迷惑了好久,于是决定细致的记录一下,一步一步的探究各种关于二维数组的问题,巩固基础。
二维数组的探究之旅(初级)
首先定义二维数组
int a[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
然后开始研究二维数组名和地址的关系
// 打印a a[0] 和 a[0][0]的地址
cout << "the value of a: " << a << endl;
cout << "the value of a[0]: " << a[0] << endl;
cout << "the address of a[0][0]: " << &a[0][0] << endl;
the value of a: 0x7ffe5b8c1ee0
the value of a[0]: 0x7ffe5b8c1ee0
the address of a[0][0]: 0x7ffe5b8c1ee0
就如各种资料说的那样,可以看出三个表达指向的是一个地址,继续看
这里看一下每一行\(a[i], 0\leq i<3\)
for (int i = 0; i < 3; ++i)
cout << "the value of a[" << i << "]" << " is " << a[i] << endl;
the value of a[0]is 0x7ffe5b8c1ee0
the value of a[1]is 0x7ffe5b8c1eec
the value of a[2]is 0x7ffe5b8c1ef8
打印的结果是每一行的首地址,可以看出来每两个地址之间差12个字节,也就是三个int的长度(每个int是四个字节,大部分编译器是这样的)。这与我们预期的是一样的,毕竟是每行的首地址。
继续走,我们看到\(a, a[0], a[0][0]\)的地址是一样的,都是最头上的首地址,那么这里用这个地址推导进而显示其他位置的元素
// 由a[0]推出其他,这里以第1行第1列(0 base)为例
cout << "the address of a[0+1]+1 " << "is " << a[0+1]+1 << endl;
cout << "the value of a[0+1]+1 " << "is " << *(a[0+1]+1) << endl;
cout << "the address of a[0]+4 " << "is " << a[0]+4 << endl;
cout << "the value of a[0]+4 " << "is " << *(a[0]+4) << endl;
the address of a[0+1]+1 is 0x7ffe5b8c1ef0
the value of a[0+1]+1 is 5
the address of a[0]+4 is 0x7ffe5b8c1ef0
the value of a[0]+4 is 5
前两种行是通过加a[0]的索引得到其他行的首地址,然后再加偏移量得到的,后两行是直接计算偏移量得到的。
继续,由\(a[0][0]\)的地址推导
// 由&a[0][0]推出其他, 这里以第1行第1列(0 base)为例
cout << "the address of a[0][0]+4 " << "is " << &a[0][0]+4 << endl;
cout << "the value of a[0][0]+1 " << "is " << *(&a[0][0]+4) << endl;
the address of a[0][0]+4 is 0x7ffe5b8c1ef0
the value of a[0][0]+1 is 5
这里和上面的第二中直接加偏移量的情况是一样的。
由数组名得到其他元素
现在是让人有点迷惑的地方,就是数组名a既然和\(a[0], a[0][0]\)指向的地址一样,那么是否用法也一样呢?
我们先来看看如何用a得到\(a[1][1]\)
// 假设要求a[1][1](5)
cout << "a[1][1] inferred from a : " << *(*(a+1)+1) << endl;
a[1][1] inferred from a : 5
a+1指向的是\(a[1]\),这里是第1行(0 base)的首地址,对它解引用得到a[1]的地址,然后+1就得到\(a[1][1]\)的地址了。
前面说a+1是指向地址的,那么是不是意味a是一个二级指针呢?
int *p = a; // 不通过
实验发现报错,说明a不是一个指针类型,继续看
int *p = *a;
cout << "the value of p is: " << p << endl;
cout << "the value of *p is: " << *p << endl;
cout << "the value of p+1 is: " << p+1 << endl;
cout << "the value of *(p+1) is: " << *(p+1) << endl;
cout << "a[1][1] inferred from p : " << *(p+1*3+1) << endl;
the value of p is: 0x7ffe5b8c1ee0
the value of *p is: 1
the value of p+1 is: 0x7ffe5b8c1ee4
the value of *(p+1) is: 2
a[1][1] inferred from p : 5
对a解引用后确实是一个地址,所以可以定义指针,并且可以用加偏移量的方式得到\(a[1][1]\)
更为有趣的是
cout << "a[1][1] inferred from p[] : " << p[1*3+1] << endl;
a[1][1] inferred from p[] : 5
指针p表现的竟然像一个一维数组(因为直接按索引就可以得到元素),这里也增加了一种新的取元素方式。这可能和[]的工作方式有关,这部分还是没弄明白,欢迎指导。
总结
这篇博客详细的记录了由二维数组名引出的各种细节,虽然还不完善,但是确实让自己巩固了基础,以后估计应该不会倒在二维数组了……吧。
深入理解C/C++二维数组的更多相关文章
- Java基础学习之“二维数组”
一.鄙人对二维数组的理解 二维数组就是由多个数组并列而成 二.举例 1.普通数组(一维数组)的图像格式 2.二维数组的图像格式 代码 1 @Test 2 public void xueXi(){ 3 ...
- C语言教学--二维数组和指针的理解
对于初学者对二维数组和指针的理解很模糊, 或者感觉很难理解, 其实我们和生活联系起来, 这一切都会变得清晰透彻. 我们用理解一维数组的思想来理解二维数组, 对于一维数组,每个箱子里存放的是具体的苹果, ...
- 关于c语言二维数组与指针的个人理解及处理办法。
相信大家在学习C语言时,对一维数组和指针的理解应该是自信的,但是,我在学习过程中,看到网上一些博文,发现即便是参加工作的一些专业编程人员,突然碰到二维数组和指针的问题时,也可能会遇到难以处理的诡异问题 ...
- 程序员之--C语言细节13(二维数组和指针,&*a[i][0]的理解,数组1[e]和e[1]非常可能你没见过)
主要内容:二维数组和指针.&*a[i][0]的理解.数组1[e]和e[1] #include <stdio.h> #define NUM_ROWS 10 #define NUM_C ...
- java二维数组简单初步理解
二维数组 二维数组本质上是以数组作为数组元素的数组,即“数组的数组”. int[][] arr = {{1, 2, 3}, {4, 5, 6}}; System.out.println(arr[0][ ...
- 洛谷 P2701 [USACO5.3]巨大的牛棚Big Barn Label:二维数组前缀和 你够了 这次我用DP
题目背景 (USACO 5.3.4) 题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方.我们假定,他的农场划分成 N ...
- 【C语言入门教程】4.2 二维数组
C 语言允许使用多维数组,即使用多组小标的数组,二维数组是最常用的多维数组.多维数组在内存中存放数据的顺序与一维数组相同,使用连续的存储单元. 4.2.1 二维数组的一般形式 二维数组的一般声明形式为 ...
- Java 一维数组 二维数组 三维数组
二维数组包含一位数组 三维数组就是在二维数组的基础上,再加一层.把二维数组看做是一维数组就可以了,按照上述理解类推. 下面是 一维 二维 三维数组例子 一维数组: int[] array1 ...
- (一)二维数组&&指针数组与数组指针
一.首先我们从字面意思理解一下什么是指针数组什么是数组指针 1.指针数组:本质是一个数组,数组中的每一个元素是一个指针. 2.数组指针:本质是一个指针,而指针指向一个数组. 二.我们该怎么区分指针数组 ...
随机推荐
- spark搭建部署
基础环境准备 安装JDK1.8+,并设置环境变量 搭建zookeeper集群 搭建Hadoop集群 Spark local模式 上传编译完成的spark安装程序到服务器上,并解压到指定目录 [root ...
- selenium安装浏览器驱动
3.0以上版本恩的selenium需要安装驱动 pip show selenium 安装驱动 1.下载驱动地址: 火狐:https://github.com/mozilla/geckodriver/r ...
- Connection:Keep-alive
名词解释: HTTP无状态:无状态是指协议对于事务处理没有记忆能力,服务器不知道客户端是什么状态.从另一方面讲,打开一个服务器上的网页和你之前打开这个服务器上的网页之间没有任何联系 如果你要实现一个购 ...
- ECharts 定制 label 样式
起因 实现对 label 的样式定制,自定义字体颜色.大小等属性:效果如下图 实现 itemStyle: { normal: { color: '#f7ba0e', label: { ...
- mysql大数据量使用limit分页,随着页码的增大,查询效率越低下
1. 直接用limit start, count分页语句, 也是我程序中用的方法: select * from product limit start, count当起始页较小时,查询没有性能问题 ...
- BZOJ3747:[POI2015]Kinoman(线段树)
Description 共有m部电影,编号为1~m,第i部电影的好看值为w[i]. 在n天之中(从1~n编号)每天会放映一部电影,第i天放映的是第f[i]部. 你可以选择l,r(1<=l< ...
- F2eTest程序快捷方式安装到桌面
按照http://f2etest.***.com/install页面上介绍的:安装快捷方式到Windows桌面 (Win7)部分的介绍进行安装. 其中第三步的https连接需要在f2etest的c ...
- macbook下 go 语言的 helloworld
go语言开发的目录 一般go语言$GOPATH 目录约定有三个子目录: src 存放源代码(比如:.go .c .h .s等) pkg 编译后生成的文件(比如:.a) bin 编译后生成的可执行文件( ...
- Hadoop学习之路(十四)MapReduce的核心运行机制
概述 一个完整的 MapReduce 程序在分布式运行时有两类实例进程: 1.MRAppMaster:负责整个程序的过程调度及状态协调 2.Yarnchild:负责 map 阶段的整个数据处理流程 3 ...
- virtualbox+vagrant学习-2(command cli)-12-vagrant Provision命令
Provision 格式: vagrant provision [vm-name] [--provision-with x,y,z] 针对正在运行的vagrant托管计算机运行任何配置预配置程序. u ...