二维数据名作形参

之前帮同学调一个程序的时候遇到的,把二维数据改为全局变量,不通过参数传递就没问题了,否则程序崩溃。

细究一下,二维数据名用于形参时需要注意哪些方面。

测试程序如下:

#include<stdio.h>
#include<stdlib.h>

void print1(int **a, int m, int n);
void print2(int (*a)[2], int m, int n);

int main()
{
  int a[2][2]={1,2,3,4};
  print1((int**)a,2,2);
  print2(a,2,2);
  system("pause");
  return 0;
}

void print1(int **a, int m, int n)
{
  for(int i=0;i<m;++i)
    for(int j=0;j<n;++j)
    {
      printf("%d\n",*(a+i*n+j));
      //printf("%d\n",a[i][j]);
    }
}

void print2(int (*a)[2], int m, int n)
{
  for(int i=0;i<m;++i)
    for(int j=0;j<n;++j)
    {
      printf("%d\n",a[i][j]);
    }
}

程序可以正常运行,而且没问题。有问题的是print1中注释掉的语句。可能很多人会觉得二维数组的数组名不就是一个二维指针吗,为什么用a[i][j]的方式访问不行?注释掉的语句在执行时,程序崩溃。

原因是这样的,二维数组的数组名其实是一个int (*)[N]的指针,和 int** 指针还是不一样的。直观来看,对前者一次解引用的话,得到的是数组;对后者一次解引用,得到的是指针。其实在调用的时候就可以发现,如果你不进行强制类型转换,而直接进行这样的调用 print1(a,2,2); 会提示如下错误:cannot convert `int (*)[2]‘ to `int**‘ for argument `1‘ to `void print1(int**, int, int)‘ 。编译器已经告诉你,类型不匹配了;这个时候你应该想到的是用第二种方式来定义函数。而有的人可能觉得既然类型不匹配,就给直接强制类型转换了,结果编译通过了,但程序崩溃了,更找不出问题。

产生这个问题的根本原因是,对数组名和指针的细微差别没有认识到。

数组名,在访问元素时,是直接取址的过程。比如a[i],它是直接在a的地址上进行一个 i (乘以a[i]的类型大小)的偏移。(每个符号的地址在编译时可知)

指针,访问元素时,是一个间接寻址的过程。比如对int *a; 在a[i]取元素时,首先它会在变量a的地址上取数,取得的值作为地址再去寻址,然后再进行一个 i (乘以类型大小)的偏移。

这样的话,对上面测试代码而言,在main函数中,你声明的a是数组名,即int (*)[2]类型,传递到print2中,在print2函数中用a[i][j]访问时,是先对形参a进行一个间接寻址,然后直接寻址。而传递到print1中,首先你需要强制转换成int ** 才可以,在print1中用a[i][j]访问时,是对形参a进行间接寻址后,再间接寻址,这样就发生了错误。而在print1中用*(a+i*n+j)的方式则是可以的。

这个和下面这类错误很类似。就是在一个文件中定义了int a[100]; 然后你想在另一文件中使用它,你用了外部声明,但是你声明成了这样: extern int * a; 这样,在访问a数组的元素时,本来应该是按照数组名的直接寻址方式,在这个文件中却会用指针的间接寻址,就会出现不可预知的错误。

也有参考这里

关于指针和数组名在什么情况下不同,以后有时间再总结下。

时间: 2024-10-12 08:13:51

二维数据名作形参的相关文章

二维数组名作为实参或者形参

    1.方式1.void fun(int a[4][6]); //二维数据作为函数参数时,要明确指明二维数组的列数.         void fun(int a[][6])    //二维数组行数可以省略         另外,不能用非常量定义二维数组作为其下标.     */ void fun1(int a[][3],int n){//数组的行数    for (int i = 0; i < n; i++) {        for (int j = 0; j < 3; j++) { 

【C语言】二维指针做形参

转自:http://hi.baidu.com/gpmzccqceabimqq/item/f499f057aa1520404eff208b 关键: 传入时强制类型转换 + 使用时自己手工寻址 今天写程序的时候要用到二维数组作参数传给一个函数,我发现将二维数组作参数进行传递还不是想象得那么简单里,但是最后我也解决了遇到的问题,所以这篇文章主要介绍如何处理二维数组当作参数传递的情况,希望大家不至于再在这上面浪费时间. 正文: 首先,我引用了谭浩强先生编著的<C程序设计>上面的一节原文,它简要介绍了如

【C语言】二维数组做形参

二维数组有两种形式: ①在栈上: int a[4][4] = {...}; ②在堆堆上: int ** a = new int *[4]; for(int i = 0; i < 4; i++) a[i] = new int[4]; 这两种情况下,二维数组做形参的传参方式是不一样的. ①在栈上时 void fun(int * a, int rownum, int colmunnum)   //形参传递按照一维指针 { ... a[r * colmunnum + c] = ...;     //根据

对二维数据进行边界拓展

对二维数据处理的时候,经常遇到需要越界的问题,比如对图像进行滤波操作.对原始数据的边界进行拓展,然后使用拓展后的数据作处理,可以解决越界的问题.根据拓展出的数据的值来自哪里可以分为多种边界拓展方式,我们要实现的是将边界进行奇对称拓展. 算法 举例说明什么是奇拓展.比如对原始二维数据向左拓展4列,那么在边界上向左第一列复制边界上向右第一列,在边界上向左第二列复制边界上向右第二列,以此类推.边界列并没有被复制,因为C语言中是从0开始计数的,所以边界列是0列,按照0列对称拓展就称为奇对称拓展.如果0列

【Excle数据透视】二维数据如何创建数据透视表

二维数据在创建数据透视表的时候,可能会给你带来一些麻烦,没法创建,会丢失维度,那怎么办呢? 解决办法:使用数据透视表和数据透视图向导即可创建 步骤1 按下[Alt+D+P],出现如下界面 选择上图中的"多重合并计算数据区域"→下一步 创建单页字段→下一步 选定区域A:A15→添加→下一步 单击完成 数据透视表已经创建完成.二维数据透视表与一维数据透视表在于"行合计" 注意:我上图的数据透视是使用默认计数,所以全部都是1,这个可以根据自己的需求进行调整.

PHP二维数据排序,二维数据模糊查询

一.因为项目中的一个报表需要合并三个表的数据,所以分表查询再合并数据,利用PHP数组函数进行排序,搜索.三表合并后的数组结构如下: Array ( [0] => Array ( [history_id] => 12 [sla_group_id] => 1 [sla_id] => -1 [create_time] => 1513057695 [tasklog_id] => 12 [tasklog_time] => 2017-12-12 13:48:15 [taskl

TensorflowTutorial_二维数据构造简单CNN

使用二维数据构造简单卷积神经网络 觉得有用的话,欢迎一起讨论相互学习~Follow Me 图像和一些时序数据集都可以用二维数据的形式表现,我们此次使用随机分布的二位数据构造一个简单的CNN-网络卷积-最大池化-全连接 参考代码 # Implementing Different Layers # --------------------------------------- # # We will illustrate how to use different types # of layers

一维数据和二维数据

此文章为本人学习所得,如有不足之处,欢迎指正,分享原创,一起进步 维度:数据的组织形式 一维数据 由对等关系的有序或无序数据构成,采用线性方式(一条直线排开)组织 对等关系:这些数据平级关系(不是包含.从属关系) 一维数据的表示----- 如果数据间有序:使用列表类型.如:一维列表ls = [3.1 , 3.02 , 4.15]如果数据间无序:使用集合类型,如:一维集合st ={ 4.15 , 3.02 , 3.1} 切记:for循环可以遍历数据,进而对每个数据进行处理 一维数据的存储-----

python第七周,二维数据的格式化和处理

二维数据的表示: 类表类型可以表示二维数据 [   [424,23423,2342],[131,535,3646]  ] 使用两层for循环可以便利每个元素 外层列表中每个元素可以对应一行,也可以对应一列 一维数据分为列表和集合类型,二维数据只有列表类型 CSV数据存储格式 国际通用的一二维数据存储格式,一般.csv扩展名,每行一个一维数据,采用逗号分隔,无空行 Excel软件可读入输出,一般编辑软件都可以产生,如果某个元素缺失,逗号仍要保留, 二维数据的表头可以作为数据存储,也可以另行存储,