这个陈述是否有意义,请参阅“ C编程:现代方法”,第269页第2版
正如一维数组的名称可以用作指针一样, 任何数组的名称也可以使用,无论它具有多少维度。 但是,需要注意一些事项。 考虑以下数组:
int a[NUM_ROWS][NUM_COLS];
a
不是指向a[0][0];
的指针a[0][0];
相反,它是指向a[0]
的指针。 如果我们从C的角度来看它会更有意义,它不是将二维数组视为二维数组,而是将元素视为一维数组的一维数组。 当用作指针时,a
具有类型int (*) [NUM_COLS]
(指向长度为NUM_COLS
的整数数组的NUM_COLS
)。
我很困惑,因为当我认为“其元素是一维数组的数组”时,我认为是一个锯齿状数组 ,但这不是这里发生的事情..这更像是一个带指针算术的宏?
这是参考类型系统以及它如何处理多维数组? 任何人都能解释一下吗?
是的,它是有道理的,不,它甚至没有谈论“衣衫褴褛”或“锯齿状”arrays。 就在我们说的时候
int a[NUM_ROWS][NUM_COLS];
我们正在创建的是一个数组a
,它的数组是……其他数组。 你可以这样想:
+---------------------------------------+ | +--------+--------+--------+--------+ | a: [0]: | | | | | | | | +--------+--------+--------+--------+ | + + | +--------+--------+--------+--------+ | [1]: | | | | | | | | +--------+--------+--------+--------+ | + + | +--------+--------+--------+--------+ | [2]: | | | | | | | | +--------+--------+--------+--------+ | +---------------------------------------+
(此处NUM_COLS
显然为4, NUM_ROWS
为3.)
两个(或更多)维数组100%类似于简单的单维数组 – 您只需要仔细考虑类比。 如果a
是一个数组,那么在需要其值的表达式中提及a
会导致指向数组的第一个元素&a[0]
的指针。 因此,给定我们所讨论的二维数组, a
值为&a[0]
并且是指向NUM_COLS
整数数组的指针 。
如果多维数组下标要正常工作,它必须以这种方式工作。 如果我们写a[i][j]
,那就被解释为(a[i])[j]
。 a
像往常一样变成指向数组第一个元素的指针,但是a[i]
相当于*(a + i)
,其中指针算术最终被指向元素的大小缩放 – 这是在引擎盖下,它更像是*(a+ i * sizeof(*a))
。 因此sizeof(*a)
必须是sizeof(int [NUM_COLS])
或NUM_COLS * sizeof(int)
。 这样a[i]
就可以得到i
的子arrays,然后j
可以选择子arrays中的一个单元格 – int
单元格。
最后一点说明:我曾经俗称“多维数组”,但严格来说,正如许多常规人士所指出的那样,C没有多维数组; 它只有一维数组,而我们所认为的二维数组实际上就像我们在这里看到的那样,它的元素恰好是其他单维数组。 (如果C具有真正的多维数组,则下标可能看起来像a[i,j]
而不是a[i][j]
。)
附录:尽管你提到了指针算法,并且我提到了指针算法,但重要的是要意识到定义中没有指针 。 只有当我们试图“取值” a
或解释a[i]
等于*(a + i)
时,才会出现指针。
对于涉及指针的数据结构,我们可以对比代码描述的情况
int *a2[NUM_ROWS]; for(i = 0; i < NUM_ROWS; i++) a2[i] = malloc(NUM_COLS * sizeof(int));
这给了我们一个非常不同的内存布局:
+-----+ a2: | | +--------+--------+--------+--------+ | *------->| | | | | | | +--------+--------+--------+--------+ +-----+ | | +--------+--------+--------+--------+ | *------->| | | | | | | +--------+--------+--------+--------+ +-----+ | | +--------+--------+--------+--------+ | *------->| | | | | | | +--------+--------+--------+--------+ +-----+
这就是通常所说的“粗糙”或“锯齿状”arrays,因为在这种情况下,所有行显然不必是相同的长度。 然而,几乎神奇地,“衣衫褴褛”arrays中的单元也可以使用a2[i][j]
表示法访问。 为了充满活力,我们可以使用
int **a3 = malloc(NUM_ROWS * sizeof(int *)); for(i = 0; i < NUM_ROWS; i++) a3[i] = malloc(NUM_COLS * sizeof(int));
导致这种内存布局:
+-----+ a3: | | | * | | | | +--|--+ | | V +-----+ | | +--------+--------+--------+--------+ | *------->| | | | | | | +--------+--------+--------+--------+ +-----+ | | +--------+--------+--------+--------+ | *------->| | | | | | | +--------+--------+--------+--------+ +-----+ | | +--------+--------+--------+--------+ | *------->| | | | | | | +--------+--------+--------+--------+ +-----+
a3[i][j]
也在这里工作。
(当然,在构建像a2
和a3
这样的“动态数组”的实际代码中,我们必须检查以确保malloc
没有返回NULL
。)
另一种看待它的方式……
对于任何类型T
,我们创建一个数组作为
T arr[N];
其中T
可以是int
, char
, double
, struct foo
,等等,并读作“ T
元素的N元素”。 它也可以是另一种数组类型 。 因此,假设T
是int
的M元素数组 ,而不仅仅是int
,我们将其写为
int arr[N][M];
这读作“ arr
是int
元素的M元素数组的N元素数组”。 这不是一个锯齿状的数组 – 所有“行”都是相同的大小。 但它也不完全是一个二维数组 – 它是一个数组数组。 表达式arr[i]
具有数组类型( int [M]
)。
这个视图也帮助我们找出指向数组类型的指针。 除非它是sizeof
或一元&
运算符的操作数,或者是用于初始化声明中的字符数组的字符串文字,否则将转换类型为“N元素数组T
”( T [N]
)的表达式 (“衰变”)到“指向T
指针”( T *
)类型的表达式。 同样,如果用数组类型int [M]
替换T
,那么你有一个类型为“N元素数组的M元素数组int
”( int [N][M]
)的表达式,它“衰变”为输入“指向M的元素数组的指针”( int (*)[M]
)。
以上就是c/c++开发分享C,多维数组:元素是一维数组的数组?相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/562677.html