Проблемы с разыменованием указателя (и его возвратом) - PullRequest
4 голосов
/ 19 марта 2011

здесь у меня есть функция, которая создает строку, присваивает ее указателю строки и возвращает ее. Я попытался вернуть обычную строку, и она работала нормально, но потом, когда я интегрировал указатели и де-ссылки на них, моя программа потерпела крах. Когда я попытался отладить это, я получил следующее сообщение:

Необработанное исключение в 0x00024cbf в Назначении 2.exe: 0xC0000005: Место чтения нарушения доступа 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_;
}

Надеюсь, кто-нибудь может мне помочь, спасибо!

Ответы [ 3 ]

3 голосов
/ 19 марта 2011

Проблема в том, что вы разыменовываете переменную cTime_ без фактического выделения памяти в первую очередь. Я не уверен, является ли это глобальной переменной или переменной-членом, но сначала вам нужно использовать оператор «new», чтобы выделить ее память. Таким образом, вы возвращаете указатель на (адрес) этой переменной обратно в вызывающую функцию, но как только эта функция завершается, она удаляет переменную «temp» и, следовательно, возвращенный указатель будет указывать на недопустимую память.

Решением будет использование оператора «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) внутри функции, а не удалять ее явно. Кто бы ни выделял память, почти всегда должен быть тот, кто ее освобождает

2 голосов
/ 19 марта 2011
*cTime_ = temp;

Кажется, вы не выделили память для cTime_.

Мне интересно, почему вы возвращаете указатель на std::string.Почему бы вам просто не вернуть std::string, как показано ниже:

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

Обратите внимание, что тип возвращаемого типа изменяется с std::string* на std::string.

0 голосов
/ 19 марта 2011

Я просто сосредоточусь на том, где адрес вашего вопроса, а не где-нибудь еще в вашем коде.Во-первых, я не думаю, что вы опубликовали свой полный код, потому что из того, что вы опубликовали, я не вижу, где в этом методе определено 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);

Вместо того, чтобы иметь дело с указателем, вы теперь имеете дело со ссылкой.Код будет более простым.

...