C指向二维数组

我知道有几个问题可以提供良好(和工作)的解决方案,但没有恕我直言,这清楚地说明了实现这一目标的最佳方法。 所以,假设我们有一些2D数组:

int tab1[100][280]; 

我们想要制作一个指向这个2D数组的指针。 为实现这一目标,我们可以做到:

 int (*pointer)[280]; // pointer creation pointer = tab1; //assignation pointer[5][12] = 517; // use int myint = pointer[5][12]; // use 

或者,或者:

 int (*pointer)[100][280]; // pointer creation pointer = &tab1; //assignation (*pointer)[5][12] = 517; // use int myint = (*pointer)[5][12]; // use 

好的,两者似乎都运作良好。 现在我想知道:

  • 什么是最好的方式,第一或第二?
  • 两者都等于编译器? (速度,性能…)
  • 这些解决方案中的一种比其他解决方案占用更多内存?
  • 开发人员更常使用的是什么?

 //defines an array of 280 pointers (1120 or 2240 bytes) int *pointer1 [280]; //defines a pointer (4 or 8 bytes depending on 32/64 bits platform) int (*pointer2)[280]; //pointer to an array of 280 integers int (*pointer3)[100][280]; //pointer to an 2D array of 100*280 integers 

使用pointer2pointer3产生相同的二进制文件,除了像++pointer2所指出的++pointer2那样的操作 。

我建议使用typedef (产生与上面pointer3相同的二进制代码)

 typedef int myType[100][280]; myType *pointer3; 

注意:从C ++ 11开始,您也可以使用keyword而不是typedef

 using myType = int[100][280]; myType *pointer3; 

在你的例子中:

 myType *pointer; // pointer creation pointer = &tab1; // assignation (*pointer)[5][12] = 517; // set (write) int myint = (*pointer)[5][12]; // get (read) 

注意:如果在函数体中使用数组tab1 =>此数组将被放置在调用堆栈内存中。 但堆栈大小有限。 使用大于空闲内存堆栈的数组会导致堆栈溢出崩溃 。

完整的代码片段可在线编辑, url为gcc.godbolt.org

 int main() { //defines an array of 280 pointers (1120 or 2240 bytes) int *pointer1 [280]; static_assert( sizeof(pointer1) == 2240, "" ); //defines a pointer (4 or 8 bytes depending on 32/64 bits platform) int (*pointer2)[280]; //pointer to an array of 280 integers int (*pointer3)[100][280]; //pointer to an 2D array of 100*280 integers static_assert( sizeof(pointer2) == 8, "" ); static_assert( sizeof(pointer3) == 8, "" ); // Use 'typedef' (or 'using' if you use a modern C++ compiler) typedef int myType[100][280]; //using myType = int[100][280]; int tab1[100][280]; myType *pointer; // pointer creation pointer = &tab1; // assignation (*pointer)[5][12] = 517; // set (write) int myint = (*pointer)[5][12]; // get (read) return myint; } 

int *pointer[280]; //创建280个int类型的指针。

在32位操作系统中,每个指针有4个字节。 所以4 * 280 = 1120字节。

int (*pointer)[100][280]; //仅创建一个指针,用于指向[100] [280]整数的数组。

这里只有4个字节。

来到你的问题, int (*pointer)[280];int (*pointer)[100][280]; 虽然它指向[100] [280]的相同2D数组,但它们是不同的。

因为如果int (*pointer)[280]; 增加,然后它将指向下一个1D数组,但其中int (*pointer)[100][280]; 穿过整个2Darrays并指向下一个字节。 如果该内存不属于您的进程,则访问该字节可能会导致问题。

你的例子都是等价的。 然而,第一个不太明显,更“hacky”,而第二个明确表明你的意图。

 int (*pointer)[280]; pointer = tab1; 

pointer指向280个整数的1D数组。 在您的作业中,您实际上分配了tab1的第一 。 这是有效的,因为您可以隐式地将数组转换为指针(到第一个元素)。

当你使用pointer[5][12] ,C将pointer视为数组数组( pointer[5]的类型为int[280] ),因此这里有另一个隐式转换 (至少在语义上)。

在第二个示例中,您显式创建指向2D数组的指针:

 int (*pointer)[100][280]; pointer = &tab1; 

这里的语义更清晰: *pointer是一个2D数组,所以你需要使用(*pointer)[i][j]来访问它。

两种解决方案都使用相同数量的内存(1个指针),并且很可能同样快速地运行。 在引擎盖下,两个指针甚至会指向相同的内存位置( tab1数组的第一个元素),并且您的编译器甚至可能生成相同的代码。

第一个解决方案是“更高级”,因为人们需要非常深入地了解数组和指针如何在C中工作以了解正在发生的事情。 第二个是更明确的。