问题
Here is the thing. I can completely understand a concept of a multidimensional array (let's consider 2D for a while) made by pointer to array to pointers and so on...
We do something like this:
// we can use dynamically defined size n and m
int n = 3, m = 5 ;
int **T = new int *[n];
for (int i = 0 ; i < n ; ++i)
T[i] = new int[m];
What we got is: (Check if I'm right here)
- 3 blocks of memory of 5 ints, placed somewhere in memory
- One additional block of memory of same size as number of the blocks of ints (number of rows). This block is an array of pointers (usually 4 bytes for pointer like int) to those int rows.
- What we are interested in most - that is T which is of type (**T) - a pointer to pointer. Which is exactly a pointer to an array of pointer, because in C++ an array is in fact a pointer pointing to a block of memory so t[] or t[0] means *t, and t[x] means *(t+x).
Now the problem is when we do sth like this:
int n = 3, m = 5 ;
int T[n][m] ;
What we've got is not what w could have doing the thing I showed before. We get sth strange. What is T? When printfing T, we get the same value as T[0]. It looks like we reserved a block of ints sized n*m without additional array of pointers to rows.
My question is: does the compiler remembers the dimension of the array and number of rows and columns? And when asking for T[i][j] it actually asks for *(T+i*n+j) so this n is stored somewhere? The problem is when we are trying to pass this thing (T) to a function. I dont know why but if n and m were constants its possible to pass T as a pointer to this array to function like in this program:
#include <stdio.h>
const int n = 3, m = 4 ; // this is constant!
void add_5(int K[][m])
{
for (int i = 0 ; i < n ; ++i)
for (int j = 0 ; j < m ; j++)
K[i][j] += 5 ;
}
int main()
{
// n x m array the most straight forward method
int T[n][m] ;
for (int i = 0 ; i < n ; ++i)
for (int j = 0 ; j < m ; ++j)
T[i][j] = i*m + j ;
for (int i = 0 ; i < n ; ++i)
{
for (int j = 0 ; j < m ; j++)
printf("%d ",T[i][j]) ;
printf("\n") ;
}
printf("\n") ;
// adding 5 to all cells
add_5(T) ;
printf("it worked!!\n") ;
for (int i = 0 ; i < n ; ++i)
{
for (int j = 0 ; j < m ; j++)
printf("%d ",T[i][j]) ;
printf("\n") ;
}
int ss ;
scanf("%d",&ss) ;
}
But if n and m aren't constant we cant. So what I need is to pass dynamically created multidimensional array's pointer to a function without manually allocating memory for that. How to do this?
回答1:
in C++ an array is in fact a pointer pointing to a block of memory
Absolutely not. An array is entirely separate from a pointer. The reason you might have this confusion is because of a standard conversion called array-to-pointer conversion. Consider:
int arr[10];
The variable arr
denotes an array. It's not a pointer at all. It just so happens that in many circumstances, the name of an array will be converted to a pointer to its first element. That is, the conversion turns it into an int*
.
int T[n][m] ;
In this case, T
is an "array of n
array of m
int
s". You mentioned that printing both T
and T[0]
give the same result, and this is due to array-to-pointer conversion.
The expression
T
can be converted to a pointer to the first element; that is, anint (*)[m]
, because the first element ofT
is itself an array withm
elements.The expression
T[0]
can be converted to a pointer to the first element of the first subarray. So you get a pointer to the elementT[0][0]
of typeint*
.
These pointers hold the same address because of the way an array is laid out in memory. The address that an array begins at is the same address as the first element of that array. However, the pointers do not behave in the same way. If you increment the pointer resulting from T
, you move along to the next subarray. If you increment the pointer resulting from T[0]
, you move along to the next int
.
It might help you to look at a diagram of how a 2D array is laid out in memory compared to a dynamically allocated "2D array". A 3-by-3 2D array would look like this:
0,0 0,1 0,2 1,0 1,1 1,2 2,0 2,1 2,2
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│ int │ int │ int │ int │ int │ int │ int │ int │ int │
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
Whereas if you dynamically allocated a 3-by-3 "2D array":
┌─────┐
│ │ // The int**
└──╂──┘
┃
▼
┌─────┬─────┬─────┐
│ │ │ ┿━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ // An array of int*
└──╂──┴──╂──┴─────┘ ┃
┃ ┗━━━━━━━━━━━━━━━┓ ┃
▼ ▼ ▼
┌─────┬─────┬─────┐ ┌─────┬─────┬─────┐ ┌─────┬─────┬─────┐
│ int │ int │ int │ │ int │ int │ int │ │ int │ int │ int │ // Arrays of ints
└─────┴─────┴─────┘ └─────┴─────┴─────┘ └─────┴─────┴─────┘
0,0 0,1 0,2 1,0 1,1 1,2 2,0 2,1 2,2
does the compiler remembers the dimension of the array and number of rows and columns?
Yes, if you have a variable with array type, the size of the array is part of that type. The compiler always knows the type of a variable.
And when asking for T[i][j] it actually asks for *(T+i*n+j) so this n is stored somewhere?
The expression T[i][j]
is equivalent to *(*(T + i) + j)
. Let's understand what this does. First, array-to-pointer conversion is undergone by T
, giving an int (*)[m]
. We then add i
to this to move along to point at the i
th subarray. This is then dereferenced to get the subarray. Next, this subarray also undergoes array-to-pointer conversion, giving an int*
. You then add j
to this to get a pointer to the j
th int
object in that subarray. This is dereferenced to give that int
.
The problem is when we are trying to pass this thing (T) to a function. I dont know why but if n and m were constants its possible to pass T as a pointer to this array to function
It's actually a lie. You're not passing the 2D array to the function. In fact, there's no such thing as an array type argument. Your argument int K[][m]
is actually equivalent to int (*K)[m]
. That is, all array type arguments are transformed into pointers.
So when you call this function with add_5(T)
, you're not passing the array denoted by T
. T
is actually undergoing array-to-pointer conversion to give you an int (*)[m]
and this pointer is being passed into the function.
回答2:
Here is an example of 2d dynamic array:
const int Mapsize = n
int** GameField2 = 0;
GameField2 = new int*[Mapsize]; // memory alocation
for(int i = 0; i < Mapsize; i++)
GameField2[i] = new int[Mapsize];
for(int j = 0; j < Mapsize; j++)
for(int i = 0; i < Mapsize; i++)
GameField2[i][j] = 0;
if you wish to operate on this array on any function, simply pass the pointer like this:
int Whatver(int** GameField)
{
GameField[a][b]=x;
}
来源:https://stackoverflow.com/questions/16389952/c-multidimensional-array-and-pointers-to-table-of-pointers