2014-09-19 53 views
3

我注意到std::end在涉及字符串或字符數組時總是會引用空終止符。我認爲std::end應該是指最後一個有效元素後面的數組的末尾。 '\0'不被視爲有效元素?它是數組的一部分。這裏有一些測試,所有返回true:應該std ::結束爲字符串指向空過終止符?

#include <iostream> 

int main() 
{ 
    std::string s("hello!"); 
    auto s_end = *(s.data() + s.size() + 1); 
    std::cout << std::boolalpha << (*std::end(s) == s_end) << "\n" 
       << (s_end == '\0') << "\n"; 
    char buf[6 + 1]; 
    std::copy(s.begin(), s.end(), &buf[0]); 
    auto buf_end = *(buf + s.size() + 1); 
    std::cout << (*std::end(buf) == buf_end) << "\n" 
       << (buf_end == '\0') << "\n"; 

    char test[3] = {'h', '\0', 'e'}; 
    std::cout << (*std::end(test) == '\0'); 
    return 0; 
} 
+1

'end'迭代器不可解引用。通過取消引用,您的程序會顯示未定義的行爲。 – 2014-09-19 02:48:25

+3

null終止符不是被認爲存儲在'std :: string'中的一部分。例如,它不包含在'size()'中,而不是由'back()'返回。 – 2014-09-19 02:49:36

回答

4

對於字符數組,std::end確實指向過去的數組中的最後一個字符。對於

char test[3] = {'h', '\0', 'e'}; 

指針std::end(test)相同test + 3。解除引用與評估test[3]相同。這是未定義的行爲。在你的具體情況下,它發生了,它產生了'\0'。但總的來說,它可能會產生不同的價值,或者崩潰,或者完全不同。 std::end(test)確實不是指向'\0'字符在索引1在陣列test

請注意,std::end對於所有陣列的行爲是一致的。也就是說,如果我們有一個數組T a[N],那麼std::end(a)返回a + N,無論Tchar還是a的內容是什麼。它不會給你字符串的結尾;它會給你數組的結束。同樣,返回值始終爲a + N。沒有例外!

對於std::string,有一個終止空字符,但它不被視爲字符串的一部分。 (不像其他的字符,你不允許修改它,對未定義行爲疼痛。)如果您有

std::string s("hello"); 

然後s[5]將有空字符的值,但正如我所說,這不是考慮部分字符串:s被認爲有五個字符,而不是六個字符。最好認爲std::string根本不是空終止的。最後一個字符是s[4],它的值爲'o',而std::end(s)是剛過std::begin(s) + 4的迭代器,即std::begin(s) + 5

這比看起來更微妙一些,因爲標準在技術上並不保證std::end(s)是可解引用的,所以你不一定會說它指向終止null。在實踐中,它確實指向終止空值,但解除引用仍然是未定義的行爲。