C 指向一个引用加上一个数组的指针
我刚读到一些关于指针的问题。代码如下:C 指向一个引用加上一个数组的指针,c,arrays,pointers,reference,C,Arrays,Pointers,Reference,我刚读到一些关于指针的问题。代码如下: int a[5]={1, 2, 3, 4, 5}; int *p = (int*)(&a + 1);//second line cout<<(*p)<<endl; inta[5]={1,2,3,4,5}; int*p=(int*)(&a+1)//第二线 cout&a是数组的地址 &a+1也是一个地址,但这1是什么?它是指向a的大小的指针。这就像写int*p=&a[5],然后将其强制转换为int* 现在为什么是0?因为a[5
int a[5]={1, 2, 3, 4, 5};
int *p = (int*)(&a + 1);//second line
cout<<(*p)<<endl;
inta[5]={1,2,3,4,5};
int*p=(int*)(&a+1)//第二线
cout&a
是数组的地址
&a+1
也是一个地址,但这1是什么?它是指向a
的大小的指针。这就像写int*p=&a[5]代码>,然后将其强制转换为int*
现在为什么是0?因为a[5]
恰好是0
——请注意,它超出了范围,可能是任何其他行为(未定义的行为)
请注意,数组是基于零的,这意味着索引来自0
。因此实际上a[4]
是最后一个元素,a[5]
是不允许的。运算符&
用于获取变量的地址。因此,&a
属于指向5个整数数组的指针类型:int(*)[5]
指针算术意味着当您有一个指针p
时,p+1
将指向下一个元素,即sizeof(*p)
字节。这意味着&a+1
指向5*sizeof(int)
块,即数组中最后一个元素后面的块
将&a+1
转换为int*
意味着现在您希望将此新指针解释为指向int
的指针,而不是指向5个int数组的指针。你是说,从现在开始,这个指针引用的是sizeof(int)
字节长的内容,所以如果你增加它,它将向前移动sizeof(int)
单位
因此,*p
正在访问a[5]
,这是一个越界位置(超出最后一个),因此程序具有未定义的行为。它打印了0,但可能崩溃或打印了其他内容。当发生未定义的行为时,任何事情都可能发生。这就是您的声明的意思:
p
|
v
a[0] a[1] a[2] a[3] a[4] | a[5]
---------(Length)------->
但你想得到这个(我想):
您需要从声明语句中删除第二组括号才能获得a[1]
:
int * p = (int *)(&a + 1);
// change to this:
int * p = (int *) &a + 1;
获取错误值的原因与sizeof
运算符和指针算法有关。在解释错误之前,让我先解释一下
Sizeof运算符
sizeof
运算符计算数据类型的大小(以字节为单位)。直接例子:
sizeof (char) // always returns 1
sizeof (int) // usually returns 4 or 8
sizeof (int *) // usually returns 4 or 8
请注意这个有趣的例子:
int a[5];
sizeof (a) // returns sizeof (int) * 5
运算符优先级
运算符优先级是一系列运算符的求值顺序。括号中的任何内容都将首先计算。计算括号后,由运算符优先级决定表达式的求解顺序
以下是相关运算符及其在优先级表中的顺序:
Operator Description Associativity
() Parenthesis Left-to-right
(cast) Cast Right-to-left
& Address of Right-to-left
+, - Plus, Minus Right-to-left
指针算法
指针算法主要是关于加、减、乘指针和整数(或其他指针)。你需要知道的是(在这个问题的范围内):
即使它说的是+1
,它实际上是在向指针添加sizeof(int)
。
这是C标准编写者的设计选择,因为它更为常见
程序员希望将sizeof(int)
添加到指针(这会将他们带到数组中的下一个整数),而不是添加1
(这会将指针带到数组中的第一个和第二个元素之间)
更一般地说:
datatype p;
p = p + 1;
// actually means
p = p + sizeof (datatype);
下面是一个相关的例子:
int a[5];
a = a + 1;
// actually means
a = a + sizeof (a);
// remember that sizeof (a) is going to be sizeof (int) * 5?
声明
回到你的声明:
int * p = (int *)(&a + 1);
您可能已经看到了它的问题所在:a+1
实际上意味着a+sizeof(a)
,这使您超出了数组的范围。这可能是0
(通常是),也可能是其他一些随机值
您可能没有注意到的是:
int * p = (int *) &a + 1;
实际上给出了数组中的第二个元素。这与运算符优先级有关。如果您查看我放在链接中的运算符优先级表,则强制转换的优先级高于&
和+
运算符。因此,如果在对表达式的其余部分求值之前,将a
转换为(int*)
,而不是a[5]
,则它将等效于:
int * a;
a = a + 1; /* and this would
give you the second element
in the array */
简单地说,如果要访问数组中的第二个元素,请更改:
int * p = (int *)(&a + 1);
// to this:
int * p = (int *) &a + 1;
什么是*p
?:强>
在代码中,*p
是指向类型为int
的未知元素的指针
让我们来解释一下:
&a
是有效的指针表达式。可以将整数添加到指针表达式中
&a
的结果:指向整个数组a[5]
。它的类型是int(*)[5]
sizeof*(&a)
的结果是5
,即数组的大小
&a+1
的结果是指针表达式,它保存当前指向的&a
之外的第一个int
的地址
因此,1
对象经过&a
就是*p
指向的对象。因此,它是int
类型的未知元素。因此,访问未知元素
是未定义的行为。这也回答了为什么输出为零。
旁注:
如果您确实想访问数组中的第二个元素,那么应该将1
添加到指向数组第一个元素的指针a
指向数组中的第一个元素,大小为sizeof(int*)
a+1的结果是数组中第二个元素的地址
*(a+1)
的结果是数组中第二个元素的值<代码>2
+1为什么a[5]=0
是因为a[4]=5
和a[5]
是不允许的。。。在数组长度之外,它恰好发生在
int * a;
a = a + 1; /* and this would
give you the second element
in the array */
int * p = (int *)(&a + 1);
// to this:
int * p = (int *) &a + 1;
int *p = (int*)(&a+1);