如何将多维数组传递给C和c++中的函数

时间:2022-07-05 21:36:13
#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);
}

This works in C, but not in C++.

这在C语言中有效,但在c++中无效。

error:

错误:

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

Why does it not work in C++? What change is needed to be made?

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

12 个解决方案

#1


23  

This code will not work in either C or C++. An array of type int[4][4] is not convertible to a pointer of type int ** (which is what int *arr[] stands for in parameter declaration). If you managed to compile it in C, it is simply because you probably ignored a C compiler warning of basically the same format as the error message you got from C++ compiler. (Sometimes C compilers issue warnings for what is essentially an error.)

这段代码在C或c++中都不能工作。类型int[4][4]的数组不可转换为类型int **的指针(这是int *arr[]在参数声明中所表示的)。如果您设法用C编译它,那只是因为您可能忽略了一个C编译器警告,其格式与您从c++编译器得到的错误消息基本相同。(有时C编译器会对本质上是错误的内容发出警告。)

So, again, don't make assertions that are not true. This code does not work in C. In order to convert a built-in 2D array into a int ** pointer you can use a technique like this one

所以,同样,不要做出不正确的断言。此代码在c中不起作用,为了将内置的2D数组转换为int **指针,您可以使用像这样的技术。

Converting multidimensional arrays to pointers in c++

将多维数组转换为c++中的指针

(See the accepted answer. The problem is exactly the same.)

(见接受的答案。问题完全一样。

EDIT: The code appears to work in C because another bug in the printing code is masquerading the effects of the bug in array passing. In order to properly access an element of an int ** pseudo-array, you have to use expression *(*(arr + i) + j), or better a plain arr[i][j] (which is the same thing). You missed the extra * which made it print something that has absolutely nothing to do with the content of your array. Again, initialize your array in main to something else to see that the results you are printing in C have absolutely nothing to do with the your intended content of the array.

编辑:代码在C语言中似乎可以工作,因为打印代码中的另一个错误是在数组传递中伪装错误的效果。为了正确地访问int **伪数组的元素,您必须使用表达式*(*(*(arr + i) + j),或者使用普通的arr[i][j](这是一回事)。您错过了额外的*,这使得它打印了一些与数组内容完全无关的东西。同样,将数组主初始化到其他东西,以查看您在C中打印的结果与您预期的数组内容没有任何关系。

If you change the printf statement as shown above, your code will most likely crash because of the array-passing bug I described initially.

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

One more time: you cannot pass a int[4][4] array as an int ** pseudo-array. This is what the C++ is telling you in the error message. And, I'm sure, this is what your C compiler told you, but you probably ignored it, since it was "just a warning".

再一次:不能将int[4][4]数组作为int **伪数组传递。这是c++在错误消息中告诉您的。我确定,这就是C编译器告诉你的,但是你可能会忽略它,因为它“只是一个警告”。

#2


13  

The problem is, that

问题是,

int a[4][4];

will actually be stored in a physically continuos memory. So, to access an arbitrary part of your 4x4 array, the function "print" needs to know the dimensions of the array. For example the following little piece of code, will access the same part of the memory in two different ways.

将实际存储在一个物理连续内存中。因此,要访问4x4阵列的任意部分,函数“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);
}

So the memory layout doesn't change but the way of accessing does. It can be visualized like a checkerboard.

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

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

But the real physical memory looks like this.

但实际的物理内存是这样的。

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.

In c++ the data of an array is stored row-by-row and the length of a row (in this case 4) is always necessary to get to the proper memory offset for the next row. The first subscript therefore only indicates the amount of storage that is needed when the array is declared, but is no longer necessary to calculate the offset afterwards.

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

#3


8  

#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);
}

This will work, where by work I mean compile. @AndreyT explained why your version doesn't work already.

这是可行的,我的意思是编译。@AndreyT解释了为什么你的版本不能正常工作。

This is how you should pass a 2d array.

这是传递2d数组的方式。

For clarity, you can also specify both sizes in the function declaration:

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

#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);
}

Both will work.

都工作。

You should also change *((arr+i)+j) to either a[i][j] (preferably) or *(*(arr+i)+j) if your intention is to access the jth element of row i.

如果您打算访问第i行第j个元素,您还应该将*((arr+i)+j)改为a[i][j](最好)或*(*(*(arr+i)+j)。

#4


6  

Here's a version which is both working, but theoretically invalid (see below) C90 and C++98:

这是一个工作的版本,但理论上是无效的(见下文)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;
}

A C++ version using templates (adapted from Notinlist's answer) could look like this:

使用模板(改编自Notinlist的答案)的c++版本可能是这样的:

#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;
}

Alternatively, you could use nested STL containers - ie vector< vector<int> > - instead of a plain array.

或者,您可以使用嵌套的STL容器——ie向量< vector >——而不是普通数组。

With C99, you could do

有了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");
}

and call it as

并调用它

print(4, 4, a);

As Robert pointed out in the comments, the first snippet actually involves undefined behaviour. However, assuming that pointer arithmetics will always result in a pointer even when undefined behaviour is involved (and not blow up your computer), there is only a single possible result because of other restrictions within the standard, ie this is an instance of where the standard leaves something unnecessarily undefined.

正如Robert在评论中指出的,第一个片段实际上涉及到未定义的行为。然而,假设指针算术总是会产生一个指针,即使涉及到未定义的行为(而不是破坏您的计算机),由于标准内部的其他限制,只有一个可能的结果,也就是说,在这个例子中,标准没有定义一些不必要的东西。

As far as I can tell, substituting

就我所知,代入

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

with

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

will make it legal C.

将使之合法。

#5


4  

You can use int** instead. Its much more flexible:

您可以使用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 );
}

Another thing which you may be interested in is a structure like D3DMATRIX:

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

typedef struct _D3DMATRIX {
    union {
        struct {
            float        _11, _12, _13, _14;
            float        _21, _22, _23, _24;
            float        _31, _32, _33, _34;
            float        _41, _42, _43, _44;

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

D3DMATRIX myMatrix ;

The sweet thing about this little tidbit is you can use both myMatrix.m[0][0] (to access the first element), or you can use myMatrix._11 to access that same element as well. The union is the secret.

这个小提示的好处是你可以同时使用myMatrix。m[0][0](用于访问第一个元素),或者您可以使用myMatrix。_11访问相同的元素。工会是秘密。

#6


2  

#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);
}

#7


1  

Aside from using variable-length arrays in C99, you can't really portably write a function to accept a multidimensional array if the sizes of the arrays are not known at compile-time, See Question 6.19 of the C-FAQ. The best way to handle this is to simulate multidimensional arrays using dynamically allocated memory. Question 6.16 does a very good job of explaining the details of doing this.

除了在C99中使用可变长度数组之外,如果在编译时不知道数组的大小,那么实际上不能编写一个函数来接受多维数组,请参见C-FAQ的问题6.19。处理这个问题的最佳方法是使用动态分配的内存来模拟多维数组。问题6.16很好地解释了这个过程的细节。

#8


0  

Short answer, you may change the program as following

简短的回答,你可以改变程序如下。

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

This would need a better answer explaining the differences between pointer and pointer arithmetic and arrays in C and C++. I won't launch into that now. Maybe someone else ?

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

I obviously am not shocked by the same point as other posters in your code. What bother me most in the print function header is that you use a double indirection for an array where you do not intend to change initial pointer back (in fact it can't be done as it is a constant). @|V|lad answer fix this by setting one or two dimensions to a fixed constant, but then passing s1 and s2 become useless.

很明显,我不会被你代码中的其他海报所震惊。打印函数头中最令我困扰的是,对于一个不打算更改初始指针返回的数组,您使用了双重间接(事实上,这是一个常量)。@|V|lad解决方法是将一个或两个维度设置为一个固定常数,然后通过s1和s2变得无用。

All depends of what you really want to do. Is print a general purpose array printing function or a specialized one for some array types ?

这一切都取决于你真正想做什么。打印是一种通用的数组打印函数还是某些数组类型的专用函数?

#9


0  

First thing to do is get the types right. If C++'s rules are the same as C's with respect to array types (I'm pretty sure they are), then given the declaration

首先要做的是正确地获取类型。如果c++的规则与C关于数组类型的规则相同(我很确定它们是),那么给出声明

int a[4][4];

the expression a has type int [4][4], which is implicitly converted ("decays") to a pointer type of int (*)[4] (pointer to 4-element array of int) when passed to print, so you need to change print to

表达式a具有类型为int[4][4]的类型,当传递给print时,该类型被隐式地转换为int(*)[4]的指针类型(指向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]);        
}        

The expression arr[i] implicitly dereferences arr, so you don't need to mess with an explicit dereference.

表达式arr[i]隐式去引用arr,所以您不需要使用显式去引用。

The drawback is that print can only handle Nx4 arrays of int; if you want to handle other array sizes, you'll need to take a different approach.

缺点是打印只能处理int的Nx4数组;如果希望处理其他数组大小,则需要采用不同的方法。

One thing you can do is instead of passing the array, pass the address of the first element, and have print manually compute the offsets, as so:

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

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]);
}

#10


0  

Multidimensional arrays are continuous blocks of memory. So you can do it this way:

多维数组是连续的内存块。你可以这样做:

#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;
}

It also works in C++;

它也适用于c++;

#11


0  

I just want to show C++ version of bobobobo's answer.

我只想展示c++版本的bobobobobobo的答案。

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) ];
}

The rest of code is the same with bobobobo's.

其余的代码与bobobobobobo的相同。

#12


-1  

#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);
}

this will compile edit: someone already posted this solution my bad

这将编译编辑:有人已经张贴这个解决方案我的坏

#1


23  

This code will not work in either C or C++. An array of type int[4][4] is not convertible to a pointer of type int ** (which is what int *arr[] stands for in parameter declaration). If you managed to compile it in C, it is simply because you probably ignored a C compiler warning of basically the same format as the error message you got from C++ compiler. (Sometimes C compilers issue warnings for what is essentially an error.)

这段代码在C或c++中都不能工作。类型int[4][4]的数组不可转换为类型int **的指针(这是int *arr[]在参数声明中所表示的)。如果您设法用C编译它,那只是因为您可能忽略了一个C编译器警告,其格式与您从c++编译器得到的错误消息基本相同。(有时C编译器会对本质上是错误的内容发出警告。)

So, again, don't make assertions that are not true. This code does not work in C. In order to convert a built-in 2D array into a int ** pointer you can use a technique like this one

所以,同样,不要做出不正确的断言。此代码在c中不起作用,为了将内置的2D数组转换为int **指针,您可以使用像这样的技术。

Converting multidimensional arrays to pointers in c++

将多维数组转换为c++中的指针

(See the accepted answer. The problem is exactly the same.)

(见接受的答案。问题完全一样。

EDIT: The code appears to work in C because another bug in the printing code is masquerading the effects of the bug in array passing. In order to properly access an element of an int ** pseudo-array, you have to use expression *(*(arr + i) + j), or better a plain arr[i][j] (which is the same thing). You missed the extra * which made it print something that has absolutely nothing to do with the content of your array. Again, initialize your array in main to something else to see that the results you are printing in C have absolutely nothing to do with the your intended content of the array.

编辑:代码在C语言中似乎可以工作,因为打印代码中的另一个错误是在数组传递中伪装错误的效果。为了正确地访问int **伪数组的元素,您必须使用表达式*(*(*(arr + i) + j),或者使用普通的arr[i][j](这是一回事)。您错过了额外的*,这使得它打印了一些与数组内容完全无关的东西。同样,将数组主初始化到其他东西,以查看您在C中打印的结果与您预期的数组内容没有任何关系。

If you change the printf statement as shown above, your code will most likely crash because of the array-passing bug I described initially.

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

One more time: you cannot pass a int[4][4] array as an int ** pseudo-array. This is what the C++ is telling you in the error message. And, I'm sure, this is what your C compiler told you, but you probably ignored it, since it was "just a warning".

再一次:不能将int[4][4]数组作为int **伪数组传递。这是c++在错误消息中告诉您的。我确定,这就是C编译器告诉你的,但是你可能会忽略它,因为它“只是一个警告”。

#2


13  

The problem is, that

问题是,

int a[4][4];

will actually be stored in a physically continuos memory. So, to access an arbitrary part of your 4x4 array, the function "print" needs to know the dimensions of the array. For example the following little piece of code, will access the same part of the memory in two different ways.

将实际存储在一个物理连续内存中。因此,要访问4x4阵列的任意部分,函数“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);
}

So the memory layout doesn't change but the way of accessing does. It can be visualized like a checkerboard.

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

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

But the real physical memory looks like this.

但实际的物理内存是这样的。

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.

In c++ the data of an array is stored row-by-row and the length of a row (in this case 4) is always necessary to get to the proper memory offset for the next row. The first subscript therefore only indicates the amount of storage that is needed when the array is declared, but is no longer necessary to calculate the offset afterwards.

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

#3


8  

#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);
}

This will work, where by work I mean compile. @AndreyT explained why your version doesn't work already.

这是可行的,我的意思是编译。@AndreyT解释了为什么你的版本不能正常工作。

This is how you should pass a 2d array.

这是传递2d数组的方式。

For clarity, you can also specify both sizes in the function declaration:

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

#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);
}

Both will work.

都工作。

You should also change *((arr+i)+j) to either a[i][j] (preferably) or *(*(arr+i)+j) if your intention is to access the jth element of row i.

如果您打算访问第i行第j个元素,您还应该将*((arr+i)+j)改为a[i][j](最好)或*(*(*(arr+i)+j)。

#4


6  

Here's a version which is both working, but theoretically invalid (see below) C90 and C++98:

这是一个工作的版本,但理论上是无效的(见下文)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;
}

A C++ version using templates (adapted from Notinlist's answer) could look like this:

使用模板(改编自Notinlist的答案)的c++版本可能是这样的:

#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;
}

Alternatively, you could use nested STL containers - ie vector< vector<int> > - instead of a plain array.

或者,您可以使用嵌套的STL容器——ie向量< vector >——而不是普通数组。

With C99, you could do

有了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");
}

and call it as

并调用它

print(4, 4, a);

As Robert pointed out in the comments, the first snippet actually involves undefined behaviour. However, assuming that pointer arithmetics will always result in a pointer even when undefined behaviour is involved (and not blow up your computer), there is only a single possible result because of other restrictions within the standard, ie this is an instance of where the standard leaves something unnecessarily undefined.

正如Robert在评论中指出的,第一个片段实际上涉及到未定义的行为。然而,假设指针算术总是会产生一个指针,即使涉及到未定义的行为(而不是破坏您的计算机),由于标准内部的其他限制,只有一个可能的结果,也就是说,在这个例子中,标准没有定义一些不必要的东西。

As far as I can tell, substituting

就我所知,代入

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

with

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

will make it legal C.

将使之合法。

#5


4  

You can use int** instead. Its much more flexible:

您可以使用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 );
}

Another thing which you may be interested in is a structure like D3DMATRIX:

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

typedef struct _D3DMATRIX {
    union {
        struct {
            float        _11, _12, _13, _14;
            float        _21, _22, _23, _24;
            float        _31, _32, _33, _34;
            float        _41, _42, _43, _44;

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

D3DMATRIX myMatrix ;

The sweet thing about this little tidbit is you can use both myMatrix.m[0][0] (to access the first element), or you can use myMatrix._11 to access that same element as well. The union is the secret.

这个小提示的好处是你可以同时使用myMatrix。m[0][0](用于访问第一个元素),或者您可以使用myMatrix。_11访问相同的元素。工会是秘密。

#6


2  

#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);
}

#7


1  

Aside from using variable-length arrays in C99, you can't really portably write a function to accept a multidimensional array if the sizes of the arrays are not known at compile-time, See Question 6.19 of the C-FAQ. The best way to handle this is to simulate multidimensional arrays using dynamically allocated memory. Question 6.16 does a very good job of explaining the details of doing this.

除了在C99中使用可变长度数组之外,如果在编译时不知道数组的大小,那么实际上不能编写一个函数来接受多维数组,请参见C-FAQ的问题6.19。处理这个问题的最佳方法是使用动态分配的内存来模拟多维数组。问题6.16很好地解释了这个过程的细节。

#8


0  

Short answer, you may change the program as following

简短的回答,你可以改变程序如下。

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

This would need a better answer explaining the differences between pointer and pointer arithmetic and arrays in C and C++. I won't launch into that now. Maybe someone else ?

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

I obviously am not shocked by the same point as other posters in your code. What bother me most in the print function header is that you use a double indirection for an array where you do not intend to change initial pointer back (in fact it can't be done as it is a constant). @|V|lad answer fix this by setting one or two dimensions to a fixed constant, but then passing s1 and s2 become useless.

很明显,我不会被你代码中的其他海报所震惊。打印函数头中最令我困扰的是,对于一个不打算更改初始指针返回的数组,您使用了双重间接(事实上,这是一个常量)。@|V|lad解决方法是将一个或两个维度设置为一个固定常数,然后通过s1和s2变得无用。

All depends of what you really want to do. Is print a general purpose array printing function or a specialized one for some array types ?

这一切都取决于你真正想做什么。打印是一种通用的数组打印函数还是某些数组类型的专用函数?

#9


0  

First thing to do is get the types right. If C++'s rules are the same as C's with respect to array types (I'm pretty sure they are), then given the declaration

首先要做的是正确地获取类型。如果c++的规则与C关于数组类型的规则相同(我很确定它们是),那么给出声明

int a[4][4];

the expression a has type int [4][4], which is implicitly converted ("decays") to a pointer type of int (*)[4] (pointer to 4-element array of int) when passed to print, so you need to change print to

表达式a具有类型为int[4][4]的类型,当传递给print时,该类型被隐式地转换为int(*)[4]的指针类型(指向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]);        
}        

The expression arr[i] implicitly dereferences arr, so you don't need to mess with an explicit dereference.

表达式arr[i]隐式去引用arr,所以您不需要使用显式去引用。

The drawback is that print can only handle Nx4 arrays of int; if you want to handle other array sizes, you'll need to take a different approach.

缺点是打印只能处理int的Nx4数组;如果希望处理其他数组大小,则需要采用不同的方法。

One thing you can do is instead of passing the array, pass the address of the first element, and have print manually compute the offsets, as so:

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

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]);
}

#10


0  

Multidimensional arrays are continuous blocks of memory. So you can do it this way:

多维数组是连续的内存块。你可以这样做:

#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;
}

It also works in C++;

它也适用于c++;

#11


0  

I just want to show C++ version of bobobobo's answer.

我只想展示c++版本的bobobobobobo的答案。

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) ];
}

The rest of code is the same with bobobobo's.

其余的代码与bobobobobobo的相同。

#12


-1  

#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);
}

this will compile edit: someone already posted this solution my bad

这将编译编辑:有人已经张贴这个解决方案我的坏