5

ここに、文字列を作成し、それを文字列ポインタに割り当てて返す関数があります。通常の文字列を返してみましたが、うまくいきました。しかし、ポインターを統合して参照を解除すると、プログラムがクラッシュしました。私がそれをデバッグしようとしたとき、これは私が得たメッセージです:

Unhandled exception at 0x00024cbf in Assignment 2.exe: 0xC0000005: Access violation reading location 0xcccccce4

これが私のコードです:

string* Recipe::getCookingTime()
// @intput: none
// @output: cooking time as a string
{
    string temp;
    string displayHrs;
    string displayMins;
    if( cookingTime_->numHours < 10 ) 
        displayHrs = intToString(0) + intToString(cookingTime_->numHours );
    else 
        displayHrs = intToString(cookingTime_->numHours );
    if( cookingTime_->numMinutes < 10 ) 
        displayMins = intToString(0) + intToString(cookingTime_->numMinutes);
    else 
        displayMins = intToString(cookingTime_->numMinutes);

    temp = "The time to cook the recipe is " + displayHrs + ":" + displayMins;
    *cTime_ = temp;
    return cTime_;
}
4

3 に答える 3

4

問題は、実際に最初にメモリを割り当てずにcTime_変数を逆参照していることです。それがグローバル変数なのかメンバー変数なのかはわかりませんが、最初に「new」演算子を使用してメモリを割り当てる必要があります。したがって、この変数(のアドレス)へのポインタを関数の呼び出し元に戻しますが、この関数が終了するとすぐに「一時」変数が削除されるため、返されたポインタは無効なメモリを指しています。

解決策は、「新しい」演算子を使用することです。

string* Recipe::getCookingTime()
// @intput: none
// @output: cooking time as a string
{
    string displayHrs;
    string displayMins;
    if( cookingTime_->numHours < 10 ) 
        displayHrs = intToString(0) + intToString(cookingTime_->numHours );
    else 
        displayHrs = intToString(cookingTime_->numHours );
    if( cookingTime_->numMinutes < 10 ) 
        displayMins = intToString(0) + intToString(cookingTime_->numMinutes);
    else 
        displayMins = intToString(cookingTime_->numMinutes);

    if( NULL == cTime_ )
    {
        cTime_ = new string();
    }

    *cTime_ = "The time to cook the recipe is " + displayHrs + ":" + displayMins;
    return cTime_;
}

ただし、ここではメモリを割り当てているため、これは適切な設計ではないことを警告する必要があります。これは、メモリを割り当てたときに、メモリを解放する必要があることをコールが認識している必要があるためです。これを行うための好ましい方法は、呼び出し元に変数を割り当ててから、ポインターを渡すことです。

bool Recipe::getCookingTime( string* str )
// @intput: none
// @output: cooking time as a string
{
    if( NULL == str )
    {
        // Received invalid pointer
        return false;
    }
    string displayHrs;
    string displayMins;
    if( cookingTime_->numHours < 10 ) 
        displayHrs = intToString(0) + intToString(cookingTime_->numHours );
    else 
        displayHrs = intToString(cookingTime_->numHours );
    if( cookingTime_->numMinutes < 10 ) 
        displayMins = intToString(0) + intToString(cookingTime_->numMinutes);
    else 
        displayMins = intToString(cookingTime_->numMinutes);

    *str = "The time to cook the recipe is " + displayHrs + ":" + displayMins;
    return true;
}

次に、呼び出し元が関数を使用したい場合、これを行うことができます。

cTime_ = new string();
getCookingTime( cTime_ );

まとめ ここで覚えておくべき重要なことは、ポインタに割り当てる前に、ポインタが参照しているメモリを割り当てる必要があるということです。また、関数内で(new演算子を使用して)メモリを割り当て、明示的に削除しないことは、一般的に悪い設計です。メモリを割り当てる人は、ほとんどの場合、メモリを解放する人でなければなりません

于 2011-03-19T03:58:55.933 に答える
2
*cTime_ = temp;

にメモリを割り当てていないようですcTime_

なぜポインタをに戻すのか疑問に思いますstd::stringstd::string以下に示すように、単純に戻ってみませんか。

std::string Recipe::getCookingTime()
{
   //your same code
   return temp; //this is fine!
}

リターンタイプのタイプがからstd::string*に変更されていることに注意してくださいstd::string

于 2011-03-19T03:51:36.617 に答える
-2

私はあなたの質問がどこに対処するかに焦点を合わせ、あなたのコードの他のどこにも焦点を合わせません。まず、完全なコードを投稿したとは思いません。投稿した内容では、そのメソッドのどこでcTime_が定義されているかわからないため、コードはコンパイルされません。次に、cTime_を文字列へのポインタとして定義し、そのポインタを文字列tempが占有するメモリに割り当てると仮定します。そのメソッドが終了すると、tempはスコープ外になり、cTime_は有効なメモリ位置を指さなくなるため、アクセス違反が発生します。あなたはこのようなことを考えるかもしれません:

void Recipe::getCookingTime( string& str )
{
    string displayHrs;
    string displayMins;
    if( cookingTime_->numHours < 10 ) 
        displayHrs = intToString(0) + intToString(cookingTime_->numHours );
    else 
        displayHrs = intToString(cookingTime_->numHours );
    if( cookingTime_->numMinutes < 10 ) 
        displayMins = intToString(0) + intToString(cookingTime_->numMinutes);
    else 
        displayMins = intToString(cookingTime_->numMinutes);

    str = "The time to cook the recipe is " + displayHrs + ":" + displayMins;
}

次に、getCookingTime()を呼び出します。

string s;
getCookingTime(s);

ポインタを扱う代わりに、参照を扱うようになりました。コードはもっと簡単でしょう。

于 2011-03-19T05:09:01.930 に答える