C 为什么代码不打印指针指向的值?

C 为什么代码不打印指针指向的值?,c,pointers,C,Pointers,这是源代码 int main() { int s[4][2]={ {1,2}, {3,4}, {5,6}, {7,8}, }; printf("%d\n",*(s+2); return 0; } 上述代码正在打印s[2]或(s+2)数组的基址,即元素5的地址 但为什么不打印价值呢 5这里s是指向指针的指针,因此您可以期望*(s+2)打印指针 尝试此操作以获得5:*(*(s+2))

这是源代码

int main()
{
int s[4][2]={
            {1,2},
            {3,4},
            {5,6},
            {7,8},
          };
printf("%d\n",*(s+2);
return 0;
}
上述代码正在打印s[2]或(s+2)数组的基址,即元素5的地址 但为什么不打印价值呢
5这里
s
是指向指针的指针,因此您可以期望
*(s+2)
打印指针


尝试此操作以获得
5
*(*(s+2))
s
是指向数组
s
的第一个元素(衰减后)的指针,即数组
s
的第一行。它的类型为
int(*)[2]
,即指向
2
元素数组的指针
s=2
是指向数组
s
第三行的指针

另一方面,
*s
的类型是
int[2]
,即
2
int
s,这是因为
*
正在取消引用指针表达式
s
(它衰减到指向第一行的指针),这将导致
2
int的数组。由于
8s
也是一个数组,它将衰减到指向其第一个元素的指针,即
s[0][0]

现在
*(s+2)
正在取消对数组
s
第三行的引用。它还将给出一个
2
int
s数组。此外,它将衰减到指向其第一个元素的指针,即
s[0][2]

因此,在上面的讨论之后,您可以说,
s
是执行所有衰减后的指针(不完全是)

取消引用指向
int
(衰减后)的指针将为您提供指向
int
指针。您需要再次删除引用
*(s+2)
,以获取它所指向的值

printf("%d\n",*(*(s+2));  

注意:
s
*s
&s
&s[0]
&s[0][0]
都指向同一位置,但都属于不同类型的


(s+2)
是指向数组
s
第三行的指针。它会给你第三行的起始地址
*(s+2)
是指向第三行第一个元素的指针,即它将为您提供元素
s[0][2]
的地址。虽然它们在打印时提供相同的位置值,但它们的类型不同

s
是一个
int**
,一个指向int的指针。
*(s+2)
是一个
int*
,一个指向int的指针。
*(*(s+2))
*(s+2)
是您要查找的
int
。 如果你想访问
6
,你需要
*(*(s+2)+1)
*(s+2)
指向“子数组”
{5,6}
,它的第一个元素是
5

 *(s+0) ---> {1,2},
 *(s+1) ---> {3,4},
 *(s+2) ---> {5,6},
 *(s+3) ---> {7,8}
因此,要从指针中获取指向
值,必须插入另一个“
*
”,以再次遵从指针。这应该起作用:

/* Dereference s+2 two times, to get the value 5: */
printf("%d\n",*(*(s+2)));

你可以这样想

*(s+2)
是指向子数组
{5,6}
的指针

引入一个新的中间变量
int*a
,等于
*(s+2)

现在
a
是一个指向数组
{5,6}
的(简单的一级间接)指针,实际上指向该数组的第一个元素

如果需要值
5
,则必须使用
*a
(与普通指针和一维数组一样)取消对指针的引用


现在,如果将
a
替换为
*(s+2)
*a
将变成
*(*(s+2))
(从
s
中双重取消引用)。

请记住,在大多数情况下,调用数组的名称会返回数组的第一个元素的地址,例如,该元素也称为数组的基地址

    int arr={0,1,2,3};
    int *p=arr
在此代码中,指针
p
具有int*类型的
arr
的第一个元素的地址

现在让我们一步一步地看
*(s+2)
实际返回的内容,首先调用数组的名称
s
返回数组的第一个元素的地址,在这种情况下,该元素也是
int[2]
类型的数组,因此返回的地址将是
int(*)[2]
,现在,通过简单的指针算法,将2添加到这个地址,将得到数组第三个元素的地址,并且在解引用您得到的地址
int[2]array
之后,您显然无法打印数组

同样值得一提的是,编译器通过指针算术访问所有数组,因此在
s[4][2]
元素中
[3][0]
作为
*(*(s+2)+0)
访问,您可以使用相同的方法访问任何元素。 如果您想通过
(s+2)
引用第三个元素,您可以执行
*((int*)s+2)
,在这里,您显式地将
s
返回的地址强制转换为
int*
,它实际上是
int(*)[2]
类型。不必要地使用石膏不是一个好主意,它会导致不必要的并发症


在使用指针时一定要小心,在使用指针之前一定要注意它所指的地址类型。

因为你需要取消引用两次!但是*(s+2)表示(s+2)元素处的值,即(s+2)处的值是数组,而不是整数。(请记住,这是一个数组数组)因此它应该打印(s+2)基址处的值,(s+2)和*(s+2)之间的区别。
s
是一种数组类型。请记住,数组不是指针!我无法得到(s+2)基址处的概念*(s+2)表示值,即5,因此它应该打印5(s+2)和*(s+2)之间的区别是解引用运算符。它取消引用(返回内容)正在操作的对象。所以
*(s+2)
返回地址
s+2
处的内容。为什么要取消引用两次。。*(s+2)的意思是什么……它不是意味着……基本价值增加吗