可能重複:
Take the address of a one-past-the-end array element via subscript: legal by the C++ Standard or not?我可以把數組中的一個過去的元素的地址?
int array[10];
int* a = array + 10; // well-defined
int* b = &array[10]; // not sure...
是最後一行的有效與否?
可能重複:
Take the address of a one-past-the-end array element via subscript: legal by the C++ Standard or not?我可以把數組中的一個過去的元素的地址?
int array[10];
int* a = array + 10; // well-defined
int* b = &array[10]; // not sure...
是最後一行的有效與否?
是的,您可以將地址放在數組的末尾,但不能對其進行解引用。對於10個物品的數組,array+10
將起作用。有幾次(由委員會等人)爭論過&array[10]
究竟是否確實導致了未定義的行爲(如果確實如此,是否應該這樣做)。它的底線是,至少根據現行標準(包括C和C++)它會正式導致未定義的行爲,但如果有一個編譯器實際上不起作用,那麼任何參數都沒有人能夠找到或引用它。
編輯:這一次我的記憶是對了一半 - 這是(部分)的正式Defect Report該委員會,並至少有一些委員會成員(例如,湯姆·梅)認爲措辭已經改變,因此會不是導致未定義的行爲。 OTOH,DR的日期從2000年開始,狀態仍然是「起草」,因此可以質疑它是否確實是固定的,或者很可能是(我沒有通過N3090/3092瞭解)。
但是,在C99中,顯然是而不是未定義的行爲。
很好的答案。作爲歷史的一個可能有趣的地方,我實際上看到一個C編譯器無法正確解引用&array [N]。惠普RTE採用HP-1000主機。它在我的數組上方設置了一個內存「fence」,所以引用地址不存在於程序的地址空間中。 甚至在1989 C標準之前,所以我認爲可以肯定地說這個編譯器已經不在了。 – 2010-06-29 23:46:44
該DR的語言不在N3092中。雖然我現在找不到它們,但是有幾個_closed_ DR依賴於提議的解決方案中的「空左值」語言來解決該缺陷... – 2010-07-11 01:20:55
不是。它沒有定義。 array[10]
相當於*(array + 10)
。換句話說,你已經取消了一個無效指針。
但是他沒有對其進行解引用... – 2010-06-29 21:33:25
@clmh對於'&* p'在技術上是否構成無效操作,或者是解析引用,然後是地址 - 有一個明確的爭論。 – 2010-06-29 21:39:41
'&array [10]'是合法的,不會取消引用元素。 – 2010-06-29 21:49:53
array[10]
相當於*(array + 10)
(也相當於10[array]
),所以&array[10]
的作用就像從*(array+10)
除去*
。任何體面的編譯器都應該發出相同的代碼(和相同的警告)。
正如其他答案已經表明,表達式array[10]
相當於*(array + 10)
,這似乎導致剛剛超過數組末尾的元素的未定義解引用。然而,表達&array[10]
相當於&*(array + 10)
,和C99標準明確(6.5.3.2地址和間接運算符):
一元運算符&返回其操作數的地址。如果操作數的類型爲''type'',則結果的類型爲'',指向類型''。如果操作數是一個運算符的一元運算符,則該運算符和運算符都不會被評估,並且結果就好像兩個都被省略一樣,除了運算符上的約束仍然適用且結果不是左值。類似地,如果操作數是
[]
運算符的結果,則對[]
隱含的&
運算符和一元*
都不進行評估,結果就好像刪除了運算符&
並將[]
運算符更改爲+運算符。
因此,沒有任何關於&array[10]
未定義 - 沒有取消引用操作發生。
C99不是C++。 – 2010-06-29 22:48:09
這實際上是一個相當簡單的事情來回答。
所有你正在做的是指針數學,它沒有什麼無效的。如果您嘗試以某種方式使用結果指針,那麼取決於您的進程是否可以訪問該指針所指向的內存,如果有的話,它的權限是什麼?
foo.cc:
#include <iostream>
using namespace std;
int main() {
int array[10];
int *a = array + 10;
int *b = &array[10];
int *c = &array[3000];
cerr << "Pointers values are: " << a << " " << b << " " << c << endl;
return 0;
}
編譯:
g++ -Werror -Wall foo.cc -o foo
應產生NO警告,因爲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;
}
然後:
gcc -std=c99 -Wall -Werror -o foo foo.c
./foo
輸出:
Pointers are: 0x7fff2c7d22c8, 0x7fff2c7d22c8, 0x7fff2c7d5180
杜佩傳說中的http://stackoverflow.com/questions/988158/採取一個一個地址過去的末端數組元素通過下標合法的由 – 2010-06-29 22:42:40
@約翰內斯 - 你是對的,投票結束。 – Omnifarious 2010-06-29 23:26:40