最近复习c/c++数组的传参,发现了一些问题,下面是一些总结和思考

正文

一维数组的传参/一级指针的传参/普通指针

在理解指针的基础上,一维数组的指针传递很简单,我们知道数组的数组名就是这个数组首元素的地址,所以将数组名传入函数就可以了

// 一维数组的传递0.cpp
# include <stdio.h>void f(int *pArr, int len) {//这里传入数组的首地址和数组长度,就可以对数组进行操作了int i;for (i = 0; i < len; ++i)printf("%d  ", pArr[i] );//等价于printf("%d  ", *(pArr + i) );
}int main(void) {int a[5] = {1, 2, 3, 4, 5};//定义一个一维数组f(a, 5);  //a是 int *return 0;
}

二维数组的传参/二级指针的传参

二维数组的传参就比较麻烦了,你需要搞明白,数组名是什么类型的指针。不然编译不通过。这边重点分析一下,方便对下面三级指针有更深的了解。

我们知道一维数组名是常量指针,我们可以将一维数组名赋给一个指针类型再对一维数组进行相关的操作,那二维数组名又是什么?

我们这样初始化一个二维数组int A[3][3]={1,2,3,4,5,6,7,8}或者为int A[3][3]={ {1,2,3},{4,5,6},{7,8,9}};从后面一个定义我们可以看出二维数组是由两个一维数组组成的也就是说二维数组是数组的数组

问题
了解了二维数组那么二维数组名又是什么呢,是不是和一维数组名一样是个一维指针呢?看下面代码:

#include<stdio.h>
int main() {int i, j;int A[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};printf("%#x\n", A);printf("%#x\n", *A);printf("%d\n", **A);return 0;
}


从代码的结果可以看出只有**A才能输出数组中的元素,*A输出的是一个地址,那么我们是不是可以把二维数组名理解为指针的指针。然后定义一个指针的指针 int **p,将数组名赋给p然后二维数组进行相关操作呢?答案是否定的,看下面代码:

#include<stdio.h>
void main() {int i, j;int A[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};int **p;p = A;printf("%d", **p);
}

但是这个代码编译不过,显示error为“无法从int[3][3]转化为int **,那就说明了二维数组名不是指针的指针。那二维数组名又是什么呢?看代码:

#include<stdio.h>
int main() {int i, j;int A[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};int (*p)[3];p = A;for(i = 0; i < 3; i++) {for(j = 0; j < 3; j++)printf("%2d", p[i][j]);//等价于printf("%2d", *(*(p + i) + j));printf("\n");}return 0;
}

从这个结果我们可以看出我们可以先定义一个数组指针int (*p)[3],然后将A数组名然后进行相关操作,即二维数组名是一个数组指针,然后对P+1指向的是下一个数组下一行的地址进行操作。

原因
二维数组名即数组地址,指向首行地址,不是指针的指针。

表面上看,行地址即一维数组指针,而数组名指向行搜索就应该是指针的指针。 但是你考虑过没有,如果A[3][3],假设int**p=A; 那么要对行递增执行p++时,编译器如何知道列宽?

因为int**是指指向一个int 类型的指针,其数据宽度是4字节,内置宽度,因此p将指向下一个整数元素地址,也就是p递增了4字节,而不是3个int型数据的宽度,这就错位了。

所以A[3][3]的地址类型不是简单的指针的指针,而是行指针的指针,而行宽是由你定义的数组列数和元素类型所决定,int类型就是4*3=12个字节。这叫数据对齐。因此编译器在转换数组名时,会根据对齐要求而确定相应的指针类型,所以A的地址类型应该是int ()[3],而不是int **。 所以应该这样int (*p)[3]=A; 其含义为,p是一个指向(含3个int类型元素的一维数组或行的)指针,其实本质上任何指针都是4字节(32位系统),你完全可以将一种指针类型强制转为任何其他类型,那为什么还要区分指针类型,就是为了指针运算时实现数据对齐,准确定位。

那么数组的传递也非常简单了

#include <stdio.h>void subfun(int n, char (*subargs)[3] ) {//这个3指的是二级数组数据的个数,{0, 1, 2},比如012,有3个元素int i,j;for (i = 0; i < n; i++) {for (j = 0; j < n; j++) {printf("subargs[%d][%d] = %d\n", i, j, subargs[i][j]);//等价于 printf("subargs[%d][%d] = %d\n", i, j, *(*(subargs + i) + j));}}
}int main() {char args[][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};subfun(3, args);return 0;
}

补充

我们知道字符串的本质也是一个字符型数组,所以看字符串二维数组的传参

#include <stdio.h>void subfun(int n, char (*subargs)[4] ) {//这个4代表abc\0这个4个字符的长度,就是里面的数组长度int i;for (i = 0; i < n; i++) {//为什么这里指循环一遍,而上面的循环了两遍,因为%s,就是输入一个字符串的,即一个字符型数组printf("subargs[%d] = %s\n", i, subargs[i]);}
}int main() {char args[][4] = {"abc", "def", "ghi"};//这里的"abc" 等价于['a','b','c','\0'];也是一个字符型数组subfun(3, args);return 0;
}

三维数组的传参/三级指针的传参

有了之前两层铺垫,这个我们就比较好理解了
首先看下三维数组的首地址是什么

#include<stdio.h>
int main() {int i, j;int A[3][3][3] = {{{0, 1, 2}, {0, 1, 2}, {0, 1, 2}}, {{0, 1, 2}, {0, 1, 2}, {0, 1, 2}}, {{0, 1, 2}, {0, 1, 2}, {0, 1, 2}}};printf("%x\n", A);printf("%x\n", *A);printf("%x\n", **A);printf("%d\n", * **A);return 0;
}


然后看看看怎样能正常输出这个数组

#include<stdio.h>
int main() {int i, j, k;int A[3][3][3] = {{{0, 1, 2}, {0, 1, 2}, {0, 1, 2}}, {{0, 1, 2}, {0, 1, 2}, {0, 1, 2}}, {{0, 1, 2}, {0, 1, 2}, {0, 1, 2}}};int (*p)[3][3];//其实这里就是定义了首行指针的类型/宽度,就是p+1的单位,不然输入无法对其数据p = A;for(i = 0; i < 3; i++) {for(j = 0; j < 3; j++) {for(k = 0; k < 3; k++)printf("%2d", *(*(*(p + i) + j)) + k);printf("\n");}printf("\n");}return 0;
}


然后我们引入函数

#include <stdio.h>void subfun(int n, int (*subargs)[3][3])  {int i,j,k;   for (i = 0; i < n; i++) {for (j = 0; j < n; j++) {for (k = 0; k < n; k++) { printf("subargs[%d][%d][%d] = %d   ", i, j, k, subargs[i][j][k]); }printf("\n");}}
}int main()  {int args[3][3][3] = {{ {0, 1, 2}, {0, 1, 2}, {0, 1, 2} }, {{0, 1, 2}, {0, 1, 2}, {0, 1, 2} }, {{0, 1, 2}, {0, 1, 2}, {0, 1, 2} } };subfun(3, args);return 0;
}


同样,这里放一个字符型的数组作为补充个

#include <stdio.h>void subfun(int n, char (*subargs)[3][12])  {//这里的单位指的是这个首行指针的类型/宽度是 3行12列(单位)int i,j;   for (i = 0; i < n; i++) {for (j = 0; j < n; j++) { //为什么这里指循环2遍,而上面的循环了3遍,因为%s,就是输入一个字符串的,即一个字符型数组printf("subargs[%d][%d] = %s\n", i, j, subargs[i][j]); // printf("subargs[%d][%d] = %c\n", i, j, subargs[i][j][k]);//如果再循环一遍的话,可以输出helloword中的每个字符}}
}int main()  {char args[3][3][12] = {{ "hello word1", "hello word2", "hello word3"}, {"hello word4", "hello word5", "hello word6"}, {"hello word7", "hello word8", "hello word9"}};subfun(3, args);return 0;
}

这里看到某大佬的一篇文章,受到启发,这里放上原作者的链接!

http://m.blog.csdn.net/toyalll/article/details/50043193

最后


如果这边文章帮到你了,请给我点赞,留言,转载哦!
转载请注明出处,有什么问题可以留言!

C/C++ 一维数组的传参/一级指针的传参 二维数组的传参/二级指针的传参 三维数组的传参/三级指针的传参 方法总结分析终极篇相关推荐

  1. 【C 语言】二级指针作为输入 ( 自定义二级指针内存 | 为 二级指针 分配内存 - 存放 一维指针 | 为每个 一级指针 分配内存 | 释放二维指针内存 )

    文章目录 一.二级指针 1.为 二维指针 分配内存 2.为每个 一维指针 分配内存 3.释放 二维指针 内存 二.完整代码示例 一.二级指针 声明二级指针 : // 声明二维指针char **p = ...

  2. 数组拼接时中间怎么加入空格_【题解二维数组】1123:图像相似度

    1123:图像相似度时间限制: 1000 ms    内存限制: 65536 KB [题目描述] 给出两幅相同大小的黑白图像(用0-1矩阵)表示,求它们的相似度.说明:若两幅图像在相同位置上的像素点颜 ...

  3. c语言二维数组行优先如何访问快,C/C++遍历二维数组,列优先(column-major)比行优先(row-major)慢,why?...

    C/C++遍历二维数组,列优先(column-major)比行优先(row-major)慢,why? 简单粗暴的答案:存在Cache机制! 稍微啰嗦一点:CPU访问内存(读/写,遍历数组的话主要是读) ...

  4. C语言什么时候必须用到二级指针?(需要调用函数为一维空指针确定值的情况下,需要传入二维指针,也就是那个一维指针的指针)

    结论:需要调用函数为一维空指针确定值的情况下,需要传入二维指针,也就是那个一维指针的指针 例子:为空指针p开辟内存空间 1.不用二级指针(无法实现) #include <stdio.h> ...

  5. C语言学习之将一个二维数组的行和列互换,存到另一个二维数组中

    C语言学习之将一个二维数组的行和列互换,存到另一个二维数组中 #include <stdio.h> int main(){int a[2][3]={{1,2,3},{4,5,6}}; // ...

  6. 【SLAM】lidar-camera外参标定(港大MarsLab)无需二维码标定板

    综述 标定问题也是一种位姿估计问题,它本质上和各种激光里程计和视觉里程计解决的是一样的问题.标定采用的办法也可以在里程计问题中借鉴.它们都有着共同的流程: a.特征提取 b.特征匹配 c.位姿求解 参 ...

  7. 二维数组更改vue_使用vue中的v-for遍历二维数组的方法

    如下所示: {{itemss}} 其中,data数据为: this.data = [ [ { type: '', name: '资产', start: '期末余额', end: '期初余额' }, { ...

  8. python求二维数组各行最大值_python+numpy按行求一个二维数组的最大值方法

    问题描述: 给定一个二维数组,求每一行的最大值 返回一个列向量 如: 给定数组[1,2,3:4,5,3] 返回[3:5] import numpy as np x = np.array([[1,2,3 ...

  9. java把二维转换为一维_在R语言中什么函数可以将二维数组转换成一维数组

    满意答案 vi31892i 2013.09.11 采纳率:44%    等级:11 已帮助:6956人 这好象是汇编语言的问题吧 举个例子吧 #include "iostream.h&quo ...

最新文章

  1. 【java】兴唐第十七节课
  2. Matlab编程与数据类型 -- 多分支条件选择语句if/elseif/…/else/end
  3. If one day
  4. JDK15真的来了,一起来看看它的新特性
  5. Linux 下 Oracle 内核参数优化
  6. java半解释半编译_编译型语言、解释型语言、半编译半解释型语言
  7. 设计模式之构造函数模式
  8. 前端截取视频第一帧作为封面
  9. 数据库系统概论:ER图设计
  10. latex中文简历,硕博士找工作实习用,顶级简约简历
  11. Zabbix自定义报警提示声音
  12. C内存分配方式与C++内存分配方式
  13. 如何把微信消息或者短信实时转发到另一个手机上
  14. skywalking elasticsearch 版本匹配问题
  15. 如何显示电脑已连接的WiFi的密码
  16. 中国大数据技术大会(BDTC 2022)企业数据智能专题论坛,7月17日淄博见
  17. 最新速卖通提前放款服务解读,帮助商家减轻资金压力!
  18. STM32连YL69土壤湿度传感器以及内部温度传感器采集数据并在LCD上显示
  19. 再谈IE6之Fixed定位
  20. EasyExcel 复杂数据导出

热门文章

  1. 分布式事务 解决方案
  2. Android电视设置密码,Android TV 输入登录账号和登录密码后首页页面焦点找不到原因...
  3. 花式栈溢出值stack smash
  4. Win10为什么电脑在有密码的情况下,睡眠后不用输密码打开?
  5. 对于tomcat升级导致游览器访问页面出现的中文乱码问题解决方案
  6. 小米副总裁崔宝秋离职 原掌管的清河大学并入人力资源部
  7. 在cadence集成calibre
  8. html怎么把文字居中6,html5怎么把文字居中
  9. 专访容智信息柴亚团:终极愿景是助力天下企业成为数字化孪生组织
  10. 抓取淘宝天猫商品详情图