2009-09-14 3 views
6

私は、C/C++関数が(std :: stringとは対照的に)文字配列を返すようにするには、char *ではなくconst char *を返さなければならないと読んでいます。後者を実行すると、プログラムがクラッシュする可能性があります。返り値型でconst char *の代わりにchar *を使用すると、クラッシュする可能性がありますか?

誰でもこれが真実かどうかを説明することができますか?それが本当であれば、なぜ関数からchar *を返すのが危険なのでしょうか?ありがとうございました。

const char * my_function() 
{ 
    .... 
} 

void main(void) 
{ 
    char x[] = my_function(); 
} 
+6

main()は常にintを返す必要があります。 http://users.aber.ac.uk/auj/voidmain.shtml – nmuntz

答えて

14

を持っているでしょう。これらはmallocによってヒープ上に確保する必要はありません。実行可能ファイル自体の読み込み専用セクションにコンパイルされるからです。

例:単純にリターン・コードを変更

const char* errstr(int err) 
{ 
    switch(err) { 
     case 1: return "error 1"; 
     case 2: return "error 2"; 
     case 3: return "error 3"; 
     case 255: return "error 255 to make this sparse so people don't ask me why I didn't use an array of const char*"; 
     default: return "unknown error"; 
    } 
} 
+0

また、完全性の中には、これらが内部であり、他の変数が同じ場所を指していることに注意する必要があります。しかし、constが尊重されていれば、それは問題ではありません。 –

2

char *がスタックに割り当てられている場合は、ダングリングポインタを返します。さもなければ、それが関数のプロトタイプと一致し、宣言が戻り値と一致する限り、あなたはうまくいくはずです。

11

は、ではありません。

const char *を返すと、関数のセマンティクスを改善できます(すなわち、私があなたに与えているものを混乱させることはありません)が、char *を返すことはまったく問題ありません。

しかし、いずれの場合も、あなたははあなたのために、メモリを(すなわちmallocまたはnewを使用して割り当て)my_functionにヒープに割り当てられたchar *またはconst char *、そうでない場合はいつでもmy_functionリターンを返すことを確認する必要があります[const] char *は割り当てが解除され、無効なポインタにアクセスします。

そして最後に、あなたはfreeまたはdeleteあなたはそれで終わった、またはあなたがメモリリークが発生します一度、あなたに返却されています[const] char *をに覚えておく必要があります。 C/C++のような偉大な言語ではありませんか?

ので、Cには、あなたは、「文字列リテラル」を返す機能を持っている場合、それは*のconst char型を返す必要があります

const char *my_function() { 
    const char *my_str = (const char *)malloc(MY_STR_LEN + 1); // +1 for null terminator. 
    /* ... */ 
    return my_str; 
} 

int main() { 
    const char *my_str = my_function(); 
    /* ... */ 
    free(my_str); 
    /* ... */ 
    return 0; 
} 
+1

そのようなことは、私がC++のstd :: string(文字列クラス定義の悪いハックジョブであっても)とスマートポインタ。あなたはCの苦痛を経験する必要があります。 –

+0

@DavidThornley適切な文書はその痛みをほとんどゼロに減らします。 – Qix

1

は、クラッシュが発生することはありません。しかし返す文字列が静的であれば(return "AString"など)、const char *を返して、コンパイラがメモリの変更を試みたことを確認してください。はクラッシュする可能性があります。あなたは確かにキャストなどを使用してコンパイラのチェックを回避することができますが、その場合は、の作業を実行してクラッシュさせる必要があります。

+0

ありがとうございます。あなたがリテラル文字列を返す場合(例えば、 "This is a test";)、戻り値の型はconst char *でなければならないと言っていますか?戻り値の型がchar *の場合はどうなりますか? – Andy

+0

文字列が変更されない場合、危険はありませんが、呼び出し元が文字列を変更しようとすると、アプリケーションがクラッシュします。戻り値の型が 'const char *'の場合、コンパイラはそれを変更させません。 –

+0

ありがとうございます。それはおそらく彼らが話していることでしょう。 Cのもう一つの側面はわかりませんでした(そしてstd :: stringへの3つの歓声は素晴らしいです!)。 – Andy

4

通常、これは問題ではありませんが、考慮する必要があります。これは通常、const-correctnessの問題です。これは、変更できるものとできないものを追跡することを意味します。

二重引用符で囲まれた文字列を返す場合は、const char *であり、何かのように扱うことはトラブルの招待です。このような文字列を変更することは、未定義の動作ですが、通常、プログラムが参照されている場所では、その文字列をクラッシュさせたり変更したりします。

スタック上の文字配列(つまり、呼び出される関数のローカル変数)を返すと、ポインタは何も指さなくなります。

呼び出された関数がすでにconst char *の何かを返している場合、char *に変更するにはキャストが必要です。さらに、実際に変更する場合は、変更可能であることを確認する必要があります。 const char *としておく方が通常ははるかに優れています。

ありmalloc()またはnewに割り当てられたメモリを返すとは当面の問題はませんが、あなたは所有権の問題を持っています:どのような機能がfree()/deleteべきことは、とき、あなたは、可能なコピーについて何をしますか?これはC++のスマートポインタが輝く場所です。

関連する問題