I know there is several questions about that which gives good (and working) solutions, but none IMHO which says clearly what is the best way to achieve this. So, suppose we have some 2D array :
我知道有几个问题可以提供良好的(和工作的)解决方案,但是没有一个能清楚地说明实现这一目标的最佳途径是什么。假设我们有一些二维数组:
int tab1[100][280];
We want to make a pointer that points to this 2D array. To achieve this, we can do :
我们要做一个指向这个二维数组的指针。为此,我们可以做到:
int (*pointer)[280]; // pointer creation
pointer = tab1; //assignation
pointer[5][12] = 517; // use
int myint = pointer[5][12]; // use
or, alternatively :
或者,或者:
int (*pointer)[100][280]; // pointer creation
pointer = &tab1; //assignation
(*pointer)[5][12] = 517; // use
int myint = (*pointer)[5][12]; // use
OK, both seems to work well. Now I would like to know :
好吧,这两种方法似乎都很有效。现在我想知道:
- what is the best way, the 1st or the 2nd ?
- 什么是最好的方法,第一个还是第二个?
- are both equals for the compiler ? (speed, perf...)
- 两者都等于编译器吗?(速度、性能…)
- is one of these solutions eating more memory than the other ?
- 这些解决方案中的一种比另一种方法吃得更多吗?
- what is the more frequently used by developers ?
- 开发人员使用的频率越高?
3 个解决方案
#1
21
//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
Using pointer2
or pointer3
produce the same binary except manipulations as ++pointer2
as pointed out by WhozCraig.
使用pointer2或pointer3产生的二进制代码与WhozCraig所指出的++pointer2操作相同。
I recommend using typedef
(producing same binary code as above pointer3
)
我建议使用typedef(生成与上面pointer3相同的二进制代码)
typedef int myType[100][280];
myType *pointer3;
Note: Since C++11, you can also use keyword using
instead of typedef
注意:由于c++ 11,您也可以使用关键字而不是typedef。
using myType = int[100][280];
myType *pointer3;
in your example:
在你的例子:
myType *pointer; // pointer creation
pointer = &tab1; // assignation
(*pointer)[5][12] = 517; // set (write)
int myint = (*pointer)[5][12]; // get (read)
Note: If the array tab1
is used within a function body => this array will be placed within the call stack memory. But the stack size is limited. Using arrays bigger than the free memory stack produces a stack overflow crash.
注意:如果在函数body =>中使用数组tab1,则该数组将被放置在调用堆栈内存中。但是栈的大小是有限的。使用比空闲内存堆栈更大的数组会产生堆栈溢出崩溃。
The full snippet is online-compilable at gcc.godbolt.org
完整的代码片段可以在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;
}
#2
9
int *pointer[280];
//Creates 280 pointers of type int.
int *指针[280];//创建int类型的280个指针。
In 32 bit os, 4 bytes for each pointer. so 4 * 280 = 1120 bytes.
在32位操作系统中,每个指针4字节。4 * 280 = 1120字节。
int (*pointer)[100][280];
// Creates only one pointer which is used to point an array of [100][280] ints.
int(*指针)[100][280];//只创建一个用于指向[100][280]int数组的指针。
Here only 4 bytes.
这里只有4个字节。
Coming to your question, int (*pointer)[280];
and int (*pointer)[100][280];
are different though it points to same 2D array of [100][280].
来到你的问题,int(*指针)[280];int(*指针)[100][280];不同的是,它指向相同的二维数组[100][280]。
Because if int (*pointer)[280];
is incremented, then it will points to next 1D array, but where as int (*pointer)[100][280];
crosses the whole 2D array and points to next byte. Accessing that byte may cause problem if that memory doen't belongs to your process.
因为如果int(*指针)[280];是递增的,然后它指向下一个一维数组,但是作为int(*指针)[100][280];穿过整个2D数组,指向下一个字节。如果内存不属于您的进程,那么访问该字节可能会导致问题。
#3
8
Both your examples are equivalent. However, the first one is less obvious and more "hacky", while the second one clearly states your intention.
两个例子都是等价的。然而,第一个不那么明显,更“hacky”,而第二个则明确表示你的意图。
int (*pointer)[280];
pointer = tab1;
pointer
points to an 1D array of 280 integers. In your assignment, you actually assign the first row of tab1
. This works since you can implicitly cast arrays to pointers (to the first element).
指针指向一个1D数组的280个整数。在赋值中,实际上分配了tab1的第一行。这是可行的,因为您可以隐式地将数组转换为指针(到第一个元素)。
When you are using pointer[5][12]
, C treats pointer
as an array of arrays (pointer[5]
is of type int[280]
), so there is another implicit cast here (at least semantically).
当您使用指针[5][12]时,C将指针作为数组的数组(指针[5]的类型为int[280]),因此这里有另一个隐式的cast(至少在语义上)。
In your second example, you explicitly create a pointer to a 2D array:
在第二个示例中,您显式地创建了一个指向2D数组的指针:
int (*pointer)[100][280];
pointer = &tab1;
The semantics are clearer here: *pointer
is a 2D array, so you need to access it using (*pointer)[i][j]
.
这里的语义更清楚:*指针是一个2D数组,因此您需要使用(*指针)[i][j]访问它。
Both solutions use the same amount of memory (1 pointer) and will most likely run equally fast. Under the hood, both pointers will even point to the same memory location (the first element of the tab1
array), and it is possible that your compiler will even generate the same code.
这两个解决方案都使用相同数量的内存(1个指针),并且很可能运行得同样快。在后台,两个指针甚至指向相同的内存位置(tab1数组的第一个元素),而且编译器甚至可能生成相同的代码。
The first solution is "more advanced" since one needs quite a deep understanding on how arrays and pointers work in C to understand what is going on. The second one is more explicit.
第一个解决方案是“更高级的”,因为对于数组和指针如何在C中工作以理解正在发生的事情,需要非常深入的理解。第二个是更明确的。
#1
21
//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
Using pointer2
or pointer3
produce the same binary except manipulations as ++pointer2
as pointed out by WhozCraig.
使用pointer2或pointer3产生的二进制代码与WhozCraig所指出的++pointer2操作相同。
I recommend using typedef
(producing same binary code as above pointer3
)
我建议使用typedef(生成与上面pointer3相同的二进制代码)
typedef int myType[100][280];
myType *pointer3;
Note: Since C++11, you can also use keyword using
instead of typedef
注意:由于c++ 11,您也可以使用关键字而不是typedef。
using myType = int[100][280];
myType *pointer3;
in your example:
在你的例子:
myType *pointer; // pointer creation
pointer = &tab1; // assignation
(*pointer)[5][12] = 517; // set (write)
int myint = (*pointer)[5][12]; // get (read)
Note: If the array tab1
is used within a function body => this array will be placed within the call stack memory. But the stack size is limited. Using arrays bigger than the free memory stack produces a stack overflow crash.
注意:如果在函数body =>中使用数组tab1,则该数组将被放置在调用堆栈内存中。但是栈的大小是有限的。使用比空闲内存堆栈更大的数组会产生堆栈溢出崩溃。
The full snippet is online-compilable at gcc.godbolt.org
完整的代码片段可以在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;
}
#2
9
int *pointer[280];
//Creates 280 pointers of type int.
int *指针[280];//创建int类型的280个指针。
In 32 bit os, 4 bytes for each pointer. so 4 * 280 = 1120 bytes.
在32位操作系统中,每个指针4字节。4 * 280 = 1120字节。
int (*pointer)[100][280];
// Creates only one pointer which is used to point an array of [100][280] ints.
int(*指针)[100][280];//只创建一个用于指向[100][280]int数组的指针。
Here only 4 bytes.
这里只有4个字节。
Coming to your question, int (*pointer)[280];
and int (*pointer)[100][280];
are different though it points to same 2D array of [100][280].
来到你的问题,int(*指针)[280];int(*指针)[100][280];不同的是,它指向相同的二维数组[100][280]。
Because if int (*pointer)[280];
is incremented, then it will points to next 1D array, but where as int (*pointer)[100][280];
crosses the whole 2D array and points to next byte. Accessing that byte may cause problem if that memory doen't belongs to your process.
因为如果int(*指针)[280];是递增的,然后它指向下一个一维数组,但是作为int(*指针)[100][280];穿过整个2D数组,指向下一个字节。如果内存不属于您的进程,那么访问该字节可能会导致问题。
#3
8
Both your examples are equivalent. However, the first one is less obvious and more "hacky", while the second one clearly states your intention.
两个例子都是等价的。然而,第一个不那么明显,更“hacky”,而第二个则明确表示你的意图。
int (*pointer)[280];
pointer = tab1;
pointer
points to an 1D array of 280 integers. In your assignment, you actually assign the first row of tab1
. This works since you can implicitly cast arrays to pointers (to the first element).
指针指向一个1D数组的280个整数。在赋值中,实际上分配了tab1的第一行。这是可行的,因为您可以隐式地将数组转换为指针(到第一个元素)。
When you are using pointer[5][12]
, C treats pointer
as an array of arrays (pointer[5]
is of type int[280]
), so there is another implicit cast here (at least semantically).
当您使用指针[5][12]时,C将指针作为数组的数组(指针[5]的类型为int[280]),因此这里有另一个隐式的cast(至少在语义上)。
In your second example, you explicitly create a pointer to a 2D array:
在第二个示例中,您显式地创建了一个指向2D数组的指针:
int (*pointer)[100][280];
pointer = &tab1;
The semantics are clearer here: *pointer
is a 2D array, so you need to access it using (*pointer)[i][j]
.
这里的语义更清楚:*指针是一个2D数组,因此您需要使用(*指针)[i][j]访问它。
Both solutions use the same amount of memory (1 pointer) and will most likely run equally fast. Under the hood, both pointers will even point to the same memory location (the first element of the tab1
array), and it is possible that your compiler will even generate the same code.
这两个解决方案都使用相同数量的内存(1个指针),并且很可能运行得同样快。在后台,两个指针甚至指向相同的内存位置(tab1数组的第一个元素),而且编译器甚至可能生成相同的代码。
The first solution is "more advanced" since one needs quite a deep understanding on how arrays and pointers work in C to understand what is going on. The second one is more explicit.
第一个解决方案是“更高级的”,因为对于数组和指针如何在C中工作以理解正在发生的事情,需要非常深入的理解。第二个是更明确的。