如何将multidimensional array传递给C和C ++中的函数

#include<stdio.h> void print(int *arr[], int s1, int s2) { int i, j; for(i = 0; i<s1; i++) for(j = 0; j<s2; j++) printf("%d, ", *((arr+i)+j)); } int main() { int a[4][4] = {{0}}; print(a,4,4); } 

这在C中有效,但在C ++中不起作用。

错误:

 cannot convert `int (*)[4]' to `int**' for argument `1' to `void print(int**, int, int)' 

为什么它不能在C ++中工作? 需要做什么改变?

此代码不能在C或C ++中工作。 一个int[4][4]types的数组不能转换为int **types的指针(这是int *arr[]在参数声明中所代表的意思)。 如果你设法用C语言编译它,只是因为你可能忽略了一个C编译器的警告,它的格式与你从C ++编译器得到的错误信息基本相同。 (有时C编译器发出警告 ,说明本质上是错误 。)

所以,再次,不要做出不正确的断言。 这个代码不能在C中工​​作。为了将一个内置的2D数组转换成一个int **指针,你可以使用像这样的技术

将multidimensional array转换为c ++中的指针

(请参阅接受的答案,问题完全相同。)

编辑:代码似乎在C中工作,因为在打印代码中的另一个错误是伪装数组传递中的错误的影响。 为了正确地访问一个int **伪数组的元素,你必须使用expression式*(*(arr + i) + j) ,或者更好的是一个简单的arr[i][j] (这是同样的事情)。 你错过了额外的* ,这使得它打印出与你的数组内容完全无关的东西。 再次,初始化你的数组在main的东西,看看你打印在C中的结果与你想要的数组的内容完全没有关系。

如果如上所示更改printf语句,则由于最初描述的数组传递错误,您的代码很可能会崩溃。

还有一次:你不能将一个int[4][4]数组作为int **伪数组传递。 这就是C ++在错误信息中告诉你的。 而且,我确定,这是C编译器告诉你的,但是你可能忽略了它,因为它只是一个警告。

问题是,那个

 int a[4][4]; 

实际上将存储在一个物理连续的存储器中。 所以,要访问4×4数组的任意部分,函数“print”需要知道数组的维数。 例如下面的一小段代码,将以两种不同的方式访问内存的相同部分。

 #include <iostream> void print(int a[][4]){ for (int i = 0; i <4; i++){ for (int j = 0; j < 4; j++){ //accessing as 4x4 array std::cout << a[i][j] <<std::endl; //accessing corresponding to the physical layout in memory std::cout << *(*(a)+ i*4 + j) << std::endl; } } } int main(){ int a[4][4]; //populating the array with the corresponding indices from 0 to 15 int m = 0; for (int i = 0; i<4; i++){ for (int j= 0; j < 4; j++){ a[i][j] = m; m++; } } print(a); } 

所以内存布局不会改变,但访问的方式。 它可以像棋盘一样可视化。

  0 1 2 3 ---------- 0| 1 2 3 4 1| 5 6 7 8 2| 9 10 11 12 3|13 14 15 16 

但真正的物理记忆看起来像这样。

 0*4+0 0*4+1 0*4+2 0*4+3 1*4+0 1*4+1 1*4+2 1*4+3 2*4+1 etc. ----------------------------------------------------- 1 2 3 4 5 6 7 8 9 etc. 

在c ++中,数组的数据是逐行存储的,并且行的长度(在本例中为4)总是需要为下一行获得适当的内存偏移量。 因此,第一个下标仅指示声明数组时所需的存储量,但之后不再需要计算偏移量。

 #include<stdio.h> void print(int arr[][4], int s1, int s2) { int i, j; printf("\n"); for(i = 0; i<s1; i++) { for(j = 0; j<s2; j++) { printf("%d, ", *((arr+i)+j)); } } printf("\n"); } int main() { int a[4][4] = {{0}}; print(a,4,4); } 

这将工作,我的意思是编译。 @AndreyT解释了为什么你的版本已经不能工作了。

这是你应该如何传递一个二维数组。

为了清楚起见,您还可以在函数声明中指定两个大小:

 #include<stdio.h> void print(int arr[4][4], int s1, int s2) { int i, j; printf("\n"); for(i = 0; i<s1; i++) { for(j = 0; j<s2; j++) { printf("%d, ", *((arr+i)+j)); } } printf("\n"); } int main() { int a[4][4] = {{0}}; print(a,4,4); } 

两者都会工作。

如果你的意图是访问行的第j个元素,你还应该把*((arr+i)+j)改为a[i][j] (最好)或者*(*(arr+i)+j) i

这里有一个版本,这两个工作,但理论上无效(见下文)C90和C ++ 98:

 #include <stdio.h> static void print(int *arr, size_t s1, size_t s2) { size_t i, j; printf("\n"); for(i = 0; i < s1; i++) { for(j = 0; j < s2; j++) { printf("%d, ", arr[i * s2 + j]); } } printf("\n"); } int main(void) { int a[4][4] = {{0}}; print(a[0], 4, 4); return 0; } 

使用模板的C ++版本(从Notinlist的答案改编而来)可能如下所示:

 #include <iostream> #include <cstring> using namespace std; template <size_t N, size_t M> struct IntMatrix { int data[N][M]; IntMatrix() { memset(data, 0, sizeof data); } }; template <size_t N, size_t M> ostream& operator<<(ostream& out, const IntMatrix<N,M>& m) { out << "\n"; for(size_t i = 0; i < N; i++) { for(size_t j = 0; j < M; j++) { out << m.data[i][j] << ", "; } } out << "\n"; return out; } int main() { IntMatrix<4,4> a; cout << a; return 0; } 

或者,你可以使用嵌套的STL容器 – 即vector< vector<int> > – 而不是一个普通的数组。

用C99,你可以做

 static void print(size_t s1, size_t s2, int arr[s1][s2]) { printf("\n"); for(size_t i = 0; i < s1; i++) { for(size_t j = 0; j < s2; j++) { printf("%d, ", arr[i][j]); } } printf("\n"); } 

并称之为

 print(4, 4, a); 

正如罗伯特在评论中指出的,第一个片段实际上涉及不确定的行为。 但是,假设即使在涉及未定义的行为时指针算术总是会产生一个指针(因为在标准中还有其他的限制),所以只有一个可能的结果,也就是说,标准留下了不必要的未定义的东西。

据我所知,代之以

 print(a[0], 4, 4); 

 union m2f { int multi[4][4]; int flat[16]; } *foo = (union m2f *)&a; print(foo->flat, 4, 4); 

将使其合法C.

你可以使用int**来代替。 它更灵活:

 #include <stdio.h> #include <stdlib.h> void print(int **a, int numRows, int numCols ) { int row, col ; for( int row = 0; row < numRows; row++ ) { for( int col = 0; col < numCols ; col++ ) { printf("%5d, ", a[row][col]); } puts(""); } } int main() { int numRows = 16 ; int numCols = 5 ; int **a ; // a will be a 2d array with numRows rows and numCols cols // allocate an "array of arrays" of int a = (int**)malloc( numRows* sizeof(int*) ) ; // each entry in the array of arrays of int // isn't allocated yet, so allocate it for( int row = 0 ; row < numRows ; row++ ) { // Allocate an array of int's, at each // entry in the "array of arrays" a[row] = (int*)malloc( numCols*sizeof(int) ) ; } int count = 1 ; for( int row = 0 ; row < numRows ; row++ ) { for( int col = 0 ; col < numCols ; col++ ) { a[row][col] = count++ ; } } print( a, numRows, numCols ); } 

另一个你可能感兴趣的是像D3DMATRIX这样的结构:

 typedef struct _D3DMATRIX {
    联合{
         struct {
            浮动_11,_12,_13,_14;
            浮动_21,_22,_23,_24;
            浮动_31,_32,_33,_34;
            浮动_41,_42,_43,_44;

         };
         float m [4] [4];
     };
 } D3DMATRIX;

 D3DMATRIX myMatrix;

关于这个小myMatrix.m[0][0]的甜蜜之处是你可以使用myMatrix.m[0][0] (来访问第一个元素),或者你也可以使用myMatrix._11来访问同样的元素。 工会是秘密。

 #include<cstdio> template <size_t N, size_t M> struct DataHolder { int data[N][M]; DataHolder() { for(int i=0; i<N; ++i) for(int j=0; j<M; ++j) data[i][j] = 0; } }; template <size_t N, size_t M> void print(const DataHolder<N,M>& dataHolder) { printf("\n"); for(int i = 0; i<N; i++) { for(int j = 0; j<M; j++) { printf("%d, ", dataHolder.data[i][j]); } } printf("\n"); } int main() { DataHolder<4,4> a; print(a); } 

除了在C99中使用变长数组之外,如果在编译时不知道数组的大小,那么你就不能真正地编写一个接受multidimensional array的函数,参见C-FAQ的 问题6.19 。 处理这个问题的最好方法是使用dynamic分配的内存模拟multidimensional array。 问题6.16对解释这样做的细节做了很好的工作。

简而言之,您可以更改程序如下

 void print(int arr[], int s1, int s2) { ... printf("%d,", *(a+i + s2*j)); ... print((int*)a,4,4); 

这将需要一个更好的答案来解释C和C ++中指针和指针算术和数组之间的区别。 我现在不会启动。 也许别人?

我显然不会像你代码中的其他海报一样震惊。 在打印函数头文件中最让我困扰的是,对于一个你不打算改变初始指针的数组,你使用了双重间接(实际上它不能做,因为它是一个常量)。 @ | V | lad答案通过将一个或两个维度设置为一个固定的常量来解决这个问题,但是通过s1和s2变得毫无用处。

一切都取决于你真正想做的事情。 是打印一个通用的数组打印function或某些数组types专门的?

首先要做的是获得正确的types。 如果C ++的规则在数组types方面与C相同(我敢肯定他们是这样),然后给定声明

 int a[4][4]; 

expression式atypes为int [4][4] ,当传递给print时,它被隐式转换(“decays”)为int (*)[4]的指针types(指向int的4元素数组)你需要改变print

 void print(int (*arr)[4], int s1, int s2) { int i, j; for(i = 0; i<s1; i++) for(j = 0; j<s2; j++) printf("%d, ", arr[i][j]); } 

expression式arr[i]隐含地解除对arr引用,所以你不需要arr显式的解引用。

缺点是print只能处理int的Nx4数组; 如果你想处理其他数组大小,你需要采取不同的方法。

你可以做的一件事就是不要传递数组,传递第一个元素的地址,并且手动计算偏移量,如下所示:

 int main() { int a[4][4] = {{0}}; print(&a[0][0],4,4); // note how a is being passed } void print(int *arr, int s1, int s2) // note that arr is a simple int * { int i, j; for (i = 0; i < s1; i++) for (j = 0; j < s2; j++) printf("%d, ", arr[i * s2 + j]); } 

multidimensional array是连续的内存块。 所以你可以这样做:

 #include <stdio.h> void pa(const int *a, int y, int x) { int i, j; for (i=0;i<y;i++) { for (j=0;j<x;j++) printf("%i", *(a+j+i*x)); printf("\n"); } } int main() { int a[4][3] = { {1,2,3}, {4,5,6}, {4,5,6}, {7,8,9} }; pa(a[0], 4, 3); return 0; } 

它也适用于C ++;

我只想显示Bobobobo的答案的C ++版本。

 int numRows = 16 ; int numCols = 5 ; int **a ; a = new int*[ numRows* sizeof(int*) ]; for( int row = 0 ; row < numRows ; row++ ) { a[row] = new int[ numCols*sizeof(int) ]; } 

其余的代码和bobobobo的一样。

 #include<stdio.h> void print(int (*arr)[4], int s1, int s2) { int i, j; for(i = 0; i<s1; i++) for(j = 0; j<s2; j++) printf("%d, ", arr[i][j]); } int main() { int a[4][4] = {{6}}; print(a,4,4); } 

这将编译编辑:有人已经发布了这个解决scheme我的坏