Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/163.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 我可以用数组结束元素后面的地址吗?_C++_Arrays_Pointers_Undefined Behavior - Fatal编程技术网

C++ 我可以用数组结束元素后面的地址吗?

C++ 我可以用数组结束元素后面的地址吗?,c++,arrays,pointers,undefined-behavior,C++,Arrays,Pointers,Undefined Behavior,可能重复: 最后一行是否有效?否。未定义数组[10]等于*(数组+10)。换句话说,您取消了对无效指针的引用。是的,您可以将地址移到数组末尾之外,但不能取消对它的引用。对于包含10个项目的数组,array+10。关于&array[10]是否真的会导致未定义的行为(如果会,是否真的应该)已经有过几次争论(委员会等对此进行了讨论)。它的底线是,至少根据当前的标准(C和C++),它正式导致了未定义的行为,但是如果有一个编译器实际上不工作,那么任何参数中都没有人能够找到或引用它 编辑:这一次,我的记忆

可能重复:


最后一行是否有效?

否。未定义<代码>数组[10]等于
*(数组+10)
。换句话说,您取消了对无效指针的引用。

是的,您可以将地址移到数组末尾之外,但不能取消对它的引用。对于包含10个项目的数组,
array+10
。关于
&array[10]
是否真的会导致未定义的行为(如果会,是否真的应该)已经有过几次争论(委员会等对此进行了讨论)。它的底线是,至少根据当前的标准(C和C++),它正式导致了未定义的行为,但是如果有一个编译器实际上不工作,那么任何参数中都没有人能够找到或引用它

编辑:这一次,我的记忆有一半是正确的——这是委员会的一名官员(部分成员),至少一些委员会成员(如汤姆·普卢姆)认为措辞已经改变,因此不会导致不明确的行为。OTOH,DR的日期是2000年,状态仍然是“起草”,所以它是否真的被修复,或者是否可能被修复(我还没有通过N3090/3092了解)


然而,在C99中,它显然不是未定义的行为。

array[10]
相当于
*(array+10)
(也相当于
10[array]
),因此
&array[10]
的行为类似于从
*(array+10)
中删除
*
。任何合适的编译器都应该发出相同的代码(和相同的警告)。

正如其他答案所指出的,表达式
array[10]
相当于
*(array+10)
,这似乎会导致数组末尾的元素发生未定义的取消引用。但是,表达式
&array[10]
相当于
&*(array+10)
,C99标准明确规定(6.5.3.2地址和间接运算符):

一元运算符&返回其操作数的地址。如果操作数的类型为“类型”,则结果的类型为“指向类型的指针”。如果操作数是一元
*
运算符的结果,则不会对该运算符和&code>运算符求值,并且结果就像两个运算符都被省略一样,但运算符上的约束仍然适用,且结果不是左值。类似地,如果操作数是
[]
运算符的结果,则不会计算
&
运算符和
[]
运算符所隐含的一元
*
,结果就好像删除了
&
运算符,并且将
[]
运算符更改为+运算符一样


因此,
&array[10]
没有未定义的内容-没有发生解引用操作。

这实际上是一个非常简单的问题

你所做的只是指针数学,没有什么是无效的。如果您试图以某种方式使用生成的指针,则取决于您的进程是否可以访问该指针指向的内存,如果可以,对它的权限是什么

foo.cc:

不应产生任何警告,因为int*b=&数组[10]是有效的

实际上,我添加的下一行也是这样,只是为了指出一些关于指针数学的东西

foo不仅可以编译,而且可以顺利运行:

 ./foo
  Pointers are: 0x7fff1d356e68 0x7fff1d356e68 0x7fff1d359d20
基本上,数组语法foo[idx]是指针数学的简洁明了的表示形式

如果对c99有一些混淆,该标准无论如何都不会影响该数学,并且定义良好

C99中的情况也一样:

#include <stdio.h>

int main() {
        int array[10];
        int *a = array + 10;
        int *b = &array[10];
        int *c = &array[3000];

        fprintf(stderr, "Pointers are: %p, %p, %p\n" , a , b , c );
        return 0;
}
产出:

Pointers are: 0x7fff2c7d22c8, 0x7fff2c7d22c8, 0x7fff2c7d5180

但是他没有取消引用…@ CLMH,关于代码< >和*P>代码>是否构成了一个明确的辩论,技术上是一个“否”,或者是一个引用,后面是一个地址。<代码>和数组[10 ] < /C>是合法的,并且不去引用元素。@ LooMeST非常正式——是的,它在C++和C89中引用元素。从而导致C89中出现未定义的行为。在C++中,如果没有数组之后的元素,则会导致未定义的行为(当然,必须把那个子数组放进多维数组中,那么保证在没有填充的情况下,数组之后就有一个元素)。在C++中,如果有这样的元素,那么它也很好,因为这样的指针本身并不是无效的,它有效地指向指针的数组结束。正如上面所说,仅仅是去引用它就受到了约束。“去引用”意味着从指针获取左值。它并不意味着读取一个值。该标准规定,例如在
5.3.1/1
:“[注:指向不完整类型(cv void除外)的指针可以取消引用。由此获得的左值可以以有限的方式使用(例如初始化引用);该左值不得转换为右值,请参见4.1.]”另一个示例请参见
3.8/5
“这样的指针可能会被取消引用,但产生的左值只能以有限的方式使用,如下所述。”传奇人物@Johannes的重复-你是对的,投票结束。回答很好。作为一个可能有趣的历史点,我实际上看到一个C编译器未能正确地取消引用和数组[N]。它位于HP-1000主机架上的HP RTE上。它设置了一个内存“围栏”“就在我的数组上方,因此程序的地址空间中不存在引用地址。这甚至早于1989年的C标准,所以我认为可以肯定地说,这个编译器已经不存在了。DR的语言不在N3092中。虽然我现在找不到它们,但在针对该缺陷的建议解决方案中,有几个封闭的DRs依赖于“空左值”语言。。。
 ./foo
  Pointers are: 0x7fff1d356e68 0x7fff1d356e68 0x7fff1d359d20
#include <stdio.h>

int main() {
        int array[10];
        int *a = array + 10;
        int *b = &array[10];
        int *c = &array[3000];

        fprintf(stderr, "Pointers are: %p, %p, %p\n" , a , b , c );
        return 0;
}
gcc -std=c99 -Wall -Werror -o foo foo.c

./foo
Pointers are: 0x7fff2c7d22c8, 0x7fff2c7d22c8, 0x7fff2c7d5180