2016-06-13 3 views
-7

私は、代わりにStringクラスのC++で使用した場合であっても、それCスタイルの文字列を理解し、ヌル終端文字必要として:それはnull文字の欠如がプログラムを引き起こすことも私の理解であるヌルターミネータがないにもかかわらず、charへのC++ポインタが文字列として機能するのはなぜですか?

This is a string.\0 

を文字列の後のメモリにあるものを読み続けるために、ヌル文字のバイナリ表現が見つかるまで続けます。これは非常に明確に未定義の動作です。

私がやっている別の練習プロジェクトの一部として実践のためにこれを書いたかった - これを行うためのライブラリ施設があることは分かっていますが、 invalid_argument例外の文字列を作成します)。 null文字として

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()の関数に渡された文字は何でも印刷されました。私はそれが渡された文字へのポインタを提供することを期待しますが、null文字が見つかるまでランダムなメモリに読み込み続けます。私は、複数の異なる文字を渡してこれを複数回試しました。なぜそれがそのまま動作しますか?私はそれが未定義の振る舞いであることについて実際には正しいのですか?ここで意図したとおりに動作するのでしょうか?

+2

:あなたは全体の厄介スイッチと?:オペレータの代わりにやるべきことはこれです。 – juanchopanza

+1

downvotingしている人には:なぜあなたはこれをやっているのかわかりません - それは有効な質問のようです。特定のアクションが実際に未定義のビヘイビアかどうか、あるいはC++の仕組みを誤解しているかどうかを尋ねています。これがどういう形であれ無効であれば、下線を与えるのではなく教えてください。 – john01dav

+0

@juanchopanzaそれは非​​常に答えのように聞こえる。 – john01dav

答えて

2

This operator+がここで使用されています(ヌルで終端されていない単一のcharへのポインタは実際には適していません)。はい、最も確かにundefined behaviorです。

lhs - 文字列、文字、またはnullで終わる配列

の最初の文字へのポインタだけでそれを修正する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 - '0'といくつかの' if'文でうまくいくでしょう。 – LogicStuff

3

Cスタイルの文字列について知っておく必要がある基本的なことがあります(最後に '\ 0'が付いた文字配列)は単なる慣例にすぎず、(Cでは)文字列の場合。つまり、言語の観点から見ると、単一のcharへのポインタとchar配列の先頭へのポインタ(文字列でもよい)との間に違いはありません。だから、それを良い方法でそれを解釈するためにそのようなポインタを使用する関数の上にあり、そのドキュメントのためにあなたの友人です。

あなたがC++を使っているので、私は強くあなただけのstd ::文字列を使用し、Cライブラリとの下位互換性を維持するためにCスタイルの文字列を維持するために助言、あなたは多くの問題を回避します。

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'; 
関連する問題