-3

重複の可能性:
char* 内の char を編集できないのはなぜですか?

char *k ;

void ffill()
{
    char *d="ddddd";    
    *k=*d; //expecting to copy "ddddd" to *k
    cout<<k<<"\n";
    *d[1]=5; // trying to change array element
    cout<<k<<"\n";
}

int _tmain(int argc, _TCHAR* argv[])
{
    ffill();
    cout<<k<<"\n";
}

プロシージャ fill は、ローカル変数を使用して文字配列 k を初期化します。変数ポインターをコピーするかどうかはわかりません"ddddd"(これは間違っています。これは、d メモリの自動破棄後は安全ではないためです)、または値をコピーし、これ*kが正しく初期化された後です。

*d配列要素をエースする方法は? コンパイラは満足していません*d[1]=5;

4

6 に答える 6

17

(免責事項: この回答は C++ のみを対象としています。C と C++ の両方を尋ねることはお勧めしません。両方の言語はまったく異なるためです)

プロローグ

char *k ;

文字へのポインタを宣言します。

"ddddd"

この式は type char const[6]、つまり 6 つの定数文字の配列です。この型の式は、配列の最初の要素へのポインターに暗黙的に変換できます。そのポインタの型は ですchar const*。つまり、定数文字へのポインタです。Aは、それが指す文字の変更を許可するため、 にchar const*変換できませんが、変更はできません。char*char*char const*

char *d="ddddd";

上記の規則により、この記述は正しくありません。コンパイラで警告をオンにする必要があります。これに対して警告が表示されます (理想的には、単なる警告ではなく、実際にはエラーになります)。char const* d = "ddddd";本当にポインターが必要なchar d[] = "ddddd";場合、または配列が必要な場合は、そうする必要があります。const2 番目の形式はコピーを作成するため不要であり、元のデータを変更するリスクはありませんconst

*d

char const*この式には、前述のへの暗黙的な変換が含まれており、次に間接演算子 ( the *) が適用されて、 type の式char const&、つまり定数文字への参照が生成されます。

*k

と同様に*d、これはポインタに対して間接化を実行します。この場合、kは typechar*であるため、結果の式は type になりchar&ます。

*k=*d; //expecting to copy "ddddd" to *k

割り当ては定数文字への参照から文字への参照への割り当てであるため、単一文字を割り当てます。文字列の最初の文字を が指す文字に割り当てることになります。これは... 待ちます。k

どこkを指す?初期化されていませんでした!これは悲劇に終わるにちがいない。

第1章

では、どうすればkどこかを指し示すことができるのでしょうか? dそして、文字列全体をそのスペースにコピーするにはどうすればよいでしょうか?

d配列の 6 文字を にコピーするには、6 文字分のkスペースが必要です。これを行う最も簡単な方法は、6 文字の配列を作成することです。

char k[6];

では、六つの要素をどのようにコピーするのでしょうか? strcpynull で終わる文字列をコピーする C ライブラリ関数 を使用できます。この関数を使用するには、次の理由から注意が必要です。

  1. '\0'ソースには、末尾を示すヌル ( ) 文字が必要です。ソースにそのような文字が含まれていない場合、動作は未定義であり、何かが起こる可能性があります。これが、文字列"ddddd"が 5 文字ではなく 6 文字である理由\0です。末尾に、コンパイラが挿入する暗黙の文字があります。

  2. null ターミネータを含むソース文字列全体に十分なスペースが宛先に必要です。宛先に十分なスペースがない場合、動作も未定義であり、何かが起こる可能性があります。

これは、この関数を使用して文字列のコピーを作成する方法です。

std::strcpy(k, d);

ポイント 1 または 2 のいずれかを満たさないと、一見動作しているように見えるプログラム (運が悪い場合) から、奇妙な方法でランダムに動作するもの、単純にクラッシュする (運が良ければ) まで、あらゆる結果が生じる可能性があります。

エピローグ

男、それは多くの情報でした。C++ プログラマーは、これらの問題を常に気にする必要がありますか? それは疲れるに違いない。

C++ プログラマーstd::stringは文字配列の代わりに使用することができ、これで手間が大幅に軽減されます。代入演算子を使用してコピーを作成でき、正しいサイズを追跡する必要がなく、null を持つことを気にする必要もありません。ターミネータを配置すると、コンパイル時にサイズを制限する必要がなくなり、その他にも多くの利点があります。

std::string k;

void ffill()
{
    std::string d="ddddd";    
    k = d;
    cout<<k<<"\n";
    d[1]=5;
    cout<<k<<"\n";
}
于 2012-07-23T15:20:16.357 に答える
1

C プログラミング言語では、ポインターではなく配列を使用する必要があります (読み取り専用の文字列を指す可能性があるため)。例えば ​​:

char *k;

void 
fill(void)
{
   char d[] = "ddddd";
   k = d;
   d[1] = '5'; // Did you mean '5' ? 
}
于 2012-07-23T14:52:08.327 に答える
1

ここで、注意しなければならないことがいくつかあります。説明してみましょう:

char *k ;

kこの行は、文字へのポインターであるという変数を宣言します。ただし、何かを指すように初期化されていません。初期化されていないポインターを使用しようとすると、未定義の動作が発生します。

void ffill() 
{ 
    char *d="ddddd";

dこの行は、文字へのポインターでもあるという名前の変数を宣言します。同時に、5 つの 'd' 文字と終端の NULL 文字を含む定数文字配列 (c-string とも呼ばれます) を指すようにポインターを初期化します (したがって、配列には 6 つの要素があります)。

    *k=*d; //expecting to copy "ddddd" to *k 

この行では、逆参照演算子 (*) を使用しています。この演算子は、 が指す文字をコピーし、 が指すdアドレスに配置しkます。上で述べたように、ポインタのアドレスkが初期化されていないため、未定義の動作が発生します。

    cout<<k<<"\n";
    *d[1]=5; // trying to change array element

まず、int を char に代入しようとしています。C と C++ の両方でこれが可能ですが、期待した結果が得られない可能性があります。この場合、2 番目の「d」文字を文字コード 5 に置き換えようとしています。ASCII では、これは非印刷文字です。

また、dc-string 定数を指しているため、その要素を変更しようとすると、未定義の動作が発生します。

    cout<<k<<"\n";
}

int _tmain(int argc, _TCHAR* argv[])
{
    ffill();
    cout<<k<<"\n";
}

ある c-string を別の c-string にコピーすることには、他にもいくつかの問題がありますが、ここで詳しく説明するのはこれだけです。他の人が言及しているように、 std::string を使用する方が簡単です。ただし、c-string の使用方法を学ぶことは非常に教育的であり、コーディング スキルを向上させることができるとも考えています。

于 2012-07-23T15:03:43.770 に答える
1

Martinho Fernandes が既に述べたように: char 配列の代わりに 'std:string' を使用しようとしているようです。

char k[20] ; //*k doesn't allocate any memory for you to use.

void ffill()
{
    char *d="ddddd";    //This works, since it points to the constant character string in your code. But it can not be altered in any way. (It's a 'const char *')
    strcpy(k, d);       //This standard function copies the content of one pointer to another.
    cout<<k<<"\n";      //Not too sure, but it should work,
    k[1]=5;             //k is the 'changeable memory, not 'd'.
    cout<<k<<"\n";
}
于 2012-07-23T14:54:58.933 に答える
0

dポインタではなく配列として宣言する必要があります。:

char d[]
d[1] = '5';   // d is a char array, so did you mean the character '5'?

そしてに変更 *k=*d;しますk = d; //This will copy the value of the pointer

于 2012-07-23T14:53:38.533 に答える
0

どれどれ:

*k=*d; //expecting to copy "ddddd" to *k

これは「文字列」をコピーせず、 が指すメモリkを の最初の文字に設定しようとするだけですd。初期化されていないと、ひどく失敗します。

*d[1]=5; // trying to change array element

これも失敗します。まず、これは二重の間接化です。これd[1] = 5;は当てはまりますが、文字列は読み取り専用メモリに格納されている可能性が最も高いため、これも失敗します。

代わりに文字列を使用してください。

于 2012-07-23T14:55:21.850 に答える