#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