前回の講義資料

プログラミング演習II
2004年11月 2日(第3回)
理学部数学科・木村巌
前回までの復習





関数の宣言
複数のファイルからなるプログラム
複数のファイルからなるプログラムでのス
コープ
標準ライブラリ関数とは何か
標準ライブラリ関数の使い方
今日学ぶこと






メモリとアドレス
ポインタ変数
アドレス演算子 &, 間接参照演算子 *
ポインタを引数とすることで、呼び出し元の実
引数を変更できる
constを仮引数に付けることで、実引数の変更
を抑制できる
教科書9.1から(p. 272~)
アドレスって?



変数の値は、コンピュータの「メモリ」に記憶さ
れる
メモリには、16進表記で通し番号が振られて
いる
この通し番号を、アドレス(address)という
変数のアドレスを見る


変数が格納されているメモリのアドレスをしる
には、アドレス演算子&を使う
アドレス演算子の使い方
&変数名


例えば、aがint型の変数なら、そのアドレスは
&a で知ることが出来る
アドレスを端末に表示するには、%p 書式指
定子を使う(Sample1.cを打ち込んで、コンパ
イル・実行してみよう)
アドレスは、メモリ上の位置



アドレス演算子を使うと、変数aの値が、メモリ
上のどの位置に記憶されているか、が分かる
Sample1.cで、さらにint型の変数b, cを追加し、
それらのアドレスも表示させてみよ。
気がつくことがあるか?
ポインタ



アドレスを格納する変数を、ポインタ型の変
数という
ポインタ型の変数の事を、単にポインタという
ことも多い
ポインタ型の変数の使い方は、これまで学ん
できた、他の型の変数と同じ
ポインタの宣言



型名 *ポインタ変数名;
ポインタ変数であることが分かるような名前を
付けることも多い
例:
int *pA;
int *Aptr; /* どちらもint型へのポインタ */


変数名はあくまでpAとAptr
Sample2.cを入力し、コンパイル・実行してみ
よう
ポインタ変数にアドレスを代入




Sample2.cの
pA = &a;
という行は、ポインタ変数pAに、int型の変数a
のアドレスを代入している
pAには、例えば0x22ef3c といった値が入る
「pAはaを指すポインタ」などという
ポインタから変数の値を知る


ポインタ変数の値(つまり、別の変数のアドレ
ス)から、元の変数の値を知ることが出来る
間接参照演算子*をつかう
*ポインタ変数名;


例:pAがint型の変数aのアドレスを格納した
ポインタ変数なら、aの値は、
*pA /* これはint型 */
Sapmle3.cを入力し、コンパイル・実行してみ
よう
ポインタについて整理する
a
変数a
&a
変数aのアドレス
変数aのアドレスを格納したポインタ変
数
*pA 変数aのアドレスを格納したポインタ変
数が指している変数 == 変数a
pA
ポインタに別のアドレスを代入する




ポインタ変数とは、アドレスを格納する変数
普通の変数と同じく、プログラムの途中で、ポ
インタ変数の値を変更することが出来る
ただし、int型を指すポインタ変数には、int型
の変数のアドレスしか格納できない
Sample4.cを入力し、コンパイル・実行してみ
よう
初期化されていないポインタ変数



ポインタ変数は、宣言しただけでは使えない
特定の変数のアドレスを代入し、初期化しな
ければならない
初期化していないポインタ変数を使うと、ゴミ
が表示されたり、実行時エラーになったりする
(どのような挙動を示すかは、予言できない
ポインタを使って変数を変更



Sample5.cを入力し、コンパイル・実行してみ
よう
pAがint型を指すポインタ変数の時、*pAはint
型.よって、*pA = 50; のように、代入できる
この仕組みを使って、関数に引数を渡すと、
面白い応用がある
引数とポインタ


int型の2つの値を交
換する関数void
swap (int x, int y)を
書きたい
→は思った通りには
動かない
void swap (int x, int y)
{
int tmp;
tmp = x;
x = y;
y = tmp;
}
なぜ前のswap()は動かないのか?




Sample6.cを入力し、コンパイル・実行してみ
よう→思ったように値が交換されない
関数の引数には、変数の値のコピーが渡さ
れる
これを、値渡し(pass by value)とか、値呼び
(call by value)とかいう
コピーを交換しても、元の変数には影響が及
ばない
ポインタを使って解決



仮引数をポインタ変 void
数とする
swap (int *pX, int *pY)
{
→参照
int tmp;
Sample7.cを入力し、
tmp = *pX;
コンパイル・実行して
*pX
=
*pY;
みよう
*pX = tmp;
}
ポインタを使って解決(続)



前のスライドをswap()を使う。
引数として、&num1, &num2のように、変数の
アドレスを渡す
仮引数は、&num1と&num2で初期化される




pX = &num1; pY = &num2;
*pX = num1; *pY = num2;
これらが入れ替えられると、num1, num2その
ものが入れ替えられる
参照渡し(pass by reference)
実引数を変更したくない場合



constという指定で、ポインタがさす実引数を
変更できなくなる
void func (const int *pX); というプロトタイプ宣
言をみると、この関数はpXが指す変数を変
更しないことがわかる
同時に、func()を作成する際に、誤ってpXが
指す変数を変更してしまっても、コンパイラが
その誤りを指摘してくれる
今日学んだこと





メモリとアドレス
ポインタ変数
アドレス演算子 &, 間接参照演算子 *
ポインタを引数とすることで、呼び出し元の実
引数を変更できる
constを仮引数に付けることで、実引数の変更
を抑制できる
レポート課題


void mod (int *pA, int *pM) というプロトタイ
プを持つ関数mod()は、*pAを (*pA) %
(*pM)に置き換える.キーボードからint型の
値aとmを入力し、次のように出力するプログ
ラムを作成せよ:
ヒントは教科書p. 298の練習問題3.
レポート課題(続)
input a and m:
7 (ユーザの入力)
5 (ユーザの入力)
7 modulo 5 = 2 modulo 5.
レポート課題(続)



締め切り:2004年11月8日一杯(日本時間で)
提出:メールで木村([email protected])まで.
感想などあると木村が喜びます