5

假设我们有: int A [5] [2] [3]; 现在,如果我这样做: A[1][0][0] = 4; 这是否意味着:

1.) A [1] 和 A [1][0] 是指针?

2.) 如果 A[1] 是一个指针,那么它将存储指针 A[1][0] 的地址?

3.) 如果 A[1][0] 是一个指针,那么它将存储 A[1][0][0] 的地址,它不是一个指针,而只是一个存储 4 值的变量?

如果以上几点都是正确的,那么为什么下面的代码会给我们相同的整数地址:

int main(void)
{
        int A [5] [2] [3];
    A[1][0][0]=4;

    printf("%d\n\n", A[1]);
    printf("%d\n\n", A[1][0]);
    printf("%d\n\n",&A[1][0][0]);

        system("pause");
}

在这里,我假设 A[1] 是一个指针,它指向另一个指针 A[1][0],因此存储了指针 A[1][0] 的地址。并且, A[1][0] 是指向 VARIABLE A[1][0][0] 的指针,因此存储了 VARIABLE A[1][0][0] 的地址。

请帮我!

4

6 回答 6

4

要正确回答您的问题,请阅读行优先顺序,这就是多维数组在 C 中的存储方式。维基百科的文章有点过于简洁,但其中一个可能更清楚:

http://webster.cs.ucr.edu/AoA/Windows/HTML/Arraysa2.html http://archive.gamedev.net/archive/reference/articles/article1697.html http://www.ibiblio.org/ pub/languages/fortran/append-c.html

也有这个问题


直接回答您的观点,假设您知道行主要存储的工作原理:

int A[5][2][3]声明一个长度为 5*2*3 整数的连续内存区域:五个数组,每个数组有两个数组,每个数组三个整数。数组彼此相邻存储在线性内存中,因此

&A[0][0][0] == A
&A[0][0][1] == A+1
&A[0][1][0] == A+(1*3)
&A[3][1][2] == A+(3*(2*3))+(1*3)+2

A[1]从技术上讲,它不是指针,而是数组。这是一个int [2][3]数组。但我发现比起考虑A[5][2][3]一个平坦的内存区域要清楚得多,它长 30 个整数。

A[0][0][0] is the first integer in that region. 
A[0][0][1] is the second integer. 
A[0][0][2] is the third integer. 
A[0][1][0] is the fourth integer in this flat region. 
A[0][1][1] is the fifth integer. 
And so on until A[1][0][0] is the eleventh integer. 

因此地址A[1][0][0]是过去十个整数A[0][0][0]&A[1][0][0] - &A[0][0][0] == 10。因为 C 语言对数组和指针之间的区别非常松散,A[1]所以当您在表达式中使用它时,它被解释为好像它是一个地址,即使它实际上意味着“五个数组中的两个数组中的第一个元素三个整数”又是“由三个整数组成的两个数组的数组”。

结果是它A[1]存储指针,它一个指针。&A[0][0][0]从到的每个内存地址都&A[5][2][3]-1在多维数组中存储一个整数。

您在第 (2) 和 (3) 点中想到的是指向数组的指针数组,它们是不同的。

这用图片更容易解释,这就是为什么你应该找到一本关于 C 数组的合适的教科书或文章。

一般来说,在学习 C 中的指针和数组时,我建议您暂时忘记语言本身,并假装您是 Dennis Ritchie 在具有 56kb 平面 RAM 的 PDP-11 计算机上发明 C。拿一张大方格纸,连续编号它的单元格,假装它代表你的 RAM,每个单元格是一个字节,你可以用铅笔和纸完成你的指针数学

C 是在那种环境中发明的,了解它的起源将使现代语言更加明智。

附带说明一下,当我尝试编写此答案时,Stack Overflow 的标记语言反复更改并搞砸了我上面的数组示例中的索引。因此,如果您看到那里的任何数字似乎超出了其数组的范围,那么这是编辑器引入的错误。

于 2012-05-24T23:58:23.537 回答
1

c 中的多维数组不使用指针。尽管指针对指针的访问可能看起来相似,但实际数据可能不连续,并且存储所有地址存在开销。C 中多维数组的访问是一种语法糖:

char a[5][7][9]
a[d][h][w]  <<==>>  ((char*)a)[((9*7*d)+(9*h)+w] 

C 数组都共享它们衰减的属性(或自动变成指向数组中第一个元素的指针)。因此,

a[1]  (char[7][9])    --decay-->   ((*char)[5][9]) pointer to char array
&a[1] ((*char)[5][9])  no decay

两者是等价的,因为在后面你明确地“衰减”了指针,而它在第一个中自动发生。

于 2012-05-24T23:39:10.940 回答
1

如果您有动态数组(即使用malloc/分配calloc),您的假设将是正确的。

然而,静态数组被分配为连续的内存块,并且只是指向第一个元素的指针。当你写A[X][Y][Z]它时,它基本上相当于*(A + X*YSIZE*ZSIZE + Y*SIZE + Z),而不是*(*(*(A+X) + Y) + Z)。这允许更快地访问数据(您不需要访问中间指针),但需要将所有数据分配在一个块中并且具有常规大小。

是有关 C 中静态数组与动态数组不可互换性的更多信息。

于 2012-05-24T23:40:33.880 回答
1

变量 A 是 5 * 2 * 3 个整数,作为一个块一起分配。(即 30 个整数)。

声明“int A[5][2][3];”中不涉及指针 - 唯一留出的空间是保存 30 个 int 值。

当您使用 A 和下标编写表达式时,因为您已经说过有 3 个维度,所以您必须提供所有 3 个维度才能指定您正在访问或更改的 int 值。如果您使用的下标少于 3 个,则您只是部分指定了您正在访问的内容;惯例是这样的引用被视为对整个空间相关部分的地址的请求。

于 2012-05-24T23:41:58.240 回答
0

阅读行主要订单

是的,那根本没有帮助,我认为C是主要的专栏。(忘记所有的东西是什么意思)

于 2012-05-24T23:29:59.440 回答
0

这可能有点奇怪,但这是我的解释。想象一下,你有六个不同的人,从 1 到 6 编号,他们从 1 到 6 相应地排列。如果你告诉这个团队(这六个人)分为两组,其中前三个(1-3)是在 A 组,其余(4-6 人)在 B 组。

[1 2 3] [4 5 6]

那么,如果我告诉你谁是 TEAM 中的第一个?你会说第一个!但是如果我问你谁是THE TEAM A组的第一个成员?一样的,第一人称!

另外,如果我告诉你谁是团队中的第四位成员?你会说第四个!那么,如果我问你谁是THE TEAM B组的第一个成员呢?第四个也是一样。


同样的故事也发生在你身上;A[1] 是指向大数组(The Team)开头的指针,其中 A[1][0]指示指向数组(A[ 1]),这是相同的!然后你说,&A[1][0][0],这就像要问驻留在大数组中的第一个内部数组的第一个成员,你的号码是多少?然后,他将重播相同的内容。

不同的是指针的类型以及它们的解释方式,但它们的值是相同的。这是因为数组以连续的方式存储元素。

于 2012-05-25T02:22:57.063 回答