我在C中有以下代码:
int arr[] = {1,7,4,2,5,8};
int x = (&(arr[arr[1] - arr[4]]) - arr);
当我运行此代码时,则x = 2。
但如果我这样做:
int arr[] = {1,7,4,2,5,8};
int a = &(arr[arr[1] - arr[4]]);
int b = arr;
int x = a-b;
他们x = 8。
为什么我会得到不同的值?
答案 0 :(得分:4)
在您的情况下,8
等于2 * sizeof( int )
在第一个代码片段中,使用指针算术,而在第二个代码snipeet中,使用普通算术和整数。
在此表达式中
&(arr[arr[1] - arr[4]]) - arr
你处理指针。在这两个地址(&(arr[arr[1] - arr[4]])
和arr
)之间,数组中有two
个元素,第一个代码段显示了这些地址之间的元素数量。但是,它们占用的内存大小等于'8,第二个代码片段显示为。
考虑一个简单的例子,它会更清楚
int a[2];
sizeof(a)等于8,即2 * sizeof(int)。
而sizeof( a ) / sizeof(int )
等于2.它与表达式
( a + 2 ) - a
答案 1 :(得分:2)
int b = arr;
这是一个错误(更确切地说,约束违规)。由于arr
是一个数组表达式,因此在包括这个表达式的大多数上下文中,它隐式转换为第一个元素的地址。因此,在隐式转换之后,expersion arr
的类型为int *。
由于同样的原因,a
的初始化无效。
没有从int*
到int
的隐式转换。
您的编译器可能会将这种隐式转换实现为扩展(它实际上是一个不再定义的非常古老的C功能),但如果它符合要求,它必须至少发布一个警告信息。
在您的第一个代码块中,您需要减去两个int*
值,这两个值分别指向位置2 int
。指针算术是根据数组索引定义的。
在你的第二个(无效)代码块中,如果,编译器允许你在int*
对象中存储int
值,它可能会存储原始内存地址。根据系统使用的寻址方案,并且取决于int
的大小(系统上可能是4个字节),减法可能有效地计算差异,以字节为单位两个指针之间。
如果您在编译此代码时看到警告,您应该注意它们,并且在询问时您应该明确提及它们。如果您没有看到警告,您应该了解如何鼓励编译器警告错误的代码。
如果您真的想要计算两个地址之间的字节距离,可以将两个指针都转换为char*
:
int arr[] = {1,7,4,2,5,8};
int *p1 = &arr[0];
int *p2 = &arr[2];
char *cp1 = (char*)p1;
char *cp2 = (char*)p2;
printf("p2 - p1 = %d\n", (int)(p2 - p1));
printf("cp2 - cp1 = %d\n", (int)(cp2 - cp1));
第一行应打印2
;第二个应打印2 * sizeof (int)
的值。
答案 2 :(得分:1)
在第一个中,arr
是一个指针。在第二个中,b
是一个int。
在第一个中,减法结果为2,因为差异是数组中的两个点。
在第二个中,减法结果为8,因为数组中的每个点占用4个字节的内存。 4 * 2 = 8。
答案 3 :(得分:0)
使用指针进行算术运算时,结果是类型数组的单位数。
使用整数进行算术运算时,结果是字面数字差异。