2009-03-09 15 views
1
#include <iostream> 

using namespace std; 

class Marks 
{ 
public: 
    char* name(); 
}; 

char* Marks::name() 
{ 
    char temp[30]; 
    cout<<"Enter a name:"<<endl; 
    cin.getline(temp,30); 
    return temp; 
} 

int main() 
{ 
    char *name; 
    Marks test1; 
    name=test1.name(); 

    //cout<<"name:"; //uncomment this line to see the problem 
    cout<<name<<endl; 

    return 0; 
} 
+0

それは可能性があります期待される出力と実際の出力を質問の一部として入力すると便利です。 –

+0

サンプル出力はどうですか?予想される実際の行動? (あなたのコードをインデントするのもいいでしょう:-P) –

+0

次の質問のために上記の質問を含める: –

答えて

5

問題は、名前が指している値が破棄されたためです。ローカル変数のアドレスをMarks::name()から戻しています。最初のcoutの副作用の可能性が最も高いため、nameの内容が破壊されています。最初のcoutがコメントアウトされていると、あなたはたぶん幸運になるでしょう。

char* Marks::name() 
{ 
    char* temp = new char[30]; 
    cout<<"Enter a name:"<<endl; 
    cin.getline(temp,30); 
    return temp; 
} 

int main() 
{ 
    char *name; 
    Marks test1; 
    name=test1.name(); 

    cout<<"name:"; 
    cout<<name<<endl; 

    delete[] name; 

    return 0; 
} 

いうだけでdeleteよりも、delete[]を使用することを忘れないでください、以来:あなたが完了したら

これを行うための正しい方法は、いくつかのメモリを割り当てることを返却し、それを破壊することですそれ以外の場合、最初の文字のみが割り当て解除されます。

+0

メモは、呼び出し先が割り当てて呼び出し元が処理することに注意してください - これは悪い設計であり、メモリリークの潜在的な原因です。呼び出し元と呼び出し先が別々のライブラリに含まれると考えてください。 – dirkgently

+0

それは良い点です。私はちょうどポイントを得るためにコードサンプルを小さく保つことを試みていた。 – Andy

2

Marks::name()メソッドが終了するたびに解放されるスタックベースのポインタ(呼び出されたプロセスのスタックにあるポインタ)を返します。

これは基本的なC/C++メモリ管理に関する質問ですので、このトピックに関するいくつかの書籍を読むことをお勧めします。

これを正しく行うにはいくつかの方法があります。例えば、呼出関数に文字列のメモリを確保し、機能にこのポインタを渡す:main()方法において

char name[30]; 
Marks test1; 
test1.name(name); 

対応する方法を用いて(ここでnameが正しい値を有します)。

char* Marks::name(char* temp) 
{ 
    cout<<"Enter a name:"<<endl; 
    cin.getline(temp,30); 
    return temp; 
} 

しかし、文字列の静的および動的メモリを管理する他の方法があります。

1

まあ、一時変数へのポインタを返すMarks :: name()にはかなり厄介なバグがあります。 tempはスコープの外に出て行くので関数の終了時に破棄されるので、もはや存在しない変数へのポインタを返しています。

8

ローカル変数のアドレスを返却されています

char temp[30]; 
// ... 
return temp; 

これは、厳密なノーノーCまたはC++です。あなたがMarks::name()から出てくる瞬間に、あなたのtemp変数がブームになります!あなたはもはやそれにアクセスすることができません - それは未定義の動作を呼び出します。これを試してみてください

#include <string> // somewhere at the top 
// ... 
std::string Marks::name() 
{ 
    std::string line; 
    cout<<"Enter a name:"<<endl; 
    std::getline(cout, line); 
    return line; 
} 
+0

文字列が常に利用できるとは限りません。時には、ちょうどchar *の下に落ちて汚れていなければなりません。 – xan

+0

例を挙げることができますか? IMHO、getline()とcharバッファで入力を管理するのは、最も簡単な作業ではありません。 – dirkgently

+0

1つのためのゲームプログラミング。しばしばそうではありませんが、その種のアプリケーションでは、stdやboostライブラリの一部を利用できないかもしれません。私はこの正確な問題を具体的には意味しませんでしたが、私はmemと同様の問題に直面しました。内部関数を自分で割り当てます。 – xan

0

これまでの回答はすべて正しいものですが、これを実装する方法のいくつかは改善されている可能性があります。私はその非常に簡単なテストアプリケーションを知っているが、次の点を考慮してください

ここ
char* Marks::name() 
{ 
    char* temp = new char[30]; 
    cout<<"Enter a name:"<<endl; 
    cin.getline(temp,30); 
    return temp; 
} 

int main() 
{ 
    char *name; 
    Marks test1; 
    name=test1.name(); 

    cout<<"name:"; 
    cout<<name<<endl; 

    delete[] name; 

    return 0; 
} 

、それはメモリを割り当てている関数名()であるが、それはそれを削除されていません。これは、特に複雑なシナリオでは、問題につながる矛盾です。これをやるほうがいいかもしれません(あなたには人がどのくらいのスペースを書き込むかを事前に知っていると仮定します...)

//this time, pass in some ALREADY allocated memory, and a length count. 
void Marks::name(char *buf, int len) 
{ 
    cout<<"Enter a name (max " << len <<" letters):"<<endl; 
    cin.getline(buf,len); //read into the memory provided 
} 

int main() 
{ 
    //preallocate your memory so that the same code that allocates... 
    char *name = new char[30]; 
    Marks test1; 
    test1.name(name, 30); 

    cout<<"name:"; 
    cout<<name<<endl; 

    //... also deallocates it. This is perhaps cleaner in terms of responcibility. 
    delete[] name; 

    return 0; 
} 

実際には、この種のことを行う正しい方法と間違った方法はありません。場合によっては、関数が使用するメモリを割り当てる必要があります。これは、他のアプリケーションで使用するためにこれを返す必要があります。これは、誰が新しくなったのかを考え、削除するときに一貫性を持たせようとする例です。

1

Marks :: name()は、ローカル変数へのポインタを返します。 関数が終了すると、そのメモリは解放されます。

Marks :: nameとcout :: operatorの呼び出しの間に関数を呼び出さない限り、まだ適切な出力が得られる理由は、< <です。

静的でない文字列を値で返す場合は、char *の代わりにstd :: stringを使用できます。

また、あなたは* charとして名前の関数にchar型のバッファを渡すと、バッファのサイズを渡し、マーク::名前が(strncpyをまたはstrncpy_sを使用して例えば)そのバッファを満たす可能性があり

void Marks::name(char* buffer, int length) 
{ 
    cout<<"Enter a name:"<<endl; 
    cin.getline(buffer,length); 
} 

void main() 
{ 
    char buffer[30]; 
    Marks::name(buffer, 30); 
} 
+0

+1 - それは私が運転していたもので、コンパイル時にバッファの大きさを知っている限り、スタックに割り当てる方がはるかに優れています。 – xan

関連する問題