前言
本文将探讨一下关于二维数组在内存中的存储和二维数组在参数传递时的使用。
一、二维数组在内存中的存储
如果定义一个这样的二维数组int a[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}};则其在内存中的表示可能下面这样的。
由上图可以看出,在内存中二维数组是按照行主序进行存储的,从内存的角度上看,二维数组本质就是一个一维数组。如果把二维数组的每一行看成一个整体,即看成一个数组中的一个元素,那么整个二维数组就是一个一维数组。而二维数组的名字代表二维数组第0行的首地址(注意它是代表一行元素的首地址,而不是第0行第0列元素的首地址,虽然是相等的,但不能这么理解,所以在没有强制转换的情况下,二维数据要么通过行指针进行参数传递,要么通过二维指针进行参数传递)。
二、二维数组在参数传递时的使用
1、 可以用二维数组名作为实参或者形参,在被调用函数中对形参数组定义时可以指定所有维数的大小,也可以省略第一维的大小说明,如:
void Func(int array[3][10]);
void Func(int array[][10]);
但是不能把第二维或者更高维的大小省略,如下面的定义是不合法的:
如 void Func(int array[3][]);
因为从实参传递来的是数组的起始地址,在内存中按数组排列规则存放(行主序),而并不区分行和列,如果在形参中不说明列数,则系统无法决定应为多少行,多少列,不能只指定一维而不指定第二维。
2、将二维数组作为指针进行参数传递
(1)直接作为行指针(数组指针)来传递参数(二维数组的名字代表二维数组第0行的首地址)
1 #include "stdafx.h" 2 #include<iostream> 3 using namespace std; 4 5 void test(int (*a)[4],int m,int n) 6 { 7 cout<<*(*(a+m)+n); 8 } 9 10 int _tmain(int argc, _TCHAR* argv[]) 11 { 12 int a[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}}; 13 test(a,1,1); 14 return 0; 15 }
上述程序中int (*a)[4],可以理解为二维数组的行指针(这个指针指向二维数组的行,而每一行最多有4列),a[n]表示二维数组的第n行,所以cout<<*(*(a+m)+n);先定位出a数组的第m行的位置,然后再求出第m行第n列的值
(2)参数传递时将二维数组的强制转换为一维指针,然后按照内存中存储的方法计算二维数组对应成一维数组的下标
1 #include "stdafx.h" 2 #include<iostream> 3 using namespace std; 4 void test(int *a,int row,int column,int m,int n) 5 { 6 cout<<a[m*column+n]; 7 } 8 9 int _tmain(int argc, _TCHAR* argv[]) 10 { 11 int a[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}}; 12 test((int*)a,3,4,1,1); 13 return 0; 14 }
注意参数传递时将二维数组的强制转换为一维指针,如上述程序中的第12行
注意:切不可将二维数组直接转换成二维指针作为形参传递,因为在这样子函数中不知道每一个一维元素含有多少个二维元素。
如,下面这样写就是错误的: