スライド10

プログラミング演習Ⅱ
第10回
ポインタ(1)
情報・知能工学系
山本一公
[email protected]
前回の課題の解説・ポイント(1)
• 課題8-1
– 例えば、文字列の長さは
void rev_string(char str[])
{
…
int count = 0;
while (str[count]) count++;
…
/* 文字列の長さを得る */
こんな感じで分かるので、
後はstr[i]とstr[count – i – 1]をひっくり返せば良い。
– 文字列の長さはstrlen()でも得られる
前回の課題の解説・ポイント(2)
• 課題8-2
– 例えば、toupper()かtolower()を使って、
大文字か小文字に統一してから比較する
int stricomp(const char str1[], const char str2[])
{
int i = 0;
while (str1[i] != 0 || str2[i] != 0) {
if (toupper(str1[i]) != toupper(str2[i])) {
return 0;
}
i++;
}
return 1;
}
課題7の採点結果から(1)
• 課題7-1
– 「関数型」なのだから、関数と同じように使
えないとダメ
• 繰り返し使えないとダメ
– ブロック化してないとダメ
– 問題を変えない
• もちろん変えたらダメに決まっています
課題7の採点結果から(2)
• 課題7-2
– 行数をカウントする変数の初期化を忘れてい
る
人が多かった
課題7の採点結果から(3)
• 行の途中でEOFが来ることを考慮すると
int ch, count = 0, cnum = 0;
/* count:行数, cnum:処理している行の文字数 */
do {
ch = getchar();
if (cnum == 0) /* 行頭だったら */
if (ch == EOF) break;
else
count++;
if (ch == ‘\n’) cnum = 0; /* 改行で文字数を0に */
else
cnum++;
} while (ch != EOF);
printf(“\nNumber of rows = %d\n”, count);
今日の内容
• 教科書 pp.225~237
• ポインタ
•
•
•
•
•
計算機のメモリモデル
アドレス演算子
ポインタ
間接演算子
ポインタと関数
計算機のメモリモデル
• 変数の考え方
– 箱モデル ⇒ 独立の箱に変数の名前
(int) a
(float) x
floatなので、
4Byte分
– 実際の計算機のメモリ
• 番地(アドレス)と変数名を対応させて記憶
0
a
x
4
8
……
☜ 番地
アドレス演算子
• 変数のアドレスを知りたい!
– アドレス演算子 “&”
• scanf()で使っていたアレ
• 変数の”先頭番地”が値となる
– “&a”は “4”、“&x”は“8”になる
0
a
x
4
8
……
☜ 番地
ポインタ(1)
• アドレスを知ると何の役に立つのか?
– 変数を介さずにアドレスから直接変数を
操作できる!
– 配列や文字列の操作にとても便利
– 関数に副作用を起こさせるためにも便利
• 副作用:呼出し元の変数の値を書きかえる効果
• アドレスを格納する変数 ⇒ ポインタ型
– “*”を付けて宣言する
int *ptr;
ポインタ(2)
• int型のオブジェクト
– 整数(int型)の値を格納する
• intへのポインタ型のオブジェクト
– ≪整数を格納する箱≫の“アドレス”を
格納する
int a, *ptra;
ptra = &a;
/* 変数 a のアドレスをポインタ変数 ptra に代入 */
間接演算子(1)
• ポインタ変数に格納されているアドレス
にはどんな値が入っているか?
– 間接演算子 “*” で値を取り出せる
• 変数宣言と同じ “*”
int a, b, *ptra;
ptra = &a;
/* 変数 a のアドレスをポインタ変数 ptra に代入 */
a = 100;
b = *ptra;
a = 200;
b = *ptra;
/* “*ptra”は“a”と同じなので
b には 100 が入る! */
/* b には 200 が入る! */
間接演算子(2)
• 下の図のような場合
int *x, a, b;
x = &a;
/* 変数 a のアドレス(4)をポインタ変数 x に代入 */
a = 10;
b = *x;
/* “*x”は“a”と同じなので
b には 10 が入る! */
*x
x
4
a
10
b
10
……
0
4
8
☜ 番地
ポインタと関数(1)
• C言語での関数の引数は“値渡し”
– 関数の引数・変数は呼出し側の変数とは独立
⇒ 呼出し側の変数の値は変更されない
• “関数の独立性”という観点からは良いが、
値を変更したいときもある
– ポインタを関数に渡して間接的に変更する!
– 1つの関数から複数の値を返したい場合にも
使える
ポインタと関数(2)
• ポインタでアドレスを渡す
void function(int *b) /* 引数に“*”を付ける */
{
if (*b < 10)
*b = 10; /* bが示すアドレスに 10 を格納 */
}
int main(void)
{
int a;
…
function(&a); /* 関数に a のアドレスを渡す */
/* 関数から戻ってくると、aの値が変わっている */
…
}
ポインタと関数(3)
• 下の図のような場合
– “&a”の値は“4”
– 関数function()の引数“b” には“4”が渡される
• アドレスが“値渡し”される
– “*b”に代入すると、呼び出し元の“a”に
値が入る
*b
0
a
10
b
4
……
4
8
☜ 番地
参照渡し
• 変数の値ではなく変数の参照(変数の場所等、
諸々の属性)を渡すやり方
– C言語にはない。C++言語にはある。
– ポインタ渡しは、“ポインタの値渡し”
• ただし
– C言語におけるポインタ渡しを、
俗に“参照渡し”と呼んでいる
– 本当の意味での“参照渡し”を指しているの か、
俗な言い方での“参照渡し”を指しているのか、
本を読んだりするときに気を付けること
今週の課題
1. main関数の中で、char 型変数 a, b[3]、 short型変
数 c, d[3]、 float型変数 e, f[3]、 double型変数 g,
h[3]を定義し、それぞれのアドレス(配列は各
要素毎)を表示するプログラムを作成せよ。そ
れぞれの変数がメモリ上でどのように配置され
ているか、確認することがこの課題の目的であ
る。
2. p.239、演習10-1のプログラムを作成せよ。
main関数等も作成して、完成したプログラムを
作成すること。
レポートについて
• 電子メールで提出
– 提出先は [email protected]
– Subjectを「プログラミング演習2 課題9提出
号・氏名 」とすること
– C言語ソースファイルを添付する
学籍番
• メールの本文には何も書かなくて良いです
– ソースファイルの頭にコメントで以下の情報を入れる
• 学籍番号・氏名
• プログラムの説明(どのように動くのか、工夫した点等)
• 実行結果(長い場合は一部)を貼る
– 提出締切は、1月16日(水) 12:00 (1週間後)
授業用Webサイト
• URL:
http://www.slp.cs.tut.ac.jp/~kyama/programming2/
– 課題のpdfファイルが置いてあります。
– 授業で使ったpptファイルを置いていきます。
• 質問メールは、以下のどちらかのアドレスまで
– [email protected][email protected]
• C-515へ直接質問しに来ても構いません