2016-06-13 22 views
-7

據我瞭解C風格的字符串,用於C++而不是字符串類即使,需要一個空終止符:儘管缺少空終止符,爲什麼指向char的C++指針充當字符串?

This is a string.\0 

這也是我的理解是,缺乏一個空字符導致程序繼續讀取字符串後面的任何內存,直到找到空字符的二進制表示形式。這是非常明顯的未定義的行爲。當我寫一個dtoi函數(我想自己寫這個練習作爲一個不同的練習項目的一部分,我正在做 - 我知道有庫函數已經做到這一點),我發現不同的行爲(具體來說,當創建invalid_argument例外的字符串)。

int dtoi(const char d){ 
    switch(d){ //using switch statement rather than d-'0' to support character sets with non-consecutive digits or digits that go from 9 to 0 rather than 0 to 9 
     case '0': 
      return 0; 
     case '1': 
      return 1; 
     case '2': 
      return 2; 
     case '3': 
      return 3; 
     case '4': 
      return 4; 
     case '5': 
      return 5; 
     case '6': 
      return 6; 
     case '7': 
      return 7; 
     case '8': 
      return 8; 
     case '9': 
      return 9; 
     default: 
      throw invalid_argument(((d == '\0') ? "null character" : &d) + string(" is not a valid digit character.")); 
    } 
} 

截至異常字符串的開頭空字符導致它在第一個字符結束(即當空字符傳遞給我的實現dtoi的),我決定把它顯示的文本「空字符」,而不是直接插入字符,如果它是'\0'。爲了實現這個,我使用條件運算符。我不能使用(d == '\0') ? "null character" : d(注意末尾的d而不是&d),因爲條件運算符可能會直接返回字符串中第一個字符的指針或字符。爲了看看發生了什麼,我決定嘗試&d,令我驚訝的是,它打印了在exception.what()中傳遞給函數的任何字符。我期望它提供一個指向傳遞字符的指針,但是,然後繼續讀入隨機存儲器,直到找到空字符。我多次嘗試多次傳入不同的字符。爲什麼它的行爲如此?我是否正確地認爲它是未定義的行爲,並且恰好在這裏按照預期工作?

+2

因爲未定義的行爲。 – juanchopanza

+1

對於任何壓低投票的人:我不確定你爲什麼這樣做 - 這似乎是一個有效的問題。我在問一個具體的行爲實際上是不確定的行爲,還是我誤解了C++的工作原理。如果這在某種程度上是無效的,請告訴我,而不是給予低估。 – john01dav

+0

@juanchopanza這聽起來很像一個答案。 – john01dav

回答

2

This operator+這裏使用(一個指向單個char的指針不是空終止的並不真正合適)。是的,最肯定的是undefined behavior

lhs - 串,字符,或指針到一個空終止陣列

的第一個字符只是要std::string普通型修復它:

((d == '\0') ? std::string("null character") : std::string(1, d)) 

並且不要形成switch - case這樣的陳述。

+0

感謝您的回答。我有一個問題,但是我的開關盒有什麼問題?這是否僅僅是因爲標準將0-9定義爲保證?如果是這樣,我應該如何實施無效輸入的例外情況? – john01dav

+0

@ john01dav T.C. M.M解釋說。你可以用'd'''和一些'if'語句來處理。 – LogicStuff

3

關於C-Style字符串,有一個基本的東西需要知道,我們代表它們的方式(末尾帶有'\ 0'的char數組)僅僅是一個約定,沒有類型(以C語言)爲字符串。這意味着,從語言的角度來看,指向單個字符的指針和指向字符數組開頭的指針(可能是字符串)沒有區別。所以這是一個使用這樣一個指針來解釋它的函數,並且該文檔是你的朋友。

由於您使用的是C++,我強烈建議您僅使用std :: string,並且爲了向後兼容C庫而保留C-Style字符串,這樣可以避免很多問題。

0

是的,它是未定義的行爲,因爲你讀隨機存儲器。你應該做的,而不是整個凌亂的開關和?:運營商是這樣的:

#include <cctype> 

if(!std::isdigit(d)) 
{ 
    std::string err_str; 

    if(d == '\0') 
    { 
    err_str = "Null character"; 
    } 
    else 
    { 
    err_str = std::string(1, d); 
    } 
    err_str += " is not a valid digit character."; 

    throw invalid_argument(err_str); 
} 

return (int)d - '0';