int main()
{
char arr[5][7][6];
char (*p)[5][7][6] = &arr;
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
为什么输出不是 1
在每种情况下?
注意 &arr
是完整的三维字符数组的地址,而 arr
指向第一个元素,即二维char数组。如下图所示:
0xbf8ce2c6
+------------------+ ◄-- arr = 0xbf8ce2c6
| 0xbf8ce2f0 |
| +------------------+ ◄-- arr + 1 = 0xbf8ce2f0
| | 0xbf8ce31a | |
| | +------------------+ ◄-- arr + 2 = 0xbf8ce31a
| | 0xbf8ce344 | | |
| | | +------------------+ ◄-- arr + 3 = 0xbf8ce344
| | 0xbf8ce36e | | | |
| | | | +------------------+ ◄-- arr + 4 = 0xbf8ce36e
| | | | | | | | | |
+---|---|---|--|---+ | | | | Each are 7*6, 2-Dimensional
| | | | | | | | Consists Of 42 bytes
+---|---|--|-------+ | | |
| | | | | |
+---|--|-----------+ | |
| | | |
+--|---------------+ |
| |
+------------------+
The diagram show:
1. How a 3-dimensional can be interpreted as series of 2-dimensional arrays
2. Here (arr + i) points to a 2-D array
3. Notice difference between: (arr + i + 1) - (arr + i) = 0x2a = 42, where i = [0, 4]
类型 &arr
是 char(*)[5][7][6]
这是char三维数组的地址 [5][7][6]
。
价值方面的区别 &arr
和 &arr + 1
是 5 * 7 * 6 * sizeof(char)
= 210
。
因为大小 char[5][7][6]
是 5 * 7 * 6 * sizeof(char)
。
在你的代码中 &arr
指向三维数组和 &arry + 1
下一个三维数组(我们的代码中不存在)。
检查此工作代码 codepade:
int main()
{
char arr[5][7][6];
printf(" &arr : %p", &arr);
printf(" &arr+1: %p", &arr + 1);
return 0;
}
输出:
&arr : 0xbf5dd7de
&arr+1: 0xbf5dd8b0
之间的区别 (&arr + 1) - (&arr)
= 0xbf5dd8b0 - 0xbf5dd7de
= 0xd2
= 210
。
在你的第二个printf:
printf("%d\n", (char *)(&arr + 1) - (char *)&arr);
你强制转换类型的地址 char(*)[5][7][6]
平淡无奇 (char*)
,因为sizeof char[5][7][6]
是 210
两个地址都是210远。 (记得 sizeof(char) == 1
)。这是输出的原因: 210
正如我在第一次发言中说的那样, arr
是第一个元素的地址,它是二维chars数组。类型 arr
是 char(*)[7][6]
。现在一个元素(二维数组的大小是 6 * 7 * sizeof(char) = 42
)。
(注意:您可以将三维数组视为一维数组,其中每个元素都是一个二维数组)。
在你的第三个printf:
printf("%d\n", (unsigned)(arr + 1) - (unsigned)arr);
您将类型转换为无符号值(但不是地址/指针类型)。和...之间的不同 arr + 1
和 arr
是 42 * sizeof(char)
= 42
(这相当于。的大小 char[7][6]
)。所以printf语句输出: 42
。
注意: 你应该读 sizeof(int)== sizeof(void *)?,因为你是对地址进行类型转换。并且此转换尚未完全定义。 (我的解释是你的输出和我给出的输出)。
有关进一步说明,请查看下面的工作代码 codepade:
int main()
{
char arr[5][7][6];
printf(" arr : %p\n", arr);
printf(" arr+1: %p", arr + 1);
return 0;
}
输出是:
arr : 0xbf48367e
arr+1: 0xbf4836a8
区别对待 (arr + 1) - (arr)
= 0xbf4836a8
- 0xbf48367e
= 0x2a
= 42
。
最后的printf:
printf("%d\n", (unsigned)(p + 1) - (unsigned)p);
只需区分 &arr+1
和 &arr
= 210
(类似于第二个printf)因为 p
指向3-D char数组(=&arr
)。而且你将它类型化为值类型(不是指针类型)。
另外, (只是为了理解目的添加,我想读者会发现它有用),
让我们学习另一个区别 arr
和 &arr
使用sizeof运算符可以帮助您更深入地理解概念。对于这第一次阅读: sizeof
操作者
当你申请时 sizeof
运算符到数组标识符,结果是整个数组的大小而不是
由数组标识符表示的指针的大小。
检查此工作代码 codepade:
int main()
{
char arr[5][7][6];
printf(" Sizeof(&arr) : %lu and value &arr: %p\n", sizeof(&arr), &arr);
printf(" Sizeof(arr) : %lu and value arr : %p\n", sizeof(arr), arr);
printf(" Sizeof(arr[0]): %lu and value a[0]: %p\n",sizeof(arr[0]), arr[0]);
return 0;
}
它的输出:
Sizeof(&arr) : 4 and value &arr: 0xbf4d9eda
Sizeof(arr) : 210 and value arr : 0xbf4d9eda
Sizeof(arr[0]): 42 and value a[0]: 0xbf4d9eda
正如我在图中所示 arr
指向作为二维数组的第一个元素。因为 arr
= (arr + 0)
。现在用 *
取消引用运营商 (arr + 0)
给出地址的价值 *(arr + 0) = arr[0]
。
- 注意
sizeof(arr[0])
给 42
= 7 * 6 * sizeof(char)
。并且这在概念上证明了一个三维数组,但是二维数组的数组。
因为上面在我的回答很多时候我写的像: “的大小 char[5][7][6]
是 5 * 7 * 6 * sizeof(char)
“。 所以我在@下面添加一个有趣的代码codepade:
int main(){
printf(" Char : %lu \n", sizeof(char));
printf(" Char[5] : %lu \n", sizeof(char[6]));
printf(" Char[5][7] : %lu \n", sizeof(char[7][6]));
printf(" Char[5][7][6]: %lu \n", sizeof(char[5][7][6]));
return 1;
}
输出:
Char : 1
Char[5] : 6
Char[5][7] : 42
Char[5][7][6]: 210
好吧,如果我想拆分头发:首先,代码在整个地方调用未定义的行为 printf()
声明。两个指针的区别有类型 ptrdiff_t
,为此,正确的转换说明符是 %td
不是 %d
。
剩下的只是猜测。假设您的系统合理,并且 数字 指针值 &arr
它总是相同的,无论它转换成什么类型。
现在, (&arr + 1) - &arr
当然是1,根据指针算法的规则。 (两个指针之间的实际差异是 210 * sizeof(int)
字节,但这不是学校数学而是指针算术,这就是为什么结果以大小为单位给出的原因 sizeof(T)
,哪里 T
是指针的基本类型。)
然后 (char *)(&arr + 1) - (char *)&arr
投射指针 char *
,以及以来的大小 char
是1,这将打印出差异 以字节为单位 你在这里有效地欺骗/滥用指针算法。
此外: printf("%d\n", (unsigned)(arr + 1) - (unsigned)arr)
正在减去两个类型的指针 int (*)[7][6]
。那是什么 arr
衰败成。当然,7 * 6 = 42,所以尺寸之间的差异 arr + 1
和 arr
是42个元素。
p
但是,它不是指向数组第一个元素的指针,而是指向数组本身的指针。其类型正确表示为 int (*)[5][6][7]
。现在,如果您使用打印差异 那种类型, 但你不要让编译器通过欺骗指针来做分裂 unsigned
那么你会得到的 5 * 6 * 7
,这是210。
在 (&arr + 1) - &arr
:
&arr
是由7个7个数组组成的5个数组的数组的地址 char
。添加一个产生的地址 下一个 5个阵列的7个阵列的数组6 char
如果我们有一个这些对象的数组而不是一个对象,那将是。减去原始地址, &arr
,产生两个地址之间的差异。根据C标准,此差异表示为两个地址之间的元素数,其中元素类型是指向的对象的类型。由于该类型是由5个7个数组组成的5个数组的数组 char
,两个地址之间的距离是一个元素。换句话说,距离 &arr
至 (&arr + 1)
是 一 5个阵列的7个阵列的数组6 char
。
在 (char *)(&arr + 1) - (char *)&arr
:
&arr + 1
再次指向7个7个数组的5个数组的下一个数组的指针 char
将会。当它转换为 char *
,结果是指向下一个数组的第一个字节的指针。 Similarlly, (char *)&arr
是指向第一个数组的第一个字节的指针。然后减去两个指针会产生元素之间的差异。因为这些指针是指针 char
,差异是产生的数量 char
。所以不同的是5个7个数组的5个数组的数组中的字节数 char
,这是5•7•6 char
,或210 char
。
在 (unsigned)(arr + 1) - (unsigned)arr
:
以来 arr
不用于 &
(要么 sizeof
或其他特殊情况),它自动转换为5个阵列的5个阵列的数组6 char
指向第一个元素的指针。因此,它是指向7个6的数组的数组的指针 char
。然后 arr + 1
是指向7个6的数组的下一个数组的指针 char
。将此地址转换为 unsigned
,结果,在您正在使用的C实现中,实际上是对象的内存地址。 (这很常见,但C标准无法保证,当地址为64位时肯定会中断 unsigned
是32位。)同样, (unsigned)arr
是第一个对象的地址。减去地址后,结果就是它们之间的距离(以字节为单位)。所以不同的是7个7的数组的数组中的字节数 char
,这是7•6字节,或42字节。请注意这种情况下的关键区别: &arr
是一个指向由5个7个数组组成的5个数组的数组的指针 char
但是 arr
是一个指向7个6的数组的数组的指针 char
。
在 (unsigned)(p + 1) - (unsigned)p
:
p
是一个指向由5个7个数组组成的5个数组的数组的指针 char
。然后 p+1
是指向下一个数组的指针。转换为 unsigned
如上所述。减去产生差异的字节,所以它是5个7个数组的5个数组的数组的大小 char
,所以它又是210字节。
作为旁白:
的类型 (&arr + 1) - &arr
是 ptrdiff_t
并应打印 %td
。
的类型 (char *)(&arr + 1) - (char *)&arr
是 ptrdiff_t
并应打印 %td
。
的类型 (unsigned)(arr + 1) - (unsigned)arr
是 unsigned int
并应打印 %u
。
的类型 (unsigned)(p + 1) - (unsigned)p
是 unsigned int
并应打印 %u
。