Comments
Description
Transcript
演習Ⅱ 第三週 デバッグとポインタ
演習Ⅱ 第三週 デバッグとポインタ 担当 榎並 (9)デバッグ 今日覚えること デバ グ デバッグ5つの基本 基本 デバッグの基本その① インデントをつける イ デ トを ける サンプルプログラム: 文字列“hi there” を縦に表示. (各文字ごとに改行する.) 各 ご #include <stdio.h> i main(){ int i (){ char str[]="hi there"; while(str[i]!= ¥n ){ while(str[i]!='¥n'){ putchar(str[i]); putchar('¥n') } return 0; } デバッグの基本その① イ デ トを ける インデントをつける #include <stdio.h> int main() { char str[]="hi there"; while(str[i]! ¥n ) while(str[i]!='¥n') { putchar(str[i]); putchar('¥n') } return 0; return 0; } デバッグの基本その② エラー(ワーニング)メッセージを読む ( グ)メ セ ジを読む % gcc –Wall –o hithere % W ll hi h hi h hithere.c hithere.c: In function `main': hithere c:4: error: `i'i undeclared (first use hithere.c:4: error: undeclared (first use in this function) hithere.c:4: error: (Each undeclared identifier is reported only once (中略) hith hithere.c:7: error: parse error before '}' 7 b f '}' token デバッグの基本その③ プ グ ムを読む プログラムを読む #include <stdio.h> #include <stdio.h> int main() { char str[]="hi there"; int i; while(str[i]!='¥n') hil ( t [i]! '¥ ') { putchar(str[i]); putchar('¥n'); } return 0; } デバッグの基本その④ プ グ ム 進行状態を把握 プログラムの進行状態を把握 #include <stdio.h> #include <stdio.h> int main() { char str[]="hi there"; int i; while(str[i]!='¥n') hil ( t [i]! '¥ ') { putchar(str[i]); putchar('¥n'); } return 0; } デバッグの基本その⑤ 変数 値を確認 変数の値を確認 #include <stdio.h> int main() { char str[]="hi there"; int i;; printf("%s¥n", str); printf("%d¥n", i); while(str[i]!='¥n') hil ( [i]! ' ') { putchar(str[i]); putchar('¥n'); } return 0; } サンプルプログラム 演習 ( 演習2(1~4週)のページからhithere.c 週) ペ ジから をダウ をダウンロード. ド #include <stdio.h> int main(){ char str[]="hi char str[]= hi there there";; while(str[i]!='¥n'){ putchar(str[i]); putchar('¥n') } return 0; } 練習 インデント プログラムを読む コンパイル デバッグ デ ッグ 実行 printf 文挿入 gdb の使い方 % gcc % gcc ‐g hithere2.c g hithere2 c # デバッグ情報を付与 # デバッグ情報を付与 % gdb a.out # gdb 起動 ... (gdb) break main (gdb) run (gdb) next (gdb) [return で直前のコマンドの繰り返し] gdb 基本コマンド(よく用いられるコマンドのみ) (gdb) break ○○○ (gdb) run (gdb) next (gdb) next (gdb) step (gdb) print □□□ (gdb) print □□□ (gdb) list ○○○ (gdb) kill ( db) it (gdb) quit (gdb) help △△△ # ブレイクポイント設定(○○○:例えば関数名) # プログラム実行 # 一行進む(関数の内部では停止しない) # 行進む(関数の内部では停止しない) # 一行進む # (関数呼び出しの際、関数の先頭行で停止) # 変数の値を表示(□□□:変数名) # 変数の値を表示(□□□:変数名) # ソース表示 # プログラム終了 # db 終了 # gdb # ヘルプ(△△△:コマンド名) gdb の練習 一行ずつhithere.c 行ず を実行し みよう を実行してみよう (10)ポインタの基本 ポインタ操作とは 主記憶(メインメモリ)のアドレスを意識した操作. 主記憶(メイ メ リ) ド を意識した操作 プログラミングの初学者には理解しにくいとされる. 主記憶の動作がわかっていれば理解はさほど困難ではない. が ば 変数名 割当番地 data1 1000 data2 2000 変数とポインタの違い 変数 このアドレスは変更できない アドレス割り当てはコンパイラが行う 変数aa 1000番地 1000 123 このデータは 変更出来る 変数テーブル ポインタ ポインタpt このアドレスは変更出来る 1000 1000番地 123 このデータは ポインタは間接指示で 変更することができる 参照呼び出し x p a b a ,b にはデータの値が記憶される. *p=a+b: p にはアドレスが記憶される. a の内容とb の内容とを足して,変数 p が示すアドレスの位置に代入 a+b 主記憶をアドレス記憶部として利用 するか デ タ記憶部と するか,データ記憶部として利用する. 利 する 主記憶には固有のアドレスが存在し、 そこにデ タが存格納される そこにデータが存格納される. ポインタ変数 主記憶 書き込むデ タとし 主記憶へ書き込むデータとしてアドレスを使う. ド を使う ポインタ変数と呼ぶ 宣言 int a; int *b; a 整数など普通のデータ b アドレス b はポインタなので* を付ける. b にはアドレスしか書き込まれない. b にはアドレスしか書き込まれない ポインタ変数と通常の変数の比較 float a1, b1; , ; float *a2, *b2; 両者の扱われ方の違いに注意! a1 a1 は通常の変数なので a2 a1 : a1 の中身 &a1 : a1 の存在場所(アドレス) a2 はポインタ変数なので a2 : a2 の中身(アドレス) *a2 : a2 の中身が示す場所のデータ ポインタ操作の例 int a=100; int *b; b=&a; bにaのアドレスを代入 これで*bとaは同じ 名前 アドレス ア 内容 a 19453 100 b 29435 ポインタ操作の例 int a=100; int *b; b=&a; bにaのアドレスを代入 これで*bとaは同じ 名前 アドレス ア 内容 a 19453 100 b 29435 19453 関数の値渡し 呼び出された関数は引数用の領域を確保して呼び出し び 数 数 確保 び 側の値を代入 void changeX(int x, int y) { x=y; } a=0; b=4; changeX(a,b); x 0 → → 4 y 4 a 0 b 4 関数の値渡し 呼び出された関数は引数用の領域を確保して呼び出し び 数 数 確保 び 側の値を代入 void changeX(int x, int y) { x=y; } a=0; b=4; changeX(a,b); x y a 0 → 4 b 4 ポインタと配列 これまでに学習した配列では,x[0],x[1],…,x[5] のように れま に学習した配列 は ように 添え字で要素を指定した。 x[0] x[1] x[2] x[3] x[4] x[5] *p *(p+1) *(p+2) int *p; p=x あるいはp=&x[0]によってp にx の先頭アドレスを セットできる. ポインタと文字列 ポインタの文字列初期化 char s[4] = “ABC”; char *p=“XYZ”; S[0] S[1] S[2] S[3] 配列 S A B C ¥0 ポインタp 先頭 番地 X Y Z ¥0 メモリ上のどこか ポインタと文字列 ポインタの文字列設定 strcpy(s, ”123”); p=“789”; S[0] S[1] S[2] S[3] 配列 S ポインタp 1 2 3 ¥0 先頭 番地 7 8 9 ¥0 メモリ上のどこか ポインタの配列 ポインタは配列にすることができる char *pp[10]; 今までは char namev[3][10] = { “January”, “February”, “February” “March” } ポインタ配列では char *namep[3] = { “January”, “February”, March “March” }