static付きの宣言をした場合の変数の初期化について教えてください。(ANSI-C)
int func(void)
{
static int si;
static char sca[10];
static char *scp;
/* 何らかの処理 */
return 0;
}
このように関数内でstatic付きで宣言したとき、変数はどのように初期化されますか?
siは0、sca[0]からsca[9]までは'\0'、scpはNULLで初期化されますか?
また、このようなstatic付きの宣言が関数の外にあった場合は、どのように初期化されますか?
No.9ベストアンサー
- 回答日時:
自信を持って取り消し。
質問に対しての
~~~~
>siは0、sca[0]からsca[9]までは'\0'、scpはNULLで
>初期化されますか?
A.はいそうです。
>static付きの宣言が関数の外にあった場合は、どのよう
>に初期化されますか?
A.同じです。
~~~~
についての結論は変わりませんが、
根拠説明時の宣言領域内の全クリアについては、確かに
確実な回答ではないようです。
calloc は単にメモリのバイト単位クリアなので、値に対する
保障が無関係なのはその通りですが、静的領域のクリア
にはコンパイラにより確実な処理が含まれているのかも
知れません。
事実上は
ポインタ→NULL=0
数値変数→0
なのでどっちでも同じことですが、
・値・・・0かつビット配列・・・0以外 の型定義が存在するとき
・NULLポインタのビット配列が0でない場合
現実的かどうかは別として、上記の条件のものがある場合の
動作保障については、よくわかりません。
参考までに構造体と列挙型の静的宣言確認を載せておきます
ただしこれも、ビットクリアされているのか、メンバ単位に
数値変数=0・ポインタ=NULLとしてのコンパイラ処理されて
いるのかの区別はつきません。
おかげでひとつ利口になった。
----------------------------------------------
#pragma pack(1)// 境界整列用(処理系依存デフォルト4)
struct TESTSTRUCT {
double numd;
int num;
char chara[13];
void* ptr;
};
enum TESTENUM {
aaa = 2,
bbb =356,
ccc = 568
};
static struct TESTSTRUCT ts;
static enum TESTENUM te;
int main()
{
char* pdump;
int i;
int tssize, tesize;
tssize = sizeof(struct TESTSTRUCT);
tesize = sizeof(enum TESTENUM);
// ダンプ
printf("TESTSTRUCT size = %d\n", tssize);
pdump = (char*)&ts;
for(i = 0; i < tssize; i++) {
printf("%02X ", pdump[i]);
if((i % 8) == 7)printf(" ");
if((i % 16) == 15)printf("\n");
}
printf("\n");
printf("TESTENUM size = %d\n", tesize);
pdump = (char*)&te;
for(i = 0; i < tesize; i++) {
printf("%02X ", pdump[i]);
if((i % 8) == 7)printf(" ");
if((i % 16) == 15)printf("\n");
}
printf("\n");
// メンバ
printf("TESTSTRUCT (double)ts.numd = %f\n", ts.numd);
printf("TESTSTRUCT (int)ts.num = %d\n", ts.num);
printf("TESTSTRUCT (char[])ts.chara[] = ");
for(i = 0; i < sizeof(ts.chara); i++)
printf("%02X ", ts.chara[i]);
printf("\n");
printf("TESTSTRUCT (void*)ts.ptr = 0x%08X\n", ts.ptr);
printf("TESTENUM te = %d\n", te);
return 0;
}
----------------------------------------------
ということは、質問に書いたとおりに初期化されるんですね。
また、(質問には書いてないですが)No.5の参考URLから、浮動小数点数は0.0に初期化されることもわかりました。
みなさん、ありがとうございました。
No.7
- 回答日時:
こう覚えたらよいと思います
・staticで宣言された領域は起動時に初期値が入る
・初期値とは0である
・NULLも'\0'も0である
注意
・関数の中でstaticを使った場合、1回目は0だが、一度書き換えて、もう一度その関数を呼んだ場合、書き換えた値のままである
この回答への補足
この質問は、つまるところ、static変数は全ビット0で初期化されるのか、それとも、ポインタはNULLで初期化され、数値は0で初期化されるのか、を聞いているわけです。
全ビット0ではないようですね。
>・NULLも'\0'も0である
そうそうNULLって、0なんだよなあ~~、って思い出しました。
こんなプログラムを作りましたが、NULLのビットパターンがわかるわけでもないし、質問とは直接関係ないし、大して意味はないし、どうでもいいようなプログラムですけど。
(繰り返しますが、質問とはそんなに関係ないです。)
#include <stdio.h>
int main(void)
{
#ifdef NULL
puts("NULLマクロは定義されています。");
if(NULL==0)
puts("NULLは0です。");
else
puts("NULLは0ではありません。");
#else
puts("NULLマクロは定義されていません。");
#endif
return 0;
}
実行結果
NULLマクロは定義されています。
NULLは0です。
No.6
- 回答日時:
皆さん、ご指摘ありがとうございます。
最新の規格書にて再確認したところ、皆さんが仰る通り初期化されると書いてありました。
混乱を招きますので、管理者に私のコメントを削除をしてもらうよう、連絡しておきます。
この回答への補足
回答ありがとうございます。が、他の方の回答も ららぽーとさんのNo.1の回答を前提に書かれているものもありますし、、、
本当に混乱を避けるんであれば質問ごと削除する必要があるかと思いますが、それは困りますんで、
ご趣旨はわかりましたので、ご回答はもとのままにしておいてください。
私からのお願いです。
No.5
- 回答日時:
記憶クラスと初期化省略時初期値の関係は単純です。
auto:不定
その他:全てのビットが0である値
例外)
extern:記憶領域を確保しない
typedef:記憶領域の宣言ではない
例外であるextern記憶クラスとtypedef記憶クラスを除くと2パターンしかありません。
この回答への補足
static付きで宣言された場合、全ビット0で初期化されるが、その数値が0なのか(ポインタの場合NULLになるか)は決まっていないんですね。
補足日時:2002/07/13 10:30No.4
- 回答日時:
他の方々が言われるように ANSI C ならstatic付の宣言では0で初期化されることが保証されます。
ただ、初期化されるのはメモリを確保したときのみなので、例ですとfuncを呼び出すたびに初期化では無く、プログラムの起動時に1回だけ0に初期化と成ります。
2回目以降のfuncの呼び出しではsi等の値は、前回の/* 何らかの処理 */ で代入された値のままに成ります。
Lara-Portさんが言われるような不定値には成りません。
と言うか、初期化と代入を混同しているように見受けられますが・・・
参考URL:http://www.catnet.ne.jp/kouno/c_faq/c1.html#30
この回答への補足
参考URL見ました。「C言語 FAQ 日本語訳 」というものですね。
そこには、staticつきの場合、ポインタはヌルポインタに、浮動小数は0.0に初期化されると書いてありました。
しかし、気になることも書いてあります。私なりに解釈すると、
「calloc()によって確保された領域は全ビット0になるが、それが浮動小数の0.0やヌルポインタを意味するとは限らない。」
ということみたいです。
処理系によっては、static変数は、全ビット0で初期化されるとは限らないのでしょうか。
No.3
- 回答日時:
dtmさんが既に答えられてますが、
静的宣言は指定が無ければ全て0クリアされます。
>static int si;
>static char sca[10];
>static char *scp;
si ・・・ 0
sca[0] ~ sca[9] ・・・オール0
scp ・・・ NULL
宣言領域内が全部クリアされるだけなので、関数内・外、配列・ポインタ 等の区別は全て無いです。
ありがとうございます。
ご回答どおり、static変数は全ビット0になるようです。
次のプログラムを動かしてみました。(意図したとおりに動いているかは自信ないけど。)
#include <limits.h>
#include <stdio.h>
#include <string.h>
void func(void)
{
static int si;
static double sdouble;
static char sca[10];
static char *scp;
int not_static_i;
int i;
char null_char='\0';
char null_char_array[10]={
'\0' , '\0' , '\0' ,
'\0' , '\0' , '\0' ,
'\0' , '\0' , '\0' , '\0'
};
puts("とりあえず前提として");
printf("1バイトのビット数は%dです。\n" , CHAR_BIT ) ;
printf("siは%dバイトです。\n" , (int)sizeof(si) );
printf("sdoubleは%dバイトです。\n" , (int)sizeof(sdouble) );
printf("scaは%dバイトです。\n" , (int)sizeof(sca) );
printf("scpは%dバイトです。\n\n" , (int)sizeof(scp) );
puts("'\\0' のビットパターン ");
for( i=CHAR_BIT-1 ; i>=0 ; i-- )
{
printf("%d" , (null_char >> i) & 0x01);
}
printf("\n\n");
if( memcmp(¬_static_i , null_char_array , sizeof(not_static_i) ) )
{
puts("not_static_iは0でないビットが含まれています。");
printf("ちなみにnot_static_iは%d\n", not_static_i );
}
else
puts("not_static_iは全ビット0です。");
printf("\n★★★それではstatic変数は…★★★\n");
if( memcmp(&si , null_char_array , sizeof(si) ) )
puts("siは0でないビットが含まれています。");
else
puts("siは全ビット0です。");
if( memcmp(&sdouble , null_char_array , sizeof(sdouble) ) )
puts("sdoubleは0でないビットが含まれています。");
else
puts("sdoubleは全ビット0です。");
if( memcmp(sca , null_char_array , sizeof(sca) ) )
puts("scaは0でないビットが含まれています。");
else
puts("scaは全ビット0です。");
if( memcmp(&scp , null_char_array , sizeof(scp) ) )
puts("scpは0でないビットが含まれています。");
else
puts("scpは全ビット0です。");
}
int main(void)
{
func();
return 0;
}
結果
とりあえず前提として
1バイトのビット数は8です。
siは4バイトです。
sdoubleは8バイトです。
scaは10バイトです。
scpは4バイトです。
'\0' のビットパターン
00000000
not_static_iは0でないビットが含まれています。
ちなみにnot_static_iは512
★★★それではstatic変数は…★★★
siは全ビット0です。
sdoubleは全ビット0です。
scaは全ビット0です。
scpは全ビット0です。
No.2
- 回答日時:
最新の ANSI C を知らないので流そうかと思ったのですが、気になったので書かせていただきます。
私の知る限りでは、static 変数はゼロ(あるいはヌル)に初期化されたはずです。関数の外で宣言された場合も同じくゼロに初期化されます。どちらもプログラムが実行されるとすぐに割り当てられ初期化され、終了するまで維持されます。
これが ANSI C で定義されていないのであれば、処理系独自の拡張という事でしょうか? 初期化されることを前提として書かれたソースも多くあり、これが ANSI から外されるというのは少し疑問です。
この回答への補足
>これが ANSI C で定義されていないのであれば、処理系独自の拡張という事でしょうか?
自分でもやってみました。double型も付け加えました。
#include <stdio.h>
int func(void)
{
static int si;
static double sdouble;
static char sca[10];
static char *scp;
int i;
printf("siは%dです。\n",si);
putchar('\n');
printf("sdoubleは%fです。\n",sdouble);
putchar('\n');
for(i=0 ; i<10 ; i++)
{
if(sca[i]=='\0')
printf("sca[%d]は'\\0'です。\n", i ) ;
else
printf("sca[%d]は'\\0'ではありません。\n",i) ;
}
putchar('\n');
(scp==NULL) ? puts("scpはNULLです。") : puts("scpはNULLではありません。") ;
return 0;
}
int main(void)
{
func();
return 0;
}
結果
siは0です。
sdoubleは0.000000です。
sca[0]は'\0'です。
sca[1]は'\0'です。
sca[2]は'\0'です。
sca[3]は'\0'です。
sca[4]は'\0'です。
sca[5]は'\0'です。
sca[6]は'\0'です。
sca[7]は'\0'です。
sca[8]は'\0'です。
sca[9]は'\0'です。
scpはNULLです。
きちんと、int型は0、double型は0.0、sca[0]からsca[9]までは'\0'、scpはNULLに初期化されているようですね。
>初期化されることを前提として書かれたソースも多くあり、これが ANSI から外されるというのは少し疑問です。
そうですね。
もちろん、質問は、そういう処理系に依存する話ではなくて、規則としてそのように初期化されることが定まっているか、です。
No.1
- 回答日時:
C言語では、ANSIの仕様・宣言する位置に限らず、変数は初期値を入れない限り、不定値となります。
(偶然、割り当てられた領域が0である場合は初期化されているように見えますが…)ですので、初期値が必要な場合は、main()や各関数の前半で、初期化する習慣をつけましょう。
今回の関数の場合、以下のようにされればいいのではないでしょうか。(static変数の使い方を理解してると仮定して書きます)
<関数の呼び出しが1回目のみ初期値をもつとき>
int func(void)
{
static int si = 0;
static char *scp = NULL;
static char sca[10] ={
NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL
};
/* 何らかの処理 */
return 0;
}
<関数を呼び出すたび初期値をもつとき>
int func(void)
{
static int si;
static char *scp;
static char sca[10];
/* 初期化 */
si = 0;
scp = (char*)NULL;
memset( sca, 0, sizeof(sca));
/* 何らかの処理 */
return 0;
}
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Java java 入力 3 4 3 出力 ABC DEFG HIJ このようなプログラムの書き方を教えてくだ 2 2022/07/15 14:18
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- Java JavaのSingletonパターンのprivateの持つ意味が分かりません。 5 2022/06/12 10:38
- C言語・C++・C# int tff(int clk) { static int state = 0; //状態 stat 1 2022/07/11 21:14
- Java javaでのプログラム(配列)について質問です. 2 2022/10/14 22:27
- Java java 飾子を付けること(public static・・・) ・コンソールへの出力処理はmainメ 2 2022/06/16 19:34
- Java java final 1 2022/06/10 22:49
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- C言語・C++・C# C言語初心者 構造体 課題について 1 2023/03/10 19:30
- Java Java プログラム public class Main { public static void 3 2023/08/10 23:46
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
Enterキーを押されたら次の処理...
-
printf による16進表示について
-
C言語で複数列のデータを1列の...
-
VC++でSQLへSELECT文を送ったの...
-
#defineが使用するメモリ領域に...
-
バイナリファイル(画像)のよみ...
-
[C]セグメンテーションエラー:...
-
char型2つを結合し、short型に...
-
【C言語】全角文字の配列を、全...
-
プログラミングの授業の課題です
-
空白を含んだ文字列がうまく格...
-
C言語のプログラムで、途中で止...
-
大量のファイルを読み込み、そ...
-
csvファイルの読み取り
-
ファイルから数字列を16進数の...
-
構造体メンバの初期化
-
既約分数の表示プログラム
-
マイナスからプラスへ転じた時...
-
プログラムでの数字につく”f”の...
-
DWORDの実際の型は何でしょうか
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Enterキーを押されたら次の処理...
-
printf による16進表示について
-
#defineが使用するメモリ領域に...
-
空白を含んだ文字列がうまく格...
-
char型2つを結合し、short型に...
-
【C言語】全角文字の配列を、全...
-
プログラミングの授業の課題です
-
C言語のプログラムで、途中で止...
-
C++で指定文字列のカウント方法...
-
C言語で複数列のデータを1列の...
-
C言語でのCSVファイルの読み出...
-
構造体メンバの初期化
-
なぜ無限ループになるかが分か...
-
reallocでエラー
-
Ç言語でファイルサイズを変更す...
-
ファイル操作で全角空白を消す
-
矢印キーを押下してコンソール...
-
セグメンテーションエラーの原...
-
static付き宣言の初期化
-
ファイルから数字列を16進数の...
おすすめ情報