Comments
Description
Transcript
Outline ポインタの基本(復習) ミニテスト(問1)
http://apple.ee.uec.ac.jp/isyslab http://apple.ee.uec.ac.jp/isyslab Outline 先週の復習 基礎プログラミングおよび演習 第11回 ポインタの基本 ポインタその2 on 2010.01.20 課題の復習 配列とポインタ 電気通信大学大学院電子工学専攻 電子知能システム学講座 長井隆行 本日の演習課題 2 http://apple.ee.uec.ac.jp/isyslab http://apple.ee.uec.ac.jp/isyslab ポインタの基本(復習) ミニテスト(問1) 変数に&演算子を適用すると、その変数のアド レス(メモリの番地)が取得できる #include<stdio.h> int main(void) { int x = 2; int y = 4; int* p_x; ⇒このアドレスのことを、その変数へのポインタと呼ぶ ポインタ変数hoge_pが別の変数hogeのポインタ を保持しているとき、hoge_pがhogeを指している という ポインタに*演算子を適用すると、そのポインタ の指している先を表すようになる p_x = &y; *p_x = *p_x + x +y; p_x = &x; *p_x = *p_x + x + y; /*変数の宣言*/ /*変数の宣言*/ /*ポインタ変数の宣言*/ /*アドレスをポインタ変数に代入*/ printf("results are %d and %d¥n", x, y); return 0; } ⇒ hoge_pがhogeを指しているなら、*hoge_pとhogeは同 じものを表す p11-1.c 結果がどうなるか頭で考える! 3 4 http://apple.ee.uec.ac.jp/isyslab http://apple.ee.uec.ac.jp/isyslab 前回の課題の復習 アドレス渡し補足 ポインタと関数における引数の両方を理解していないとい けない #include<stdio.h> アドレス渡しで、実引数はアドレス(&x)で仮 引数は値(*x)なのがなぜか? 単純にアドレスを代入する場面を考えてみる void swap(int* x, int* y) { int tmp; void swap(int* x, int* y); int main(void) { int x, y; int x; int* px; x=10; px = &x; tmp = *x; *x = *y; *y = tmp; x = 5; y = 10; } swap( &x, &y ); なぜここがこうなるのか? 箱x(型はint) main func(&x) p11-2.c } 5 http://apple.ee.uec.ac.jp/isyslab } add 10 funcのローカル変数 func( int* x ) { } 箱x(型はint*) add コピーされる 6 http://apple.ee.uec.ac.jp/isyslab 箱を考える x = 5; y = 10; 箱を用意して積め! mainのローカル変数 関数になっていても同じ { printf(“x=%d, y=%d¥n”, x, y); return 0; int x,y; これは、int* に & intがコピーされる形になっている オ tmp 空 エ y イ エ y イ ウ x ア ウ x ア メイン関数で2つの変数x,yを用意する それらに適当な値を代入する(x,yの型に イ y空 イ y 10 イ y 10 イ y 10 ア x空 ア x5 ア x5 ア x5 *y = tmp; *x = *y; tmp = *x; ミニテスト(問2) int tmp; swap(&x, &y); オ tmp 5 オ tmp 5 オ tmp 5 エ yイ エ y イ エ y イ ウ xア ウ x ア ウ x ア イ y 10 イ y 10 イ y5 ア x5 ア x 10 ア x 10 ここの値を入れ替えたい! 7 注意) 値を2つ受取ってそれらの和と積を計算す る関数を作る 結果をメインで受け取るにはどうすればよ いか? 8 http://apple.ee.uec.ac.jp/isyslab http://apple.ee.uec.ac.jp/isyslab ミニテスト(問2) 続き ミニテスト(問2) 解答例 void waseki( { #include<stdio.h> void waseki( #include<stdio.h> ) void waseki(double x, double y, double* p_wa, double* p_seki); ); int main(void) { double x, y; double wa, seki; /*値は何でもよい*/ /*値は何でもよい*/ waseki( *p_wa = x + y; *p_seki = x*y; int main(void) { double x, y; double wa, seki; } x = 2; y = 3; x = 2; y = 3; p11-3.c ); void waseki(double x, double y, double* p_wa, double* p_seki) { } 答えをしまって欲しい 箱の場所を関数に渡している waseki( x, y, &wa, &seki ); printf(“wa=%f, seki=%f¥n”, wa, seki); return 0; printf(“wa=%f, seki=%f¥n”, wa, seki); return 0; } 9 http://apple.ee.uec.ac.jp/isyslab } 10 http://apple.ee.uec.ac.jp/isyslab 配列とポインタ つまり・・・ hoge[0]のアドレスは&hoge[0] 山田さんの隣の家とか隣の隣ということが よって、&hoge[0] ⇒ 0x10000000 できる! 配列の小箱はアドレスの順番に並んでい ることがポイント ここで、&hoge[0]を hogeと書くことができる *hoge は hoge[0] *(hoge+1) は hoge[1] *(hoge+2) は hoge[2] を意味する 注)hogeはint型で4バイトなので、*(hoge+1)の+1はアドレスを4バイト 先に進めることを意味します 11 12 http://apple.ee.uec.ac.jp/isyslab http://apple.ee.uec.ac.jp/isyslab ポインタの演算 ちょっと余談ではありますが・・・ ポインタ(アドレス)を足したり引いたり(演算) して、 配列の位置を指定することができる。 ポインタの演算 配列の添え字はポインタ演算で置き換えられる hoge[5] *(hoge+5) 昔は、ポインタ演算で書いた方が早かった C言語っぽい感じがする(玄人っぽい) 読みにくくなる場合は使うべきではない p[i]とi[p]は全く同じ!? #include<stdio.h> int main(void) 証明 { p[i]と*(p+i)は同じですね(配列とポインタ演算の関係)。 int i=0; tnagai@golf-1[20]_% gcc -o irekae irekae.c int p[10]={1,2,3,4,5,6,7,8,9,10}; ということは、加算は入れ替え可能ですから tnagai@golf-1[21]_% ./irekae *(p+i) = *(i+p) p[0] = 1, 0[p]=1 for(i=0; i<10; i++) p[1] = 2, 1[p]=2 { ということになります。 p[2] = 3, 2[p]=3 printf("p[%d] = %d, %d[p]=%d¥n",i,p[i],i,i[p]); これをまた配列とポインタ演算の関係で戻すと p[3] = 4, 3[p]=4 } p[4] = 5, 4[p]=5 return 0; *(i+p)とi[p]は同じになります p[5] = 6, 5[p]=6 } で結局p[i]=i[p]とあいなります。 p[6] = 7, 6[p]=7 p[7] = 8, 7[p]=8 あら不思議・・・ p[8] = 9, 8[p]=9 p[9] = 10, 9[p]=10 tnagai@golf-1[22]_% 13 http://apple.ee.uec.ac.jp/isyslab 14 http://apple.ee.uec.ac.jp/isyslab ミニテスト(問3) ミニテスト(問3) 続き void waseki( { メイン関数で配列xを用意する #include<stdio.h> それらに適当な値を代入する(xの型とサイ void waseki( ズに注意) 配列の全ての値を受取ってそれらの和と 積を計算する関数を作る 結果をメインで受け取るにはどうすればよ いか? int main(void) { double x[5]={1,5,3,6,2}; /*値は何でもよい*/ double wa, seki; waseki( ) ); ); } p11-4.c printf(“wa=%f, seki=%f¥n”, wa, seki); return 0; } 15 16 http://apple.ee.uec.ac.jp/isyslab http://apple.ee.uec.ac.jp/isyslab 本日の演習 ミニテスト(問3) 解答例 #include<stdio.h> void waseki(double* p_x, double* p_wa, double* p_seki); int main(void) { double x[5]={1,5,3,6,2}; /*値は何でもよい*/ double wa, seki; void waseki(double* p_x, double* p_wa, double* p_seki) { int i = 0; *p_wa = 0; *p_seki = 1; } printf(“wa=%f, seki=%f¥n”, wa, seki); return 0; } *p_wa = *p_wa + *(p_x+i); *p_seki = *p_seki * *(p_x+i); でもよい 17 http://apple.ee.uec.ac.jp/isyslab 修正前のソースコード(p11-5.c) #include<stdio.h> int main(void) { int i; /*データ*/ double kion[31] = {32.3, 32.0, 32.6, 31.1, 34.9, 36.5, 23.4, 20.9, double sum, heikin; sum = 0.0; for(i=0; i<31; i++) { sum = sum + kion[i]; } heikin = sum/31.0; printf(“heikin : %f¥n”, heikin); return 0; } ー課題ー (ここから先をメールで送る) p11-5.cの平均値計算の部分を関数にする for(i=0; i<5; i++) { *p_wa = *p_wa + p_x[i]; *p_seki = *p_seki * p_x[i]; } waseki( x, &wa, &seki ); ー準備ー まずは、p11-5.cをHPよりダウンロードする コンパイル、実行して正しく動作することを確認する 32.3, 33.6, 31.3, 33.2, 32.1, 31.9, 33.0, 32.6, 33.5, 34.7, 28.5, 30.3, 31.0, 35.1, 29.8, 29.8, 23.8, 31.7, 27.9, 29.2, 28.3, 29.7, 34.4}; /*sum += kion[i];でもよい*/ 19 気温のデータをポインタを使って関数に渡す必要がある 平均値を計算してメイン関数に戻す(アドレス渡しでもよい) ソースコードと実行結果をメールで送る 送る際には注意事項をよく確認すること 今日の講義の感想・質問をメール本文に書いてください よく分かった、ここが分からない、など コメントは楽しいのがgood 今日の課題は今日締め切り 18