C 关于指针和运算符的值
为什么输出1和输出2是相同的地址?如果它有1D数组,那么应用'value of'操作符将在数组中给出相应的值,但这里得到的是地址,混淆了C 关于指针和运算符的值,c,arrays,pointers,C,Arrays,Pointers,为什么输出1和输出2是相同的地址?如果它有1D数组,那么应用'value of'操作符将在数组中给出相应的值,但这里得到的是地址,混淆了 a+1是数组的地址。 (数组是a[1]–地址也可以写入&a[1]) *(a+1)是该地址的数组(即数组a[1]) 将数组作为参数传递时,该值将隐式转换为该数组第一个元素的地址。 在您的情况下,*(a+1)(即a[1])被转换为&a[1][0] 数组的地址与该数组的第一个元素的地址相同–&a[1]表示与&a[1][0]相同的位置,但具有不同的类型。两个a+1和*
a+1
是数组的地址。(数组是
a[1]
–地址也可以写入&a[1]
)
*(a+1)
是该地址的数组(即数组a[1]
)
将数组作为参数传递时,该值将隐式转换为该数组第一个元素的地址。在您的情况下,
*(a+1)
(即a[1]
)被转换为&a[1][0]
数组的地址与该数组的第一个元素的地址相同–
&a[1]
表示与&a[1][0]
相同的位置,但具有不同的类型。两个a+1
和*(a+1)
计算为相同的地址,但它们的类型不同
a+1
类型为int(*)[3]
,*(a+1)
类型为int*
另外,%d
不是用于打印指针的正确格式说明符。相反,您应该使用%p
....
int a[3][3]={0,1,2,3,4,5,6,7,8}
printf("%d",a+1); // output 1
printf("%d",*(a+1)); //output 2
....
编辑
[OP在评论中提问-
我的问题是它们的评估结果是否相同
要通过举例说明这一点,请编辑我的答案]
以简单的方式理解这一点,让我们考虑一个1D数组的例子:
printf("a+1 = %p\n", (void*)(a+1)); // output 1
printf("*(a+1) = %p\n", (void*)(*(a+1))); //output 2
让我们打印&b
和b
:
int b[3] = {3,4,5};
b[0] b[1] b[2]
+-----------+
b | 3 | 4 | 5 |
+-----------+
^
|
base address of array (which is also the address of first element)
&b
和b
都指同一地址数组地址和数组第一个元素的地址在数字上相同,但类型不同。
b
是指向数组第一个元素的指针,而&b
是指向三个int
数组的指针
b
的类型是int*
,而&b
的类型是int(*)[3]
我们可以通过执行一个简单的指针算法来看到差异-向这些指针添加1
。当您将
1
添加到这些指针时,结果将不同,因为类型不同
b+1
将导致数组b+4字节的第一个元素的地址
[假设整数的大小为4
字节]&b+1
将产生b+(3*4)字节的基址
&b = 0x7ffee9f5fa2c
b = 0x7ffee9f5fa2c
让我们打印&b+1
和b+1
+-----------+
| 3 | 4 | 5 |
+-----------+
^ ^
b |
|
b+1
+-----------+
| 3 | 4 | 5 |
+-----------+
^ ^
&b |
|
&b+1
回到2D阵列的场景:
a
是3
一维数组的数组。
2D阵列的内存视图如下所示
&b = 0x7ffeee6e7a2c
&b+1 = 0x7ffeee6e7a38
b = 0x7ffeee6e7a2c
b+1 = 0x7ffeee6e7a30
输出:
#include <stdio.h>
int main() {
int b[3] = {3,4,5};
printf("&b = %p\n", (void*)&b);
printf("b = %p\n", (void*)b);
return 0;
}
#include <stdio.h>
int main() {
int b[3] = {3,4,5};
printf("&b = %p\n", (void*)&b);
printf("&b+1 = %p\n", (void*)(&b+1));
printf("b = %p\n", (void*)b);
printf("b+1 = %p\n", (void*)(b+1));
return 0;
}
#include <stdio.h>
int main() {
int a[3][3]={0,1,2,3,4,5,6,7,8};
printf("a+1 = %p\n", (void*)(a+1));
printf("(a+1)+1 = %p\n", (void*)((a+1)+1));
printf("*(a+1) = %p\n", (void*)(*(a+1)));
printf("(*(a+1)+1) = %p\n", (void*)((*(a+1))+1));
return 0;
}
希望这能澄清你所有的疑问
1)
来自C标准#6.5.2.1 下标运算符[]的定义是E1[E2]与(*(E1)+(E2))相同 在上述1D数组
b
示例的上下文中:b[x]
与*(b+x)
相同
要访问数组b
的第一个元素,您将写入b[0]
,要获取数组b
的第一个元素的地址,您将执行&b[0]
&b[0]-->&(*(b+0))-->&(*b)-->b
这意味着b
将给出数组b
的第一个元素的地址
运算符
&
用于获取地址,运算符*
用于解引用。当一个接一个地使用这些操作符时,它们会相互抵消效果。因此,&(*(b+i))
相当于内存中的b+i
,因为内存是1D,所以没有2D数组。因此,所有二维数组都存储为一维数组的序列
其次,只要只写数组的名称,就意味着该数组的第一个元素的地址
现在,在您的代码
a+1
和*(a+1)
计算为相同的地址时,您可以通过将a
替换为a[0][0]
的地址来看到这一点,它不是一维数组。在内存中,可能表示为1使用%d
打印指针是未定义的行为。a+1
和*(a+1)
都是指针,如果要打印它们,应在将它们强制转换为void*
后使用%p
。这就是说,a+1
和*(a+1)
将具有相同的值,但类型不同。为什么它们不具有相同的值呢?两个指针都指向内存中的同一点。为什么你会感到惊讶?只需停止使用%d
打印指针值即可<代码>%d不能与指针一起使用。这两个答案都为拼图提供了有用的部分。做得好。我的问题是,他们对同一地址的评价是什么?类型上的差异可以通过比较(a+1)+1
和(*(a+1))+1
的效果来说明。前者将指向a[2][0]
,而后者将指向a[1][1]
@ArijitKarali我已经编辑了我的答案,并给出了示例来解释它们是不同的,但为什么它们计算到相同的地址。
#include <stdio.h>
int main() {
int a[3][3]={0,1,2,3,4,5,6,7,8};
printf("a+1 = %p\n", (void*)(a+1));
printf("(a+1)+1 = %p\n", (void*)((a+1)+1));
printf("*(a+1) = %p\n", (void*)(*(a+1)));
printf("(*(a+1)+1) = %p\n", (void*)((*(a+1))+1));
return 0;
}
a+1 = 0x7ffee167ea1c
(a+1)+1 = 0x7ffee167ea28
*(a+1) = 0x7ffee167ea1c
(*(a+1)+1) = 0x7ffee167ea20