C指向二维数组

时间:2013-02-11 09:08:05

标签: c arrays pointers

我知道有几个问题可以提供良好(和工作)的解决方案,但没有恕我直言,这清楚地说明了实现这一目标的最佳途径。 所以,假设我们有一些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 
好的,两者似乎都运作良好。现在我想知道:

  • 最好的方式是1号还是2号?
  • 对编译器来说都是等于? (速度,性能...)
  • 这些解决方案中的一种比其他解决方案占用更多内存吗?
  • 开发人员使用频率最高的是什么?

4 个答案:

答案 0 :(得分:25)

//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生成相同的二进制文件,但WhozCraig指出的操作为++pointer2除外。

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

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

注意:从C ++ 11开始,您还可以使用关键字using代替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 =>该数组将被放置在调用堆栈内存中。但堆栈大小有限。使用大于空闲内存堆栈的数组会生成stack overflow crash

完整代码段可在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;
}

答案 1 :(得分:9)

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];穿过整个2D数组并指向下一个字节。如果该内存不属于您的进程,则访问该字节可能会导致问题。

答案 2 :(得分:9)

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

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

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

当您使用pointer[5][12]时,C将pointer视为数组数组(pointer[5]的类型为int[280]),因此还有另一个隐式< / em>在这里施放(至少在语义上)。

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

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

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

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

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

答案 3 :(得分:0)

好吧,这实际上是四个不同的问题。我将一一解答:

对于编译器来说是否相等? (速度,性能...)

是的。指针从类型int (*)[100][280]int (*)[280]的解除引用和衰减对您的CPU始终没有作用。无论如何我不会把它放在一个糟糕的编译器上来生成伪造的代码,但是一个好的优化编译器应该将两个示例都编译成完全相同的代码。

其中一种解决方案比另一种消耗更多的内存吗?

作为我的第一个答案的推论,不。

开发人员更常使用什么?

绝对没有额外的(*pointer)取消引用的变体。对于C程序员来说,第二个前提是假定任何指针实际上都可以是指向数组第一个元素的指针。

最好的方法是第一还是第二?

这取决于您要优化的内容:

  • 惯用代码使用变体1。声明缺少外部尺寸,但所有使用均与C程序员所期望的完全相同。

  • 如果要明确指出要指向数组,可以使用变量2。但是,许多经验丰富的C程序员都会认为,最里面的*后面隐藏着第三维。没有数组维度的情况对大多数程序员来说都很奇怪。