ローカル変数
C言語のローカル変数について解説します。ローカル変数は、関数の内部で宣言された変数のことです。
ローカル変数の宣言
変数の宣言は以下の構文で行います。
型名 変数名;
関数の中で記述された変数宣言は、ローカル変数の宣言になります。
int main (void) { 型名 変数名; }
int32_t型の変数宣言をするサンプルを書いてみます。
#include <stdint.h> int main (void) { int32_t num; }
ローカル変数の初期化
変数宣言は、変数の初期化と同時に行うことができます。
#include <stdint.h> int main (void) { int32_t num = 1; }
C言語では、変数の初期化を行わない場合に、自動的に0に初期化されず、値は不定になるということに注意してください。
Perlの変数の場合は未定義値undefで初期化される点が異なります。
ローカル変数のスコープ
C言語のローカル変数のスコープについて書いておきます。C言語ではスコープを「{}」を使って記述できます。スコープの中で変数宣言を行うことができます。変数はスコープの中でだけ参照することができます。関数の中でだけスコープを使用できます。
#include <stdint.h> int main (void) { { int32_t num1; 1 + 1; int32_t num2; } } // この位置ではnum1, num2は見えない。
C99からはどの位置でもローカル変数宣言が可能
C99からはどの位置でもローカル変数宣言が可能になりました。ローカル変数の宣言は、ブロックの先頭でなければならないという制約はなくなりました。
#include <stdint.h> int main (void) { { int32_t num1 = 5; 1 + 1; // どの位置でもローカル変数の宣言が可能 int32_t num2 = 4; } }
const修飾子
const修飾子をローカル変数につかうと、初期化以外でのローカル変数への代入を禁止することができます。これは、コンパイル時エラーを発生させます。
#include <stdio.h> #include <stdint.h> int main(void) { const int32_t num = 1; // コンパイルエラー num = 2; }
文字列を表現するためのconst char*
constがよく使われるのは、文字列の要素に対する代入を防ぎたい場合です。
文字列を表現する型として「const char*」という型について書きました。
// 文字列を表現する型 const char* message = "Hello";
ここではconstの役割を詳しく解説します。constは代入を禁止するための構文です。では「const char*」で一体どのような代入が禁止されるのでしょうか?
勘違いしてしまいがちですが「message」への代入が禁止されるわけではありません。これは大丈夫です。
// OK message = "Goodby";
実はここでのconstはポインタ「*」にかかっているのです。つまり、ポインタが指している要素への代入の禁止という意味になります。
// コンパイルエラー message[3] = 'a';
あまり意味のないことですが、もし、変数への代入を禁止したいなら次のように書きます。この場合はconstが変数名にかかっています。どこにかかっているのかを確認してください。
char* const message = "Hello";
constはキャストではずすことができる
constは型キャストではずすことができます。「ええー」。
char* message2 = (char*)message;
ということは、const修飾は、間違いを減らすという意味しかないということです。それでも、明示的に文字列定数として使っていることを示すことができますし、間違いは起こりやすいのでconstをつけたほうが良いです。
文字列の配列を表現する
さてもう一つconstの使う場面を紹介。定数文字列を含んだ要素の変更ができない配列の作り方です。
#include <stdio.h> int main(void) { const char* const strings[] = { "Apple", "Orange", "Grape", }; printf("%s %s\n", strings[0], strings[1]); }
constはどこにかかっているのかなぁ。うーん。わかりにくい。
const char* const strings[]
最初のconst「const char*」は、ポインタの指し示す先でしょう。つまり、文字列の要素への代入の禁止。
次は、どうなってんだ。「const strings[]」。えーっと、答えを書くと、変数への代入も禁止されますし、配列の要素への代入も禁止されます。なんで? 知らん。
次に紹介するstaticと今紹介したconstは全く機能が違うので、注意してください。雰囲気が似ているので、混同してしまいがちです。
静的ローカル変数
C言語では、ローカル変数にstatic修飾子をつけることで、静的ローカル変数を宣言できます。
int foo (void) { // 静的ローカル変数 static int32_t foo; static int32_t bar = -5; }
静的ローカル変数という名前ですが、実際の役割について考えると、スコープのあるグローバル変数と考えるのがよいです。
寿命は、プログラムの開始から最後までですが、スコープを持たせて、スコープ外から直接アクセスさせないようにできます。
静的ローカル変数は、グローバル変数と同じく0(すべてのビットが0)で初期化されます。代入演算子の右辺に定数を記述すると、その値で初期化されます。
static宣言の初期化における代入は、プログラムの最初に一度だけおこなわれるということに注意してください。関数が実行されるたびに、初期値が代入されるわけではありません。
静的ローカル変数のサンプル
静的ローカル変数のサンプルです。静的ローカル変数は、プログラムの最初から最後まで存在しているところに注目してみてください。
#include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <string.h> void foo(void) { static int32_t num = -5; num++; printf("%d\n", num); } int main(void) { foo(); foo(); foo(); foo(); foo(); }
出力結果です。
-4 -3 -2 -1 0