6

我对 C 中的指针和数组的问题感到困惑。

我们先来看一段代码:

//case 1
int **a;
a = (int **)malloc(sizeof(int*)*m);
for(i = 0; i < m; i++)
    a[i] = (int *)malloc(sizeof(int)*n);

//case 2
int b[m][n];

然后,我们知道,b内存中的布局如下:

b[0][0] b[0][1] ... ... b[m-1][n-1]

并且,a 在内存中的布局如下:

a
 \
 _\|
 a[0]  a[1] ... a[m-1]
  |    |
  |    |
  |   \|/
  |   a[1][0] a[1][a] ... a[1][n-1]
 \|/
a[0][1] a[0][2] ... a[0][n-1]

所以,我的问题是:既然a[0..m-1][0..n-1]不连续地存储在内存中,为什么我们可以使用下标运算[]a?换句话说,为什么a[i][j]能得到正确的元素,就b[i][j]这样呢?

4

5 回答 5

3

那是因为a[i][j]等于*(*(a+i) + j)。即使a没有连续存储(可能),指针*(a+i)也会准确指向正确的位置(a[i][0]存储的位置)。

于 2013-09-19T15:50:35.283 回答
2

因为 的元素a是连续存储在内存中的,而每个元素的元素a[n]都是连续存储在内存中的。做int n = a[i][j]基本上等同于做int * p = a[i]; int n = p[j];两个维度在内存中可能不连续并不重要,a因为它们的方式b

于 2013-09-19T15:48:52.697 回答
2

它们都有效,因为编译器为每种情况生成不同的。确实,单次提及的数组和指针以及类似的,双重提及的数组和指向指针的指针具有相似性。

因此,b由于编译器知道这b是一个数组并且是一个连续的内存块,因此它生成的代码如下:

// int c = b[i][j];
int c = *(b + (i*m+j);

但它会生成不同的代码,a因为它是指向指针的指针而不是连续的内存块,每个括号运算符都是取消引用运算符:

// int c  = a[i][j];
int c = *(*(a+i)+j);
于 2013-09-19T15:54:56.670 回答
2

编译器单独处理表达式的每个部分。a[i][j]和之间的主要区别在于b[i][j],因为a是指向 的指针的指针int,所以地址计算会计算a[i]多个指针,但是,因为b是 的数组的数组int,所以地址计算会计算b[i]多个数组。C 使用表达式每个部分的类型来确定如何计算它。

口译步骤a[i][j]如下:

  • a是一个指向一个指针的指针int
  • a[i]被定义为*(a + i)
  • 总和a+ii超出 wherea点的元素。由于a指向指向的指针int,我们计算指向的i指针int以确定新地址。
  • 由于 sum 是一个指向 an 的指针int,因此应用*它会产生一个指向 an 的指针int
  • a[i][j]被定义为*(a[i] + j)。我们已经评估了这a[i]部分。
  • 总和a[i] + jj超出 wherea[i]点的元素。由于a[i]指向int对象,我们计算j int对象以确定新地址。
  • 由于这个 sum 是一个指向 an 的指针int,因此应用*它会产生一个int

口译步骤b[i][j]如下:

  • b是 的数组的m数组n int
  • 由于b是一个数组,因此它被转换为指向其第一个元素的指针,即n int.
  • b[i]被定义为*(b + i)
  • 总和b + ii超出 whereb点的元素。由于b已转换为指向 的数组的指针,我们对 的数组进行n int计数以确定新地址。in int
  • 由于 sum 是指向 的数组的指针n int,因此对其应用*会产生 的数组n int
  • 由于此表达式是另一个数组,因此它被转换为指向其第一个元素 an 的指针int
  • b[i][j]被定义为*(b[i] + j)。我们已经评估了这b[i]部分。
  • 总和b[i] + jj超出 whereb[i]点的元素。由于它指向int,我们计数j int以确定新地址。
  • 由于这个 sum 是一个指向 an 的指针int,因此应用*它会产生一个int
于 2013-09-19T16:14:23.530 回答
0

为了a[i][j]

基本上我们说:

我们需要由 指向的第 i 个指针a,然后我们需要由该内部指针指向的第 j 个 int。

只有使用这个概念我们才能写出

foo(int **a, int rows, int cols){
//...
//acess a[i][j] ; 0<=i<rows, 0<=j<cols
}
于 2013-09-19T15:51:47.570 回答