演習Ⅱ 第三週 デバッグとポインタ

演習Ⅱ
第三週 デバッグとポインタ
担当 榎並
(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”
}