2

char ポインターを扱うときに混乱します。次のコードを見てください。

class Person
{
    char* pname;
public:
    Person(char* name)
    {
        //I want to initialize 'pname' with the person's name. So, I am trying to
        //achieve the same with different scenario's

        //Case I:   
        strcpy(pname, name); // As expected, system crash.

        //Case II: 
        // suppose the input is "ABCD",  so trying to create 4+1 char space
        // 1st 4 for holding ABCD and 1 for '\0'.
        pname = (char*) malloc(sizeof(char) * (strlen(name)+1) );
        strcpy(pname, name);

        // Case III: 
        pname = (char*) malloc(sizeof(char));
        strcpy(pname, name);
    }

    void display()
    {
        cout<<pname<<endl;
    }
};

void main()
{
    Person obj("ABCD");
    obj.display(); 
}

ケース I の場合: 予想どおり、システム クラッシュ。

ケース II の出力:

あいうえお

ケース III の出力:

あいうえお

したがって、ケース II と III が同じ出力を生成する理由がわかりません!!!!..... クラスで char ポインターを初期化するにはどうすればよいですか?

4

7 に答える 7

11

3 番目のケースでは、未定義の動作が呼び出されるため、その場合は何かが起こる可能性があります。
この場合、割り当てられたメモリの境界を超えて書き込みを行っています。クラッシュする場合としない場合がありますが、UB です。

C ++でこれを正しい方法で行うには?
まったく使わないことchar *で!
単純にstd::stringを使用してください。

基になる文字列を取得するc_str()std::string関数を提供することに注意してください。ただし、常にc++ で使用する必要がある c スタイルの API に a の所有権を渡すことに煩わされている場合を除きます。char *std::string

于 2012-04-23T15:07:54.687 に答える
5

十分なメモリを割り当てていないため、3 番目のオプションも間違っています。サイズ 5 の文字列をサイズ 1 のバッファーにコピーしようとしています。これは、後のデータpname[1]が誤って上書きされてなくなったことを意味します。

運が良ければ、メモリ アクセス違反などの実行時エラーが表示されるか、その背後にあるデータ (銀行口座など) が破損している以外は何も表示されず、それを確認するまでわかりません..

正しい方法は、常にコピーするのに十分なメモリを割り当てることです。C++ でのより良い方法はstd::string、Als が指摘しているように、 を使用することです。これにより、メモリの手動管理 (割り当て、成長、割り当て解除など) から解放されるからです。

例えば、

class Person
{
    std::string pname;
public:
    Person(char* name)
    {
        pname = name;
    }

    void display()
    {
        cout << pname << endl;
    }
};

void main()
{
    Person obj("ABCD");
    obj.display(); 
}
于 2012-04-23T15:09:12.907 に答える
4

メンバー変数にメモリを割り当てる必要がありますが、 a を使用できるpnameのに a を使用する理由がわかりません。char*string

std::string pname;

//...

pname = std::string(name);

a を使用しなければならない正当な理由がある場合はchar*、次のようなことを行います。

// initialize the pname
pname = new char[strlen(name)];

// copy the pname
strcpy(pname, name);

文字列の最後に -termination 用の余分なスペースを割り当てる必要がない理由はnull、二重引用符を使用すると -terminated 文字列"blah"が自動的に生成されるためnullです。

于 2012-04-23T15:07:19.747 に答える
3

C++ ビジネスに興味がある場合は、STL 文字列の代わりに char ポインターをダンプする時が来ました。

#include <string>

class Person
{
    std::string the_name;
public:
    Person(std::string name) : the_name(name)
    { ...

cout も同様に使用します。

于 2012-04-23T15:10:35.300 に答える
2

ケース III では、単一の charpname = (char*) malloc(sizeof(char));に十分なメモリを割り当てます。ただし、 strcpy はそれを知る方法がなく、関数に渡したすべての char* のコピーが完了するまで、そのバイトの直後にあるメモリを上書きします。これはバッファ オーバーフローと呼ばれ、すぐに機能する可能性がありますが、途中で何かが壊れる可能性があります。char* のサブセクションのみをコピーする場合は、ある長さまでコピーする を調べることができます(API リファレンスはこちら)。それを使用する場合は、文字列の一部のみをコピーすると strncpy にヌル終了文字が含まれないため、ヌル終了文字を自分で追加してください。strncpy

于 2012-04-23T15:09:48.707 に答える
2

これpname = (char*) malloc(sizeof(char));が機能するのは偶然であり、strcpy割り当てられていないメモリへの書き込みの呼び出しであるため、いつでもプログラムがクラッシュする可能性があります。

バッファを初期化するより簡単な方法は次のとおりです。

pname = strdup(name);

また

pname = strndup(name, strlen(name));

http://linux.die.net/man/3/strdupを参照してください。

free(pname);また、クラス デストラクタを呼び出して割り当てられたメモリを解放することも考慮する必要があります。

全体として、誰もが言及しているように、C++ std::string クラスを使用することで、これらすべてを回避できます。

于 2012-04-23T15:10:14.193 に答える
2

正解はケースⅡです!

はい、私が間違っている場合、データを初期化されていないポインターにコピーしているため、クラッシュします。

ケース III も間違っていますが、テスト文字列が小さいので動作します! 大きな文字列を小さな割り当てられたスペースにコピーしているため、より大きな文字列を使用しようとすると、メモリが破損します。

一部のシステムでは、malloc はクラスターで動作するため、バイトごとに割り当てるのではなく、メモリのチャンクを割り当てることによって機能します。これは、malloc を使用して 1 バイトを割り当てると (ケース III で行ったように)、処理できるメモリの最小ブロックに達するまでさらに割り当てられるため、クラッシュせずに 1 バイト以上を移動できます。システム。

于 2012-04-23T15:17:35.020 に答える