#include <stdio.h> double a = 10.0; /* [A] */ void func1(double a) /* [B] */ { printf("a = %g\n", a); /* (1) */ { double a = 10.0; /* [C] */ printf("a = %g\n", a); /* (2) */ } printf("a = %g\n", a); /* (3) */ } void func2(void) { printf("a = %g\n", a); /* (4) */ { int a = 10.0; /* [D] */ printf("a = %g\n", a); /* (5) */ } printf("a = %g\n", a); /* (6) */ } void func3(double x) { printf("a = %g\n", a); /* (7) */ { int a = 10.0; /* [E] */ printf("a = %g\n", a); /* (8) */ } printf("a = %g\n", a); /* (9) */ } int main(void) { double a = 10.0; /* [F] */ printf("a = %g\n", a); /* (10) */ func1(a); func2(); func3(a); printf("a = %g\n", a); /* (11) */ { double a = 10.0; /* [G] */ printf("a = %g\n", a); /* (12) */ } printf("a = %g\n", a); /* (13) */ return 0; }
次のように, printf 関数に渡すフォーマットに, どのprintfの文を実行しているかが わかるように, 数字などを入れておくと文かり易いやす. また, 各変数aに異なる値を 代入しておくと, どの変数が参照されたかを確認することができる.
#include <stdio.h> double a = 100.0; /* [A] */ void func1(double a) /* [B] */ { printf("(01) a = %g\n", a); /* (1) */ { double a = 110.0; /* [C] */ printf("(02) a = %g\n", a); /* (2) */ } printf("(03) a = %g\n", a); /* (3) */ } void func2(void) { printf("(04) a = %g\n", a); /* (4) */ { int a = 120; /* [D] */ printf("(05) a = %d\n", a); /* (5) */ } printf("(06) a = %g\n", a); /* (6) */ } void func3(double x) { printf("(07) a = %g\n", a); /* (7) */ { int a = 130; /* [E] */ printf("(08) a = %d\n", a); /* (8) */ } printf("(09) a = %g\n", a); /* (9) */ } int main(void) { double a = 140.0; /* [F] */ printf("(10) a = %g\n", a); /* (10) */ func1(a); func2(); func3(a); printf("(11) a = %g\n", a); /* (11) */ { double a = 150.0; /* [G] */ printf("(12) a = %g\n", a); /* (12) */ } printf("(13) a = %g\n", a); /* (13) */ return 0; }
/* 円の面積を求める関数 circle を定義し, その関数を用いて円の面積を求めるプログラム. */ #include <stdio.h> /* o 関数は呼び出す前([*]印を付けた文より前)に定義する必要がある. o 関数は関数の中で定義できない. 従って int main(void) の前に 関数定義を記述することになる. */ /* 以下は関数 circle の定義. この関数は, 半径rを引数として受け取り, 円の面積を求めている. 関数(名)の宣言は 「戻り値の型 関数名(引数の宣言)」 のように記述する. その後ろの { から 対応する } までがその関数で行う処理の内容. */ double circle(double r) { double area; area = r * r * 3.14; return area; // 関数の値/戻り値 は return で指定する. } /* main はプログラム実行時に最初に呼び出される関数. OS から void を受け取り, OS に int を返すことを指定している. ここで, void は引数として何も受け取らないことを明示するキーワード. */ int main(void) { double S; // 関数を呼び出す時に r = 5.0 の代入が起きる. S = circle(5.0); // [*] // 関数内での計算が終わった後, 関数の値が戻される. // ここでは その値を S に代入している. printf("S = %f\n", S); return 0; }
/* 長方形の面積を求める関数 rectangle を定義し, その関数を用いて長方形の面積を求めるプログラム. */ #include <stdio.h> #include <stdlib.h> double rectangle(double a, double b) { double area; area = a * b; return area; } int main(void) { double x, y, area; x = 3.0; y = 4.0; // 引数に与えられた値は, 前から順に代入が起きる. // ここでは, a = x, b = y の代入がおき, その後関数内の処理が行われる. area = rectangle(x, y); printf("area = %f\n", area); // 関数は何度でも呼ぶことができる. area = rectangle(10.0, 3.2); printf("area = %f\n", area); // 関数の戻り値は, 関数の引数として用いることもできる. printf("area = %f\n", rectangle(10.0, 3.2)); return EXIT_SUCCESS; }
変数の型宣言を行うと, その変数に必要な領域がメモリ上に確保される.
型宣言はメモリ上に領域を確保することを指示する命令である. 変数の有効範囲はブロック{ }の中のみである.
注意: //から後ろはコメントを表す(C99).
#include <stdio.h> void func(void) { int a; // この a は func の中でのみ有効. mainの中の aとは別物. a = 10; // func の中の a の値を変更しても, funcの中でのみ有効. // main の中の a には影響しない. printf("func: a = %d\n", a); } /* --------------------------------------------------------- void func(void) { // main 中で宣言された a はここでは使用できない. a = 10; // 誤り. printf("func: a = %d\n", a); // 誤り. } --------------------------------------------------------- */ int main(void) { int a; // この a は main の中でのみ有効. // main中から呼び出す関数中では使用できない. a = 3; printf("main: a = %d\n", a); func(); // 関数の中の操作は呼び出し側には影響を与えない. printf("main: a = %d\n", a); // main の中の a が変更されずに残っている. return 0; }
#include <stdio.h> // 仮引数として宣言された変数 a は関数 func の中でのみ有効. // mainの中の aとは別物. void func(int a) { printf("func: a = %d\n", a); a = 10; // 関数内で宣言した変数と同様に代入もできる. // main の中の a には影響しない. printf("func: a = %d\n", a); } int main(void) { int a; // この a は main の中でのみ有効. // main中から呼び出す関数中では使用できない. a = 3; printf("main: a = %d\n", a); func(15); // 関数の中の操作は呼び出し側には影響を与えない. printf("main: a = %d\n", a); // main の中の a が変更されずに残っている. return 0; }
#include <stdio.h> #include <stdlib.h> int main(void) { int x; double x; // 1つのブロック内で同じ変数名を用いることはできない. x = 3; printf("x=%d\n", x); return EXIT_SUCCESS; }上の例では, このプログラムのファイル名を scope.cとし gcc によりコンパイルすると以下のようにエラーとなる.
scope.c:7: error: conflicting types for ‘x’ scope.c:6: error: previous declaration of ‘x’ was here
#include <stdio.h> int main(void) { int a; // この a は main の中でのみ有効. a = 3; printf("main: a = %d\n", a); // ブロックの中にブロックを作成することができる. // ブロック中でのみ使用する変数は, ブロック中で宣言する. { int a; // この a はmainの先頭で宣言したaとは別物. a = 10; // ブロック外にも同じ名前の変数がある時は, // より内側のブロックで宣言された変数が有効. printf("main_block: a = %d\n", a); } printf("main: a = %d\n", a); // main の中の a が変更されずに残っている. return 0; }
#include <stdio.h> #include <stdlib.h> void fn(int a) { int a=13; //すでに int a が宣言されているので, 再度aという変数名は使えない. printf("a=%d\n", a); } int main(void) { int x = 3; fn(x); return EXIT_SUCCESS; }gccでコンパイルすると以下のようにエラーとなる.
scope.c: In function ‘fn’: scope.c:6: error: ‘a’ redeclared as different kind of symbol scope.c:4: error: previous definition of ‘a’ was here
#include <stdio.h> #include <stdlib.h> void fn(int a) { { int a=13; //仮引数のa より内側のブロック printf("a=%d\n", a); // 内側のブロック内のa } printf("a=%d\n", a); // 仮引数のa } int main(void) { int x = 3; fn(x); return EXIT_SUCCESS; }
#include <stdio.h> /* 大域変数 関数の外で宣言された変数. 初期化は, プログラム開始時で, main関数が実行される前に行われる. 寿命は, プログラムの開始から終了時まで. 変数が宣言された行以降で参照, 代入が可能. 関数, ブロックの中で同じ名前の変数が宣言された場合は, 関数, ブロック内の変数が優先される. */ /* 大域変数. プログラム開始時に 100が代入される. どこからでも代入, 参照が可能. */ int a = 100; void func(void) { printf("func: a = %d\n", a); // funcを呼び出す直前の大域変数の値. a = 10; // 関数中でも大域変数の値を変更できる. printf("func: a = %d\n", a); } int main(void) { printf("main: a = %d\n", a); // 大域変数の初期値が参照される. a = 200; // 大域変数 a に代入される. printf("main: a = %d\n", a); func(); printf("main: a = %d\n", a); // func中で変更した値. return 0; }
#include <stdio.h> int a = 100; //大域変数. どこからでも代入・参照が可能. void func(void) { printf("func: a = %d\n", a); // funcを呼び出す直前の大域変数の値. a = 10; // 関数中でも大域変数の値を変更できる. printf("func: a = %d\n", a); } int main(void) { int a = 0; // このブロック中(main関数中)では, 大域変数のaは使用できない. printf("main: a = %d\n", a); // main 関数中で宣言されたaが参照される. a = 200; // main中の a に代入される. printf("main: a = %d\n", a); func(); printf("main: a = %d\n", a); // main中の a の値が参照される. return 0; }
#include <stdio.h> int a = 100; //大域変数. どこからでも代入・参照が可能. void func(void) { int a; // このブロック中(func関数中)では, 大域変数のaは使用できない. a = 0; // func 関数中で宣言されたaに代入. printf("func: a = %d\n", a); } int main(void) { printf("main: a = %d\n", a); // 大域変数のaが参照される. a = 200; // 大域変数aに代入. printf("main: a = %d\n", a); func(); // func 中のaの変更は, 影響されない. printf("main: a = %d\n", a); // 大域変数aの値が表示される. return 0; }
#include <stdio.h> int a = 100; //大域変数. どこからでも代入・参照が可能. int main(void) { printf("main: a = %d\n", a); // 大域変数aが参照される. a = 200; // 大域変数aの値が変更される. printf("main: a = %d\n", a); { int a; // このブロック中では, 大域変数aは使用できない. a = 10; printf("main_block: a = %d\n", a); // ブロック内の値. } printf("main: a = %d\n", a); // ブロック内の操作は, 大域変数aに影響しない. return 0; }
/* static 変数 ========== static を付けて変数を宣言する。 寿命は, プログラム開始から終了までの間となる。 初期化は, プログラム開始時に1度だけ行われる。 関数内で宣言されていても、前回その関数を呼出した時の値が保持されていて その値を用いることができる。 自動変数 (auto変数) ================ static を付けずに変数を宣言する。 寿命は、変数が宣言されてから、その変数のブロック(スコープ)が終了するまで。 関数の先頭で宣言されている場合は、関数から戻るまでになる。 初期化は、変数が宣言されるたびに毎回行われる。 関数から戻るときに、変数の値を保持する為の領域がなくなるので、 前回その関数を呼出したときの値は保持されない。 */ #include <stdio.h> // funcA ではstatic を付けて int aが宣言されている。 // プログラム開始時のみ, aが1に初期化され、 // 呼出されるたびにaの値が2倍になり、その値が記憶される。 int funcA(void) { static int a = 1; a *= 2; return a; } // funcB ではstatic を付けないで int aが宣言されている。 // 関数が呼び出され、変数を宣言するたびに, bが1に初期化される。 // 次回の呼び出し時まで値が保持されることはない。 int funcB(void) { int b = 1; b *= 2; return b; } int main(void) { int i, val; for(i=0; i<10; i++){ val = funcA(); printf("%d\n", val); } for(i=0; i<10; i++){ val = funcB(); printf("%d\n", val); } }
(c)1999-2013 Tetsuya Makimura