• 検索結果がありません。

概要 プログラミング論 変数のスコープ, 記憶クラス. メモリ動的確保. 変数のスコープ 重要. おそらく簡単. 記憶クラス 自動変数 (auto) と静的変数 (static). スコープほどではないが重要.

N/A
N/A
Protected

Academic year: 2021

シェア "概要 プログラミング論 変数のスコープ, 記憶クラス. メモリ動的確保. 変数のスコープ 重要. おそらく簡単. 記憶クラス 自動変数 (auto) と静的変数 (static). スコープほどではないが重要."

Copied!
6
0
0

読み込み中.... (全文を見る)

全文

(1)

プログラミング論

変数のスコープ,記憶クラス. メモリ動的確保. http://www.ns.kogakuin.ac.jp/~ct13140/ProgC/

概要

• 変数のスコープ – 重要.おそらく簡単. • 記憶クラス – 自動変数(auto)と静的変数(static). – スコープほどではないが重要. C-2

変数のスコープ

ブロック

• C言語では,{ から } をブロックという. void main(){ for(…){ if(…){ } } if(…){ } } C-4

変数の宣言

• グローバル変数 – 関数の外(当然ブロックの外)で変数の宣言を行う. C, C++に依らず同じ. – 全ての関数内で使用可能. • ローカル変数 – C言語では, 変数の宣言は,ブロックの先頭でのみ行える. – C++では, 変数の宣言は,ブロック内の任意の位置で行える. – 宣言されたブロック内でのみ使用可能. C-5

変数のスコープ

• 変数が使用できる範囲を"SCOPE"と言う. • SCOPEの広さは,変数を宣言した場所により異な る. • 変数宣言が含まれているブロックで最も狭いもの が選ばれる. – 変数は,宣言された中括弧{}の内側でのみ使用可 能.括弧の外では使えない. 括弧の内側には入れるが, 括弧の外側には出られない. C-6

ローカル変数とグローバル変数

#include <stdio.h> int a; void main(){ int b; } void func(int c){ int d; } グローバル変数 ローカル変数 ローカル変数 ローカル変数 C-7

ローカル変数

#include <stdio.h> int a; void main(){ int b; b = 7; printf("b = %d¥n", b); } void func(int c){ int d; b = 8; printf("b = %d¥n", b); } int bのスコープ範囲 NG NG OK OK C-8

(2)

ローカル変数

#include <stdio.h> int a; void main(){ int b; d = 7; printf("d = %d¥n", d); } void func(int c){ int d; d = 8; printf("d = %d¥n", d); } int dのスコープ範囲 OK OK NG NG C-9

ローカル変数

#include <stdio.h> int a; void main(){ int b; c = 7; printf("c = %d¥n", c); }

void func(int c){

int d; c = 8; printf("c = %d¥n", c); } int cのスコープ範囲 OK OK NG NG int cは, 「ブロックの外で 宣言されている」 ように見えるが, SCOPEの範囲は, 関数内です. ご注意あれ. C-10

グローバル変数

#include <stdio.h> int a; void main(){ int b; a = 7; printf("a = %d¥n", a); } void func(int c){ int d; a = 8; printf("a = %d¥n", a); } グローバル変数 プログラム内の 全ての関数内で, 参照可能. int aのスコープ範囲 OK OK OK OK C-11

ローカル変数(ブロック内宣言)

void main(){ int i; for(略){ int j; } } int iは内側(ピンク)ブロックに入れるが, int jはピンクブロックの外に出られない. C-12

ローカル変数(ブロック内宣言)

void main(){ int i; if(略){ int j; } } C-13

ローカル変数(ブロック内宣言)

void main(){ int i; { int j; } } 上記のように,for文やif文などなく 唐突に { } でブロックを作成しても問題ない. C-14

ローカル変数(ブロック内宣言)

void main(){ int i; { int j; } } 上記の違いは,int jのスコープの広さ. void main(){ int i, j; }

スコープの広さの善し悪し

• 一般に,以下のように考えられている. – スコープは狭いほどよい. – グローバル変数は良くない • グローバル変数や広いスコープは,間違い(バグ )の原因になりやすい. – 変数の値がどこで変更さているのか把握しづらくなる – グローバル変数が多いと,各箇所で「理解しなくては ならない変数」の数が増えて辛くなる.

(3)

同じ名前の変数が2個以上あったら

• 同じ名前の変数が2個以上あったら,スコープの 狭い変数が勝つ – 感覚的には,近くで宣言されている変数が勝つ. • ただし,混乱の元なので,このようなことは行わな いことを強く推奨する. C-17 #include <stdio.h> int a = 3; void main(){ printf("a = %d¥n", a); } a = 3 実行結果 C-18 #include <stdio.h> void main(){ int a = 7; printf("a = %d¥n", a); } a = 7 実行結果 C-19 #include <stdio.h> int a = 3; void main(){ int a = 7; printf("a = %d¥n", a); } a = 7 実行結果 C-20 #include <stdio.h> int a = 3; void main(){ int a = 7; { int a = 9; printf("a = %d¥n", a); } printf("a = %d¥n", a); } a = 9 a = 7 実行結果 正しいプログラムだが, 「同じ名前の変数が 2個以上存在する」など, 混乱の元. このようなプログラムは 避けることを勧める. C-21

同じ名前の変数が2個以上あったら

• 以下の様に,同一ブロック内で同名の変数を2個 以上宣言するのはNG. void main(){ int x; int y; int x; x = 7; } int xが 2個ある. NG! どっちのint xなのか 分からない. 実行不可能! C-22

変数の記憶クラス

記憶クラス

• auto, static, extern, register, typedef, volatile がある. – auto, static • 重要 – extern • 重要度高くない.分割コンパイル時に必要. – register • 重要度低い.高速化などに使用することあり. – typedef • 重要度はやや高い.「型に別名を付ける」のに使用. – volatile • 重要度低い.マルチスレッドプログラムなどで必要. C-24

(4)

auto変数,static変数

•auto変数は,ブロック内で誕生して,ブロックの 終わり(SCOPEの終わり)で消滅してしまう. – 変数が消滅すると,記憶されていた値も消える. – 毎回,初期化される. – 通常のローカル変数がこれにあたる. – スタック領域を使用. • auto int i; と,型の前に"auto"と書くと,auto変数となる. – ローカル変数は,明示的にstaticと書かない限り勝 手にauto変数となる. auto変数は 誕生と消滅を 繰り返す C-25

auto変数,static変数

•static変数は,プログラム実行開始時に作成さ れ,消滅しない. – 値はプログラム終了まで保持される. – 初期化は,プログラム開始時に1回だけ行われる. – 全てのグローバル変数がこれにあたる. • ただし,スライド36も参照のこと. – ヒープ領域を使用. • static int i; と,型の前に"static"と書くと,static変数と なる.(例え,ローカル変数であっても) – グローバル変数は,強制的にstatic変数となる. C-26

ヒープ領域 と スタック領域

• ヒープ領域とスタック領域の違い はサイズ – ヒープ領域にはメモリが大量にあり,巨大なメモリを使 用したいときはヒープ領域内に確保する – スタック領域には少量のメモリしかない.大量のメモリ をスタック領域内に確保するのは不可能 C-27

auto変数とstatic変数の例

#include <stdio.h> void main(){ int i;

for(i=0; i<3; i++){

printf("i=%d, ", i); { int j =6; printf("j=%d, ", j); j++; printf("j=%d¥n", j); } } } i=0, j=6, j=7 i=1, j=6, j=7 i=2, j=6, j=7 実行結果 int型変数jは, ブロックに入る毎に作成され,初期化され, ブロックを抜けて消滅してしまう. C-28

auto変数とstatic変数の例

#include <stdio.h> void main(){ int i;

for(i=0; i<3; i++){

printf("i=%d, ", i); { static int j =6; printf("j=%d, ", j); j++; printf("j=%d¥n", j); } } } i=0, j=6, j=7 i=1, j=7, j=8 i=2, j=8, j=9 実行結果 int型変数jは, プログラム開始時に1回だけ作成され,1回だけ初期化され, プログラム終了まで消滅せず,値は保持される. C-29

auto変数と

static変数の例

#include <stdio.h> void main(){ int i;

for(i=0; i<3; i++){

printf("i=%d, ", i); { static int j =6; printf("j=%d, ", j); j++; printf("j=%d¥n", j); } j = 100; /* j はここからは見えない! */ } } 例えstaticでも, jのスコープは, ブロックの中なので, ブロックの外からは アクセスできない. 感覚的には, 「存在しているが, 隠れていて見えない」 NG C-30

auto変数とstatic変数の例

#include <stdio.h> int x = 0; void count(){ printf("x=%d¥n", x); x++; } void main(){ count(); count(); count(); } x=0 x=1 x=2 実行結果 グローバル変数は, 強制的にstatic変数. 初期化は, プログラムの開始時に1回. 値はプログラム終了まで 保持される.

auto変数とstatic変数の例

#include <stdio.h> void count(){ int x = 0; printf("x=%d¥n", x); x++; } void main(){ count(); count(); count(); } x=0 x=0 x=0 実行結果 失敗作. 関数に入るたびに, 変数xは作成され, x=0と初期化される. 関数から出るたびに 変数xは消滅する.

(5)

auto変数とstatic変数の例

#include <stdio.h> void count(){ static int x = 0; printf("x=%d¥n", x); x++; } void main(){ count(); count(); count(); } 実行結果 x=0 x=1 x=2 static変数の初期化は, プログラム開始時に 1回だけ. 関数を抜けると, (見えなくなるが) 消滅せず, 値は保持される. C-33

グローバル/ローカル

auto/static

• グローバル変数をautoにすることはできない. auto/staticを選べるのはローカル変数のみ. ローカル変数は(省略時は)自動的にauto変数 になる. • よって,「autoと積極的に記述すること」はほとん ど無い. • ローカル変数をstatic化するために,「static と積極的に記述すること」はある. C-34

グローバル/ローカル

auto/static

• auto/staticは,記憶クラスを指定するもので あり,スコープを指定するものではない. ブロック内で変数宣言. 毎回初期化される. ブロックを抜けて値が消える. ブロック内からのみアクセス可能. 存在しない ブロック内で変数宣言. 初期は最初の1回のみ. ブロックを抜けても値が消えない. ブロック内からのみアクセス可能. 関数の外で変数宣言. 初期は最初の1回のみ. 値は消えない. 全ての関数からアクセス可能. 記憶クラス auto 記憶クラス static グローバル 変数 ローカル 変数 C-35

グローバル/ローカル

auto/static

• グローバル変数は,強制的に「初期化は最初に1 回のみ,値は消えない」となる. • しかし,static付きグローバル変数と, staticなしグローバル変数は意味が異なる. – static付きグローバル変数は,同一ファイル 内からのみアクセス可能. – staticなしグローバル変数は,別ファイルか らもアクセス可能. • 分割コンパイル時に,この違いが意味を持つ. C-36

typedef

• typedefは,既存の型に別名を付けるのに使用 typedef int seisuu;

/*以後「seisuu型」が使える. int型の別名に過ぎない */ int i; seisuu j; C-37

typedefの例

typedef unsigned int uint;

– "unsigned int"に"uint"という別名が付いた. typedef long int int64, lint;

– "long int"に,"int64","lint"という2個の別 名が付いた.

typedef struct hoge sthoge;

– "struct hoge"に,"sthoge"という別名が付い た. C-38

おまけ:巨大なメモリの使用

• 以下のプログラムをコンパイル&実行したら,実 行時にエラーが発生し,強制終了された. #include <stdio.h> void main(){ int data[1000000]; printf("Hello, World!¥n"); } C-39

おまけ:巨大なメモリの使用

• 以下のプログラムをコンパイル&実行したら,正 しく実行された. #include <stdio.h> int data[1000000]; void main(){ printf("Hello, World!¥n"); } C-40

(6)

おまけ:巨大なメモリの使用

• 以下のプログラムをコンパイル&実行したら,正 しく実行された.

#include <stdio.h> void main(){

static int data[1000000]; printf("Hello, World!¥n"); } C-41

練習 0

void main(){ int src[100], dst[100], i; src[0]=…; src[1]=…; src[2]=…; ?? } src[]の100個をdst[]にコピーするには? つまり,src[0]の値をdst[0]にコピー,src[1] の値をdst[1]にコピー,src[2]の値をdst[2] にコピー,src[99]の値をdst[99]にコピー. C-42

参照

関連したドキュメント

実際, クラス C の多様体については, ここでは 詳細には述べないが, 代数 reduction をはじめ類似のいくつかの方法を 組み合わせてその構造を組織的に研究することができる

これはつまり十進法ではなく、一進法を用いて自然数を表記するということである。とは いえ数が大きくなると見にくくなるので、.. 0, 1,

被保険者証等の記号及び番号を記載すること。 なお、記号と番号の間にスペース「・」又は「-」を挿入すること。

LF/HF の変化である。本研究で はキャンプの日数が経過するほど 快眠度指数が上昇し、1日目と4 日目を比較すると 9.3 点の差があ った。

ぼすことになった︒ これらいわゆる新自由主義理論は︑

検討対象は、 RCCV とする。比較する応答結果については、応力に与える影響を概略的 に評価するために適していると考えられる変位とする。

 学年進行による差異については「全てに出席」および「出席重視派」は数ポイント以内の変動で