我正在实验c中指向多维数组的指针的概念。假设我想通过函数处理多维数组。代码看起来像这样:
#include <stdio.h>
void proc_arr(int ***array)
{
// some code
}
int main(int argc, char **argv)
{
int array[10][10];
for(int i = 0; i < 10; i++)
{
for(int j = 0; j < 10; j++)
{
array[i][j] = i * j;
}
}
proc_arr(&array);
return 0;
}
问题是,当我想在proc_arr
中访问array
时,我不能。根据我的理解,我们应该这样访问它:
void proc_arr(int ***array)
{
(*array)[0][1] = 10;
}
所以我解引用array
来告诉编译器我想去那个地址并获得值。但不知何故,它崩溃了。我已经尝试了*
和括号的几种组合,仍然不能使它工作。我很确定这是因为我不理解指针和指针的指针。
哦,我注意到如果我们使用char **
(字符串数组)也是不同的,就像argv和envp一样。但是对于envp,我可以用(*envp)
访问它。为什么?
下面是处理envp的函数:
int envplen(char ***envp)
{
int count = 0;
while((*envp)[count] != NULL)
{
count++;
}
return count;
}
此外,我能否以某种方式访问envplen
函数中的envp
,只有envp
,但仍然通过引用传递它?
谢谢。
这个问题是因为在堆栈上分配的int array[10][10]
并不像您想象的那样布局内存。因为数组不是指针。内存仍然以线性数组的形式排列,而不是"二维"数组,尽管下标可能表明了这一点。换句话说,int array[10][10]
的内存如下所示:
starting address: ending address:
| Block_1 of 10 int | Block_2 of 10 int | ... | Block_10 of 10 int |
所以当你隐式地将数组转换为int***
,然后尝试访问像(*array)[1][10]这样的数组时,它实际上转换为类似*(*((*array) + 1) + 10)
的东西,并且这种操作的内存布局希望看到像下面这样的内存设置:
int*** array
|
|
| Pointer |
|
|
| Pointer_0 | Pointer_1 | ... | Pointer 10 |
| | |
| | | Block of 10 int |
| |
| | Block of 10 int |
|
|Block of 10 int|
类型不匹配。给定声明int array[10][10]
,表达式&array
的类型将是int (*)[10][10]
, 而不是 int ***
。如果将函数原型改为read
void proc_arr(int (*array)[10][10])
那么你的代码应该可以正常工作。
下表显示了给定特定声明的各种数组表达式的类型。
<>之前声明:T a[M];表达式类型衰减为---------- ---- ---------a T [M] T *& T (*)[M]* T[我]T申报:T a[M][N];表达式类型衰减为---------- ---- ---------T [M][N] T (*)[N]和T (*) [M] . [N]*a T [N] T *a[i] T [N] T *&a[i] T (*)[N]* T[我]一个T[我][j]申报:T a[M][N][O];表达式类型衰减为---------- ---- ---------a T [M][N][O] T (*)[N][O]&a T (*)[M][N][O]*a T [N][O] T (*)[O]a[i] T [N][O] T (*)[O]&a[i] T (*)[N][O]*a[i] T [N] T *a[i][j] T [N] T *a[i][j] T (*)[N]* T[我][j][我][j] [k] T之前高维数组的模式应该是清晰的。
这行不通:
void proc_arr(int ***array)
{
(*array)[0][1] = 10;
}
因为,在幕后,编译器必须将其转换为相对于数组开始的内存偏移量。这意味着它需要知道数组的维数。您没有在函数签名中声明这些