在C / C++中,除了类型信息外,数组和指针具有相似的语义。
例如,给定一个3D阵列
int buffer[5][7][6];
位置为[2] [1] [2]的元素可以作为“ buffer [2] [1] [2] ”或*(*(*(*(buffer + 2)+ 1)+ 2)进行访问。
遵守以下声明
T *p; // p is a pointer to an object of type T
当指针p指向类型T的对象时,表达式* p的类型为T。例如, buffer的类型为5个二维数组。表达式* buffer的类型是“数组数组(即二维数组)”。
基于以上概念,逐步翻译表达式*(*(*(buffer + 2)+1)+ 2)使其更加清晰。
- 缓冲区–由5个二维数组组成的数组,即其类型为“由5个二维数组组成的数组”。
- buffer + 2 – 5个二维数组中第3个元素的位移。
- *(buffer + 2) –解引用,即它的类型现在是二维数组。
- *(buffer + 2)+1-位移以访问7个一维数组中的第二个元素。
- *(*(buffer + 2)+1) –解引用(访问),现在表达式“ *(*(buffer + 2)+1) ”的类型是整数数组。
- *(*(buffer + 2)+1)+ 2 –位移以使元素在整数的一维数组中的第3个位置。
- *(*(*(buffer + 2)+ 1)+ 2) –在第3个位置访问元素(整个表达式类型现在为int )。
编译器计算“偏移量”以访问数组元素。 “偏移”是根据数组的尺寸计算的。在上述情况下, offset = 2 *( 7 * 6 )+1 *( 6 )+ 2 。蓝色是尺寸,请注意,较高的尺寸未在偏移量计算中使用。在编译期间,编译器会知道数组的维数。使用offset,我们可以访问元素,如下所示,
element_data = *( (int *)buffer + offset );
并非总是可以在编译时声明数组的维数。有时我们需要将缓冲区解释为多维数组对象。例如,当我们处理尺寸在运行时确定的3D图像时,不能使用常规的数组下标规则。这是由于在编译时缺少固定的尺寸。考虑以下示例,
int *base;
其中base指向大型图像缓冲区,该缓冲区表示尺寸为lxbxh的3D图像,其中l,b和h为变量。如果要访问位置(2、3、4)的元素,则需要将元素的偏移量计算为
offset = 2 *(bxh)+ 3 *(h)+ 4并且元素位于base + offset 。
进一步概括,给定大小为[ lxbxh ]尺寸的数组的起始地址(例如base ),我们可以通过以下方式在任意位置(a,b,c)访问元素,
数据= *(base + a *( bxh )+ b *( h )+ c); //注意,我们没有使用更高的维度l 。
相同的概念可以应用于任何数量的尺寸。我们不需要更高的维度来计算多维数组中任何元素的偏移量。这是我们将多维数组传递给函数时省略较高维的原因。仅当程序员迭代有限数量的较高维元素时,才需要较高维。
AC / C++难题,预测以下程序的输出
int main()
{
char arr[5][7][6];
char (*p)[5][7][6] = &arr;
/* Hint: &arr - is of type const pointer to an array of
5 two dimensional arrays of size [7][6] */
printf("%d\n", (&arr + 1) - &arr);
printf("%d\n", (char *)(&arr + 1) - (char *)&arr);
printf("%d\n", (unsigned)(arr + 1) - (unsigned)arr);
printf("%d\n", (unsigned)(p + 1) - (unsigned)p);
return 0;
}
输出:
1个
210
42
210
感谢学生指出错误。