CPUとメモリ メモリ CPU 32bit 演算部 整数 レジスタ 64bit 小数レジスタ アドレスバス データバス 書き込み 読み出し アドレス 0000 0001 0002 0003 ・ ・ ・ 8bit データの配置 int (32bit = 4byte) メモリ 8bit アドレス ・ 0120 0121 変数a 0122 ・ ・ ・ 変数b double (64bit = 8byte) メモリ •メモリは8bit=1byteを 単位に,格納する情報 8bit アドレス の大きさに合わせて使 用される ・ 0120 •読み書きは,各領域 0121 をひとまとめにして扱う 0122 ・ 変数r 左の例: ・ •int a, b; とした場合 ・ a は 0120 - 0123 b は 0124 - 0127 •double r; とした場合 r は 0120 - 0127 アドレス ・ 0262 0263 0264 ・ ・ ・ 8bit 配列型 •配列はメモリ中に順に確保される 左の例: a[0] •int a[3]; として配列を定義した場合 確保される領域は全部で 12byte a[x] は 0262 + (x * 4) から始まる 4byte a[1] •double d[10] のようにした場合 確保される領域は全部で 80byte d[x] は 0262 + (x * 8) から始まる 8byte a[2] アドレス ・ 0262 0263 0264 0265 0266 ・ ・ 8bit コンパイラの動作 main() { int a, b[2]; •「0262」に 10 を入れる a a = 10; コンパイル b[0] = 20; b[1] = b[0] + a; } b[0] ・メモリを 12byte 確保 (開始位置:0262) •「0266+0*4」に 20 を入れる •「0266+0*4」と「0262」の和 を計算し,その結果を 「0266+1*4」に入れる ここでは,「x」は x から始まる4byteであるとする b[1] コンパイラの動作 •変数に必要なメモリの総量を計算する •各変数名に実際のアドレスを対応づける •数式を,アドレスを用いた手順に変換する メモリのアクセス 変数のアクセスに必要な情報 • 読み書きすべき変数は,どのアドレスから始ま るか • 変数が格納されている大きさは,いくらか コンパイラの役目・利点 • アドレスを手計算しなくてよい • 変数の大きさの代わりに型(int, double など) を用いるので,間違いにくい.また,大きさの 食い違いをチェックしてくれる アドレス ・ 0262 0263 0264 0265 0266 ・ ・ 8bit a ポインタの発想 main() { int a, b[2]; ・・・ } コンパイラが管理する情報の利用 •変数 a の開始位置(アドレス)を 知りたい •アドレスを用いてメモリ操作したい b[0] b[1] コンパイラが 管理する情報 •変数 a 開始:0262 大きさ:4 操作単位:4 •変数 b 開始:0266 大きさ:8 操作単位:4 など 開始位置:変数名に対応 大きさ:sizeof(..) で取得可能 操作単位:型に対応 アドレス ・ 0262 0263 0264 0265 0266 ・ ・ 8bit a b[0] b[1] ポインタ main() { int a, b[2]; ・・・ } コンパイラが 管理する情報 •変数 a 開始:0262 大きさ:4 操作単位:4 •変数 b 開始:0266 大きさ:8 操作単位:4 & : 変数名からのアドレス取得 &a は 0262 となる &(b[0]) は 0266 となる * : アドレスによるメモリアクセス *(0262) で変数 a へアクセス できるか? →操作単位の情報が必要 ポインタ変数とポインタの型 ・ 0262 0263 0264 0265 0266 ・ ・ a b p main() { int a, b, *p; a = 10; p = &a; b = *p; *p = 20; } 1. 2. 3. 4. /* /* /* /* 1 2 3 4 */ */ */ */ p は int 型の ポインタ変数 •p には int の変数の アドレスを代入する 事が出来る •*p で,p に格納され ているアドレスから, int の大きさで アクセスできる a に 10 が入る p に 262 が入る b に a の値(10)が入る a に 20 が入る int a; int *p; p = &a; の解釈 型と文法 p はint変数へのポインタ a はint変数 int *p; p = &a; * はポインタの前に付けると, そのポインタが指す値を意味 する.つまり,int 型 & は変数の前に付けると, その型へのポインタを意味する. つまり,int 型へのポインタ 両辺は「int型」 両辺は「int型へのポインタ」 右辺と左辺の釣り合いが取れていなければならない. int 型 a *p int 型へのポインタ &a p 関数とポインタ a void change(int *x) { *x = 100; } int main() { int a = 10; x change(&a); } •a に格納された値ではなく,変数 a のポインタ(アドレ ス)を関数 change へ伝える事で,変数 a の内容を書 き換える事が出来る(関数から値を返す事が出来る) ポインタと配列 int main() { int a[2] = {10, 20}; int *y = a; a[0] *a a[1] *(a+1) y y[0] = 100; *(y+1) = 200; *a = 1000; *(a+1) = 2000; y[1] *(y+1) y[0] } *y •ポインタ変数への加算はアドレスへの 加算ではなく,操作単位(型の大きさ)を 乗じた値の加算となる •ポインタは配列として,また逆に配列は ポインタとして使う事が出来る •a[0] と *a は等価 •a[1] と *(a+1)は等価 ポインタの応用例 int spacecnt(char *p) { int cnt = 0; for( ; *p != ‘¥0’; p++) if(*p == ‘ ‘) { cnt++; } } return cnt; } • 渡された文字列の スペースの個数を 数えて返す関数 { • p++ で,文字列の 次の要素へ処理対 象を移動する Malloc() と free() int *p; p = (int *)malloc(100 * sizeof(int)); *p = 100; p[99] = 200; free(p); • 必要なときに必要なだけメモリを確保する – 大きさの計算に注意(sizeof() を使う事) – 型の変換(キャスト)をきちんとするのが望ましい • 使い終わったら解放(free)する – 解放しなければどんどんメモリが浪費される 構造体 struct foo { int a; double d; }; •x は大きさ 12byte コンパイル x.a struct foo x; x •メンバ d は大きさ 8byte で, 開始位置は x の先頭から 4 •x の型は struct foo 型 (foo はタグ名という) •x.a の型は int x.d •メンバ a は大きさ 4byte で, 開始位置は x の先頭から 0 •x.d の型は double 構造体の利点 配列に対する利点 • 様々な型をひとまとめに出来る • 丸ごとコピーできる struct hoge a, b; a = b; 読みやすさ,書きやすさ • 各要素に意味のある名前を付ける事が出来る • 構造体の宣言は,タグ名により再利用できる 構造体の作り方・使い方 struct st1 { int a, b; } struct st2 { struct st1 s; double c[3]; } struct st1 x; struct st2 y; x.a =10; y.c[0] = 10.5; y.s = x; y.s.b = 20; 作り方(宣言と定義) • 構造体を入れることが可能 • 配列を入れることも可能 • タグ名を用いていくつでも同じ型 の構造体を作る事が可能 使い方 • メンバへアクセスする演算子.は, 続けて使う事が出来る 構造体へのポインタ struct st1 { int a, b; } struct st1 x; struct st1 *y; y = &x; (*y).a = 100; y->b = 200; 構造体を指すポインタが使える • 演算子*の優先順位は.や[] より低いことに注意! • 構造体へのポインタを専門に 扱う演算子->が用意されてい る m->n は (*m).n と等価 複雑な変数定義 • int *a[3]; int *(a[3]) と同じ 「a は要素数 3 の配列で,その配 列の各要素はint へのポインタ」 • int (*b)[3]; 「b はポインタで,そのポインタが指 す先は要素数 3 の配列.その配列 の各要素は int」 • struct list { int data; struct list *p1, *p2; } x; 「x は int 型の領域 data と,自分 自身と同じ型の構造体を指すポイ ンタpをメンバに持つ構造体」 a[0] a[1] a[2] int int int int int int b data p1 p2 色を塗ってある 部分が実際に確 保されるメモリ data p1 p2 data p1 p2 data p1 p2 data p1 p2
© Copyright 2024 ExpyDoc