- ベストアンサー
static宣言 について教えてください
C言語の初心者です。内部的なstatic配列の理想的な応用例だと教科書に書いてありますが、static宣言しなくてコンパイルしても、普通に動きます。どうしてでしょうか。 char *month_name( int n ) { static char *name[] = { "Illegal month", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; return ( n<1 || n>12 ) ? name[0] : name[n]; } ちなみに下のように書き換えると、static宣言しないとうまく動かなくなります。この二つの違いがわからないです。お願いします。 char *month_name2( int n ) { static char name[13][10] = { "NG", "1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th", "10th", "11th", "12th" }; return ( n<1 || n>12 ) ? name[0] : name[n]; }
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
static char *name[] = { "Illegal month", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; の場合、nameが指すアドレスには、13個のcharのポインタが並んでいます。 nameと名前の付いたメモリ。13個のポインタが並んでる 0個目のポインタは、"Illegal month"へのアドレスが書いてある 1個目のポインタは、"January"へのアドレスが書いてある 2個目のポインタは、"February"へのアドレスが書いてある 以下略。 この時、実際の文字列は「固定の文字列が存在している、リードオンリーなどこかの領域」に存在します。 そして「13個のcharのポインタ」が静的領域にあろうが、動的領域にあろうが、そんな事はどうでも良くて「固定の文字列が存在している、リードオンリーなどこかの領域は不変」です。 つまり、文字列そのものは、nameにstaticを付けても付けなくても、消えて無くなったりはしません。 return文で返されるポインタは「固定の文字列が存在している、リードオンリーなどこかの領域」を指していますから、関数から戻った後でも、ポインタは有効です。 ----- static char name[13][10] = { "NG", "1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th", "10th", "11th", "12th" }; の場合、nameが指すアドレスには10バイトのcharが13個並んでいます。 そして、0~2バイト目が'N' 'G' '\0'に、 10~13バイト目が'1' 's' 't' '\0'に、 20~23バイト目が'2' 'n' 'd' '\0'に、順次、初期化されます。 初期化される場所は「static変数用に用意された、静的なメモリのどこか」です。 staticで宣言されているので、nameは「static変数用に用意された、静的なメモリのどこか」にあり、nameの中身は、関数から抜けても消えたりしません。return文で返されるポインタは「static変数用に用意された、静的なメモリのどこか」を指していますから、関数から戻った後でも、ポインタは有効です。 ----- char name[13][10] = { "NG", "1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th", "10th", "11th", "12th" }; の場合、nameが指すアドレスには10バイトのcharが13個並んでいます。 そして、0~2バイト目が'N' 'G' '\0'に、 10~13バイト目が'1' 's' 't' '\0'に、 20~23バイト目が'2' 'n' 'd' '\0'に、順次、初期化されます。 初期化される場所は「auto変数用に用意された、宣言した関数内でだけ有効な、動的なメモリのどこか」です。 autoで宣言されているので、nameは「auto変数用に用意された、宣言した関数内でだけ有効な、動的なメモリのどこか」にあり、nameの中身は、関数から抜けた瞬間に解放され、消えて無くなります。return文で返されるポインタは「auto変数用に用意された、宣言した関数内でだけ有効な、動的なメモリのどこか」を指していますから、関数から戻った瞬間、ポインタは無効になります。ポインタが指すメモリには、すでにname配列は存在しません。
その他の回答 (1)
- echoes_x86
- ベストアンサー率65% (21/32)
こんにちは. 後者の場合は自動変数を確保して初期化しているわけですから, 関数を抜けた段階で変数nameの内容は保証されなくなります. 典型的にはこの領域はスタック上にありますから, month_name2()の呼び出し元で別の関数を呼んだ瞬間に, 「nameだった領域」は破壊されるでしょう. 前者の場合はstaticをつけようとつけまいと定数として, 静的領域にデータが取られますので, 関数を抜けてもデータは保持されると思われます.
お礼
ありがとうございました。
お礼
詳しく説明していただいて、ありがとうございました。やっとポインタの意味が分かった気がします。