こんにちは､ お帰りなさい｡
この講義では､ ローカル変数とグローバル変数についてお話したいと思います｡
これはまさに関数スコープ､ あるいは一般的なプログラムスコープの概念である｡
それは､ 変数を使えるときと使えないときに関係する｡
機能とは何かを知っている｡
では､ 次にローカル変数について説明します｡
ローカル変数が関係するのは､ 関数だけではありません｡
ローカル変数は､ コードのブロックを持つものに関係します｡
そこで､ 関数の内部で定義される変数を自動ローカル変数と呼びます｡
つまり､ その関数本体の中で､ 開始括弧と終了括弧の間に､
変数を宣言すると､ その変数はローカル変数となる｡
この関数が呼び出されるたびに､ 自動的に作成されます｡
また､ その変数へのアクセスにおける値は､ その関数にのみ局所的に存在する｡
その関数の外では､ その変数にアクセスすることはできません｡
つまり､ 特定の関数にローカルな変数であれば､ 他の関数でアクセスすることはできないのです｡
定義されているところからしかアクセスできない｡
関数内部で変数に初期値を与えると､
その関数が呼ばれるたびにその初期値が変数に代入されます｡
もし､ その後に呼び出すたびに変数に値を保持したい場合､ 実はcでそれを実現する方法があります｡
それは､ 関数内でスタティック変数と呼ばれるものです｡
これは､ 初級クラスにはない高度な概念ですが､
関数を呼び出すたびに異なるデータを実際に持つことができる方法です｡
つまり､ 例えばある関数が何回呼ばれたかのカウンターを保持したい場合､ その関数名の内部にstaticというキーワードでローカル変数を宣言することになる｡
しかし､ 通常のローカル変数だけでは､ 毎回新しい値を持つことになります｡
データ型の前にautoキーワードを使用することもできますが､ 必須ではありません｡
少しは精度が上がるんですけどね｡
インクルードしなければ､ コンパイラがデフォルトで追加してくれます｡
でも､ もし入れたとしても､ 精度が上がるだけで､
必要ないんです｡
だから､ 自動ローカル変数と呼ばれるのです｡
cにはautoというキーワードがありますが､ デフォルトで提供されているので提供する必要はありません｡
そのため､ 変数の定義や関数の中での宣言を行っている多くの例では､ autoを見かけません｡
ローカル変数は､ ブロック､ ループ､ if文の中で変数が作成されるコードにも適用されます｡
繰り返しになりますが､ if文のブロックの中にif文がある場合､ 括弧が始まるところだけです｡
それがブロックと呼ばれるものです｡
ブロックは関数の中にも､ if文の中にも､ ループの中にも入れることができます｡
ブロックは､ 基本的に括弧があるところならどこでもいいんです｡
括弧があるところならどこでも､ その変数を作成するのです｡
変数の作成とは､ 変数を宣言し､ 値を代入することです｡
しかし､ その変数を宣言した場合､ ブロックの中でその変数を作成した場合､
その変数はブロックの中でしか使うことができないのです｡
ブロックの外でその変数にアクセスしようとしても､ その変数は使われない｡
つまり､ if文の中で変数を宣言すれば､
if文のブロックの外からでもその変数にアクセスできるわけです｡
これを理解することは非常に重要です｡
他の場所でアクセスしようとすると､ コンパイラは文句を言ってエラーを出します｡
そして､ これはデータの値がそのブロックにのみ適用されることを意味します｡
データを共有しない
グローバル変数は､ ローカル変数の反対です｡
グローバル変数は､ プログラム中のどの関数からもアクセスすることができます｡
グローバル変数の作成方法は､ 関数の外側の一番上に置くだけです｡
つまり､ グローバル変数は関数の外側で宣言され､ どの関数にも属さないのです｡
メインキーワードのmainは関数と覚えておいてください｡
そのため､ メイン関数で定義された変数は､ メイン関数の中でのみアクセス可能です｡
そのため､ main関数内の変数は､ 他の関数ではアクセスできないようになっています｡
すべての関数で使われる変数が欲しい場合は､ 関数の外､ 通常はソースファイルの一番上に変数を置き､
これはグローバル変数であるという印をつけます｡
グローバル変数は､ プログラムが始まってから止まるまでの間､ そのグローバル変数がメモリ上に配置されることになる､
というのが嘘のような話です｡
プログラム中のどの関数も､ そのグローバル変数の値を変更することができます｡ なぜなら､ その関数にはアクセス権があり､ その値を変更することができるからです｡
というのも､ 同じデータにどこからでもアクセスできるコードができてしまうからです｡
グローバル変数と同じ名前のローカル変数が関数内で宣言されている場合､
その関数はローカル変数を使用し､ グローバル変数をマスクすることになります｡
つまり､ ある関数の中にxというグローバル変数とxというローカル変数があった場合､
ローカル変数が優先されるのです｡
グローバル変数のデータを変更することはありません｡
その変数に代入しても､ ローカル変数が変更されるだけです｡
つまり､ 同じ名前にするとグローバル変数にアクセスできなくなり､
実際にそのローカル関数内でもアクセスできなくなるので､ 混乱を招くだけなので基本的に同じ名前は使わないようにしましょう｡
プログラミングをたくさんしている人､ 上級プログラマーはすぐにこのことに気がつくと思います｡
同じ名前のグローバル動詞があっても､ これはローカル変数を変更しただけの行為だと言うでしょう｡
しかし､ 初心者の方にとっては､ あまりピンとこないこともあるのではないでしょうか｡
一例を挙げましょう｡
この例では､ main関数の前の一番上の部分でグローバル変数を作成しています｡
そして､ プログラムを構成する方法としては､ 通常､
いくつかのコメントの後にinclude文を先頭に置き､ いくつかの定数を定義し､
グローバル変数を置くことになります｡
グローバル変数は､ 通常の変数と同じように見えます｡
実際に宣言される場所だけです｡
もし､ 関数の外で宣言されていれば､ グローバルです｡
そこで､ この例では､ my globalというグローバル変数を持っています｡
0に初期化しています｡
また､ これらのグローバル変数は､ どこでも初期化することができます｡
宣言時に初期化することもできますし､ 任意の関数で初期化することもできます｡
整数である｡
また､ my関数と呼ばれる関数の中にmain関数を2つ持っています｡
その内部には､ その関数の内部でのみアクセス可能なローカル変数があります｡
main関数の中で､ my localのmainを用意しています｡
私のローカルなmainにアクセスできるのは､ main関数の中だけです｡
でも､ 私のglobalはグローバルな変数なので､ main関数の中でもアクセスできるんです｡
つまり､ mainはローカルとグローバルの2つの変数にアクセスすることができます｡
そして､ 私の関数にはxというローカル変数があります｡ これは関数本体の括弧の中で宣言されているからで､
実際には私のグローバル変数にアクセスすることができます｡
xにもアクセスできるが､ 私のローカルにはアクセスできない｡
私の地元のメインというべきものです｡
なぜなら､ 私のローカルなmainはmain関数の中だけだからです｡
私たちはそれにアクセスすることができないのです｡
もし､ my関数内でmyローカルmain変数を書いたり読んだりしようとすると､
コンパイラはエラーを出します｡
このローカルとグローバルの概念を理解する必要があります｡
ローカルはコードのブロックの中にあります｡
宣言されると､ そのブロックの中でしか使えません｡
もし変数がブロックの外にあり､ 関数の中だけ､ あるいはプログラム自体の中だけであれば､
どの関数でもアクセスすることができます｡
グローバル変数は避けるべきです｡
グローバル変数というのは､ ある種､ 悪いものです｡
グローバル変数が悪いもので､ なぜ避けるべきかというと､
関数間の結合を促進させるからです｡
カップリングとはどういう意味ですか？
カップリングとは依存関係を意味します｡
グローバル変数があり､ それが4つの関数で使われているとしたら､
それぞれの関数が他の関数に依存する可能性があるということです｡
依存性の何が問題なのか？
依存性があると､ プログラムのデバッグやエラーの発見が非常に困難になります｡
もしプログラムにバグがあり､ グローバル変数を使っていて､ そのグローバル変数がバグの原因になっているとしたら､
そのバグは､ そのグローバル変数を使っている関数のどこにでもある可能性があるのです｡
グローバルなデータがあるとややこしいですね｡
グローバル変数があると､ 関数1､ 関数2､ 関数3､ 関数4で変更される可能性があります｡
アクセスを制限しているわけではないんですね｡ また､ 一度エラーを発見し､ それを切り分けると､
それを修正するのは非常に難しいかもしれません｡
なぜなら､ 今､ それを修正すると､ これらの依存関係のために他の機能で問題が発生する可能性があるからです｡
グローバル変数は､ このような依存関係があるため､
できるだけ避けるべきです｡
使う必要がある場合もありますが､ 避けたほうがいいでしょう｡
また､ C++やJavaのようなオブジェクト指向の言語では､
グローバル変数という概念すらないのが現状です｡
静的変数はクラス変数になり得ますが､ それでもクラスの中にカプセル化されています｡
グローバルデータは悪いことなので､ 新しい言語では実際に禁止しようとします｡
そして､ プログラムを複雑にするだけでなく､ エラーの発見やデバッグが難しくなるので､
なるべく避けるべきです｡
グローバルデータを使用する代わりに､ 関数にデータを渡す｡
関数が何らかのデータにアクセスする必要がある場合､ それを渡します｡
もし......データがたくさんあって､ パラメータをたくさん持ちたくないのなら､
理論的には5つ以上のパラメータを持つべきじゃないでしょう｡
クリーンコード」という素晴らしい本がありますが､ この本はコードの品質やグローバル変数のような避けるべきものについて述べています｡
また､ 関数にいくつのパラメータを持たせるかについても触れています｡
また､ 関数に20個のパラメータがある場合は､ 何かが間違っている証拠です｡
主に､ その関数が過剰な処理をしている可能性があるからです｡
しかし､ 関数はデータを渡すだけでデータにアクセスすることができ､ グローバルデータの使用を制限することができるのです｡
また､ 多くのデータを受け取る関数では､ 構造体というものを使うことができます｡
これはまだ説明していませんが､ 別の方法です｡
だから､ グローバルデータは必要なときだけ､ なるべく使わないでください｡
コードを理解するようにする｡
本当に､ 本当によく記録しておいてください｡
そうすれば､ 他の誰かがコードを見たときに､ あなたがグローバルデータを使っていることがすぐにわかり､
すべてがどのように動くのかがわかります｡
これがファンクションスコープの概念である｡
このことを理解する必要があるので､ このスライドをすべて注意して見てください｡
また､ 次のチャレンジでは､ グローバルなデータとローカルなデータを使う予定です｡
ありがとうございます｡