7

そのため、C++ で C-String を使用する方法を学ぼうとすると、メモリ割り当てに関する問題が発生します。

ここでの考え方は、新しい文字列が形式 (s1 + sep + s2) で作成されるということです。使用しているテキストはヘッダーを提供しているため、それを変更することはできませんが、サイズを設定しようとすると問題が発生します。 char str[] の。sLength が定数ではないため、配列のサイズを設定するために使用できないというエラーが表示されます。私はC++に比較的慣れていないので、これは2つの部分からなる質問です.

  1. この戦略は実際に新しい配列にメモリを割り当てていますか?

  2. strlen(char*) を使用して定数値を取得できない場合、配列サイズを正しく設定するにはどうすればよいですか?

    char* concatStrings(char* s1, char* s2, char sep){
        int sLength = strlen(s1) + strlen(s2) + 3; 
        //+1 for char sep +2 for \0 at end of string
        char *str = new char[sLength];
        strcpy (str, s1);
        str [sLength(s1)] = sep;
        strcat (str, s2);
        return str;
    }
    

編集が行われたので、コンパイルエラーは発生しなくなりましたが...

関数の呼び出しは次のとおりです。

    char* str = concatStrings("Here is String one", "Here is String two" , c);
    cout<< str;

私の出力は次のようになります。

ここに文字列 onec==================22221/21/21/21/2 / (etc.) / ここに文字列 2

4

3 に答える 3

9

エラーは、ローカル配列 variable のアドレスを返していますstrそのスコープはconcatStrings()、宣言した関数内にあり、関数から制御が戻るとアクセスできなくなります。

new外部にアクセスするには、演算子を使用してヒープから文字列にメモリを動的に割り当てる必要があります。

char* concatStrings(char* s1, char* s2, char sep){
    int s1Length = strlen(s1);
    int sLength = s1Length + strlen(s2) + 2; 
    // +1 for sep and +1 \0 at end of string
    char* str = new char[sLength];
    strcpy (str, s1);
    // Use strlen here instead of sizeof()
    str [s1Length] = sep;
    str [s1Length + 1] = '\0';
    strcat (str, s2);
    return str;
}

そして、プログラムから返された文字列を使用してプログラムが完了しconcatStringsたら、呼び出してメモリを解放する必要がありますdelete

char* str = concatStrings(s1, s2, sep);

// Do something

// Free up memory used by str
delete[] str; 

ここで delete の代わりに delete[] を使用する必要があります。そうしないと、未定義の動作が発生します

代わりにconcatStrings()使用する関数も編集しましたstrlensizeof

更新: +3 ではなく +2 のみを実行する必要があることを指摘していただき、呼び出しの前後にstr1「 \0」を追加する必要があることを確認していただきありがとうございますsepstrcat

于 2013-03-02T22:13:43.357 に答える
5

結果の文字列メモリは、C ++(またはよりCに似たスタイル)を使用して、動的に(実行時、ヒープ上で)割り当てることができます。new[]malloc

char* concatStrings(const char* s1, const char* s2, char sep) // enforced const correctness
{
    const size_t totalLength = strlen(s1) + strlen(s2) 
                            + 2; // +1 for sep char, +1 for '\0' 

    // Dynamically allocate room for the new string (on the heap)
    char* str = new char[totalLength];    

    strcpy(str, s1);
    str[strlen(s1)] = sep; // note that you had a typo with sizeof(s1) here
    strcat(str, s2);
    return str;
}

このメモリは、で割り当てられた場合、またはを使用しdelete[]て割り当てられた場合を使用して、コードのどこかで解放する必要があることに注意してください。new[]free()malloc()

これは非常に複雑です。

のような堅牢なC++文字列クラスstd::stringを使用すると、メモリを割り当てるための便利なコンストラクタ、自動的に解放するためのデストラクタ、文字列を連結するためoperator+のオーバーロードを使用して、コードを大幅に簡素化できます。operator+=以下を使用してコードがどのように簡略化されているかを確認してくださいstd::string

#include <string> // for std::string

std::string str = s1;
str += sep;
str += s2;

(生のC文字列を使用すると、コードが安全性の問題に対してより脆弱になる可能性があることに注意してください。これは、宛先文字列の適切なサイズ設定、バッファオーバーランの回避などに多くの注意を払う必要があるためです。これは、のようなRAII堅牢な文字列クラスを好むもう1つの理由std::stringです。 )。

于 2013-03-02T22:21:13.713 に答える
1

sizeof(s1)ポインター変数が指す配列の長さではなく、ポインター変数のサイズを返します。s1が C 文字列を指していることがわかっているので、strlen()代わりに関数を使用する必要があります。

于 2013-03-02T22:11:49.180 に答える