C++中的數組與指針的一個小疑惑?

在C++中基於範圍的for循環中原始數組可以編譯通過,但是對於用指針動態創建的數組卻不可以,想問一下這其中的一些區別?

int a[]={1,2,3,4,5,6};
int *p=new int[6];
for (auto x:a) {
cout&<&


std::begin和std::end是對數組做了特化的

std::begin, std::cbegin

std::end - cppreference.com


range based for依賴於被遍歷對象有begin和end返回的迭代器,指針沒有,因為不知道大小


a的類型是int[6],編譯器可以知道它的長度;p的類型是int*,編譯器無法知道它的長度,所以編譯錯誤。


使用vector可破,又動態又可以遍歷


不要把指針當成數組用,雖然他們用起來有點像,參考C++數組名可以看成指針么?

char*當字元串用時比較特殊是因為C字元串都以結束,可以判定數組邊界。你要是用char類型存儲數據,同樣無法判定數組邊界。

至於為什麼會這麼蛋疼,當然是C語言留下的設計啦。如果你不想用動態的std::vector - cppreference.com,可以試試std::array - cppreference.com。


簡單來說, 數組和指針不是一個東西, 指針沒有保存長度信息.

詳細點就涉及到了C++中range based for的實現了, 實際上

for (auto x: a) { /* ... */ }

調用了 std::begin(a) 和 std::end(a) 來判斷迭代的起點和終點, 也就是實際上是長這樣的(假裝using namespace std了)

for (auto whatever = begin(a); whatever != end(a); ++whatever) {
auto x = *whatever;
/* ... */
}

對於一般的重載了begin和end方法的對象(比如std::vector), 這兩個全局函數會調用它們的這兩個方法, 對於C風格數組, std::begin 和 std::end 是模板特化的, 簡單來說就是特判了, 而對於指針類型, 沒有重載, 所以會報錯

error: 『begin』 was not declared in this scope, error: 『end』 was not declared in this scope

或者

error: invalid range expression of type "int *"; no viable "begin" function available

之所以沒法重載指針的begin和end, 還是因為無法從指針獲得長度信息.

隨手打的std::begin和std::end對數組的特化

template &
begin(T (a)[N]) { return a; }

template &
end(T (a)[N]) { return a + N; }


動態數組嚴格來說就不是數組,就是一塊連續的空間。其實靜態分配的數組也就是一塊連續的空間而已,不同的語言給了不同的語法糖,使得用起來方便了。在內存分布中,只有實打實的內存單元,行為全靠編譯器,你運行時動態申請的,要麼換個方式去遍歷,要麼去瞅瞅編譯器有沒有啥針對的語法糖或者庫了。所以編譯原理和對象模型是很值得學習的。


個人理解,range based for實質上是調用了begin(), end()得到一個序列的起止。而這兩個函數只能返回容器的迭代器或者c array的指針。 對於指針而言並沒有相應函數的實現。

for (range_declaration: range_expression) 對於range_expression而言,只有c array,容器以及初始化列表,或者定義了begin,end函數的對象是合法的。

從另外的角度考慮,動態申請的數組實質上只是返回了指向首地址的指針而不是這個數組對象。至於這個數組有多長,程序本身其實是不知道的。那就更無所謂end()。

p.s. 手機好像不能複製粘貼

可以查一下cpp 文檔的begin end 以及 rangre-based for


對於int[6],執行期機器是不知道他的長度的,但編譯的時候機器卻是知道的,因此編譯器會設置合適的for循環邊界。

對於int*,執行期機器同樣不知道長度,但此外,作為」動態數組」,即動態分配空間的數組,機器在編譯期仍然不知道它的長度(甚至都不知道指針所指的對象是個數組還是int),因此編譯期也無法在for循環內加上合適的邊界條件,導致運行時越界


for新的用法應該是對可以有迭代器的數據結構使用。


指針和數組只是看起來像,完全不是一個東西。你debug一下就知道,a的類型是int[],p的類型是int *。這兩個類型sizeof都不一樣,只是用起來比較像而已。int[]遍歷是有邊界的,指針沒有邊界是不能遍歷的。

不論你後面實際創建的是什麼,你的類型已經寫的很清楚了,p就是指針,當然不能遍歷啦。


這個p只是一個指針,長度都沒有,怎麼循環2333


推薦閱讀:

C++解析xml有什麼好用的輪子?
為什麼Python里類中方法self是顯式的,而C++中this是隱式的?
同一段代碼,為什麼有的編譯器能編譯通過,有的不能?
有什麼很好的軟體是用 Qt 編寫的?
沒有Linux cpp後台開發經驗的應屆生如何找到一份Linux cpp後台開發的工作?

TAG:編程語言 | 計算機科學 | C |