プログラミングI第6回

Similar documents
プログラミングI第5回

プログラミングI第11回

プログラミングI第10回

Taro-ファイル処理(公開版).jtd

02: 変数と標準入出力

02: 変数と標準入出力

gengo1-11

バイオプログラミング第 1 榊原康文 佐藤健吾 慶應義塾大学理工学部生命情報学科

PowerPoint プレゼンテーション

Prog1_10th

PowerPoint プレゼンテーション

情報処理Ⅰ演習

Microsoft PowerPoint - 計算機言語 第7回.ppt

02: 変数と標準入出力

Microsoft PowerPoint - 5Chap15.ppt

プログラミング実習I

02: 変数と標準入出力

memo

02: 変数と標準入出力

< F2D837C E95CF CF68A4A94C5816A2E6A>

6 関数 6-1 関数とは少し長いプログラムを作るようになると 同じ処理を何度も行う場面が出てくる そのたびに処 理を書いていたのでは明らかに無駄であるし プログラム全体の見通しも悪くなる そこで登場す るのが 関数 である 関数を使うことを 関数を呼び出す ともいう どのように使うのか 実際に見て

7 ポインタ (P.61) ポインタを使うと, メモリ上のデータを直接操作することができる. 例えばデータの変更 やコピーなどが簡単にできる. また処理が高速になる. 7.1 ポインタの概念 変数を次のように宣言すると, int num; メモリにその領域が確保される. 仮にその開始のアドレスを 1

第1回 プログラミング演習3 センサーアプリケーション

メソッドのまとめ

コマンドラインから受け取った文字列の大文字と小文字を変換するプログラムを作成せよ 入力は 1 バイトの表示文字とし アルファベット文字以外は変換しない 1. #include <stdio.h> 2. #include <ctype.h> /*troupper,islower,isupper,tol

C プログラミング演習 1( 再 ) 2 講義では C プログラミングの基本を学び 演習では やや実践的なプログラミングを通して学ぶ

Microsoft PowerPoint - prog06.ppt

02: 変数と標準入出力

gengo1-12

2006年10月5日(木)実施

プログラミング演習3 - Cプログラミング -

02: 変数と標準入出力

Microsoft PowerPoint - 09.pptx

Microsoft Word - no202.docx

C言語講座 ~ファイル入出力編~

PowerPoint プレゼンテーション - 物理学情報処理演習

Microsoft PowerPoint - prog07.ppt

PowerPoint Presentation

プログラミング演習3 - Cプログラミング -

Prog1_12th

Microsoft Word - no103.docx

Microsoft Word - Cプログラミング演習(12)

gengo1-12

Microsoft PowerPoint - lec10.ppt

PowerPoint プレゼンテーション

プログラミング入門1

/*Source.cpp*/ #include<stdio.h> //printf はここでインクルードして初めて使えるようになる // ここで関数 average を定義 3 つの整数の平均値を返す double 型の関数です double average(int a,int b,int c){

(1) プログラムの開始場所はいつでも main( ) メソッドから始まる 順番に実行され add( a,b) が実行される これは メソッドを呼び出す ともいう (2)add( ) メソッドに実行が移る この際 add( ) メソッド呼び出し時の a と b の値がそれぞれ add( ) メソッド

今までの復習 プログラムで最低限必要なもの 入力 ( キーボードから ファイルから ) 出力 ( 画面へ ファイルへ ) 条件分岐 : 条件の成立 不成立により 異なる動作をする 繰り返し : 一定の回数の繰返し 条件成立の間の繰返し 関数の定義 関数の呼び出し C ではそれ以外に ポインタ データ

<4D F736F F D20438CBE8CEA8D758DC03389F0939A82C282AB2E646F63>

Microsoft PowerPoint - CproNt02.ppt [互換モード]

Microsoft PowerPoint - exp2-02_intro.ppt [互換モード]

Microsoft Word - no11.docx

RX ファミリ用 C/C++ コンパイラ V.1.00 Release 02 ご使用上のお願い RX ファミリ用 C/C++ コンパイラの使用上の注意事項 4 件を連絡します #pragma option 使用時の 1 または 2 バイトの整数型の関数戻り値に関する注意事項 (RXC#012) 共用

ファイル入出力

Microsoft PowerPoint - 11.pptx

Microsoft PowerPoint pptx

PowerPoint Presentation

Microsoft PowerPoint ppt

memo

演算増幅器

gengo1-12

slide5.pptx

Microsoft PowerPoint - 第3回目.ppt [互換モード]

PowerPoint プレゼンテーション

Microsoft PowerPoint - prog03.ppt

PowerPoint プレゼンテーション

memo

また 初期化について 以下のサンプルコードのように指定すれば 定義時に値を代入できます * オマケ配列は同名で複数個の箱を用意出来ます 同名ではありますが それぞれは別々の個体であるわけです また この複数個の変数は メモリ上に連続で確保されます 2. 文字と文字列 C 言語では文字と文字列は異なる

今回のプログラミングの課題 ( 前回の課題で取り上げた )data.txt の要素をソートして sorted.txt というファイルに書出す ソート (sort) とは : 数の場合 小さいものから大きなもの ( 昇順 ) もしくは 大きなものから小さなもの ( 降順 ) になるよう 並び替えること

PowerPoint プレゼンテーション

ソフトウェア基礎 Ⅰ Report#2 提出日 : 2009 年 8 月 11 日 所属 : 工学部情報工学科 学籍番号 : K 氏名 : 當銘孔太

Microsoft PowerPoint - prog08.ppt

ファイル入出力

Taro-ポインタ変数Ⅰ(公開版).j

ポインタ変数

memo

Microsoft Word - Cプログラミング演習(11)

02: 変数と標準入出力

Prog1_6th

Microsoft PowerPoint - prog04.ppt

プログラミング入門1

02: 変数と標準入出力

文字列 2 前回の授業ではコンピュータ内部での文字の取り扱い 文字型の変数 文字型変数への代入方法などを学習した 今回は 前回に引き続き 文字処理を学習する 内容は 標準入出力 ( キーボード ディスプレイ ) での文字処理 文字のファイル処理 文字を取り扱うライブラリ関数である 標準入出力 Lin

PowerPoint プレゼンテーション

関数の呼び出し ( 選択ソート ) 選択ソートのプログラム (findminvalue, findandreplace ができているとする ) #include <stdiu.h> #define InFile "data.txt" #define OutFile "surted.txt" #def

FORTRAN( と C) によるプログラミング 5 ファイル入出力 ここではファイルからデータを読みこんだり ファイルにデータを書き出したりするプログラムを作成してみます はじめに テキスト形式で書かれたデータファイルに書かれているデータを読みこんで配列に代入し 標準出力に書き出すプログラムを作り

4 月 東京都立蔵前工業高等学校平成 30 年度教科 ( 工業 ) 科目 ( プログラミング技術 ) 年間授業計画 教科 :( 工業 ) 科目 :( プログラミング技術 ) 単位数 : 2 単位 対象学年組 :( 第 3 学年電気科 ) 教科担当者 :( 高橋寛 三枝明夫 ) 使用教科書 :( プロ

PowerPoint プレゼンテーション

Javaプログラムの実行手順

プログラミング方法論 II 第 14,15 回 ( 担当 : 鈴木伸夫 ) 問題 17. x 座標と y 座標をメンバに持つ構造体 Point を作成せよ 但し座標 は double 型とする typedef struct{ (a) x; (b) y; } Point; 問題 18. 問題 17 の

PowerPoint プレゼンテーション

memo

Microsoft Word - VBA基礎(6).docx

Microsoft PowerPoint - CproNt11.ppt [互換モード]

program7app.ppt

関数の中で宣言された変数の有効範囲はその関数の中だけです さっきの rectangle _s で宣言されている変数 s は他の関数では使用できません ( 別の関数で同じ名前の変数を宣言することはできますが 全く別の変数として扱われます このように ある関数の中で宣言されている変数のことをその関数の

演算増幅器

PowerPoint プレゼンテーション

Microsoft Word - Cプログラミング演習(10)

Transcription:

プログラミング 1 第 6 回 ポインタ (3) -- ポインタの応用 関数の引数 配列を引数にする ( 前期教科書 P1) man 関数への引数 ( 後期教科書 P136) 動的メモリ割り当て ( 後期教科書 P133) この資料にあるサンプルプログラムは /home/course/prog1/publc_html/7/hw/lec/sources/ 下に置いてありますから 各自自分のディレクトリにコピーして コンパイル 実行してみてください Prog-1 7 Lec 6-1 Programmng-1 Group 1999-7

scanf の引数 scanfにおいて変数 につく & は おまじない として取り扱ってきた 又文字列の場合のみは配列名を書き & はつけないことになっていた scanf("%d"&) scanf("%s"str) また これまで学んだことで以下の事が分かった 変数に & を付けるとその変数の アドレス になる 配列名はその配列の先頭要素の アドレス である つまり &は変数 のアドレスを strは配列 ( 文字列 )strの先頭アドレスを表している 実はscanfの書式の後の引数は読み込む変数の アドレス を指定することになっている 通常の変数には & をつけ 文字列 ( 配列 ) の場合は & をつけないのはこのためだった Prog-1 7 Lec 6- Programmng-1 Group 1999-7

関数にアドレスを渡すとは? さて それでは scanf のように関数にアドレスを渡す意味は何だろうか? Prog-1 7 Lec 6-3 Programmng-1 Group 1999-7

値渡し 通常関数を呼ぶ場合は引数の値が関数に渡される これを 値渡し と呼ぶ 呼ぶ側の引数の値は決して変更されない swap( swap( ) ) 5 5 3 3 swap( swap( ) ) prf("%d\t%d\n" prf("%d\t%d\n" ) ) swap( swap( a a b) b) temp temp a a a a b b b b prf("a%d\tb%d\n" prf("a%d\tb%d\n" a a b) b) 実行結果実行結果 s11std1ss11 s11std1ss11 a3 a3 b5 b5 5 5 3 3 s11std1ss11 s11std1ss11 関数内では入れ替わったが 呼ぶ側の変数の値は入れ替わらない! man 一方向のコピー swap a b Prog-1 7 Lec 6- Programmng-1 Group 1999-7

アドレス渡し アドレスを引数として関数に渡すことも可能である これを アドレス渡し と呼ぶ 呼ぶ側の変数の値はアドレスを介して関数側から変更出来る swap( swap( * * *) *) 5 5 3 3 swap(& swap(& &) &) prf("%d\t%d\n" prf("%d\t%d\n" ) ) swap( swap( *p *p *q) *q) temp temp *p *p *p *p *q *q *q *q prf("*p%d\t*q%d\n"*p*q) prf("*p%d\t*q%d\n"*p*q) 関数の引数はポインタ 実行結果実行結果 s11std1ss11 s11std1ss11 *p3 *p3 *q5 *q5 3 3 5 5 s11std1ss1 s11std1ss1 Prog-1 7 Lec 6-5 Programmng-1 Group 1999-7 man & & 注 C の場合 アドレスを 値渡し するので 他言語のような 参照渡し ではない コピー 入れ替わった! swap p 同一の物参照 ( 同一アドレス ) q

アドレス渡しの利点と注意点 関数を呼ぶ側の変数の値を 呼ばれる側からも変更出来る 呼ぶ側の変数に値を代入したい場合 (scanf など ) に便利 複数の戻り値が欲しい場合などにも利用出来る 誤って 呼ぶ側の関数の変数を破壊する可能性もあるので 注意が必要例えば関数内で 呼ぶ側の関数 関数 a() b() 呼ばれる側の関数 関数 b() f(*p ) と書くべき所を f(*p ) とすると ポインタ p が指すアドレスの変数に が代入されてしまう! Prog-1 7 Lec 6-6 Programmng-1 Group 1999-7

クイズ 先ほどのアドレス渡しで値を入れ替えたプログラムを書き直し関数で値ではなく アドレスを入れ替えるように変更した 結果はどうなるか推測してみよう swap( swap( * * *) *) 5 5 3 3 swap(& swap(& &) &) prf("%d\t%d\n" prf("%d\t%d\n" ) ) swap( swap( *p *p *q) *q) * * temp temp p p p p q q q q prf("*p%d\t*q%d\n"*p*q) prf("*p%d\t*q%d\n"*p*q) 実行結果実行結果 s11std1ss11 s11std1ss11 *p3 *p3 *q5 *q5???? s11std1ss1 s11std1ss1 man swap & & コピー p q swap p q 入れ替え後 Prog-1 7 Lec 6-7 Programmng-1 Group 1999-7

クイズの解答 先ほどのアドレス渡しで値を入れ替えたプログラムを書き直し関数で値ではなく アドレスを入れ替えるように変更した これは 結局最初 p が を指していたのが を q が を指していたのが を指すようになる 結局 man の変数 の値は入れ替わらない 実行結果実行結果 s11std1ss11 s11std1ss11 *p3 *p3 *q5 *q5 5 5 3 3 s11std1ss1 s11std1ss1 man & & コピー swap p q swap p q 入れ替え後 Prog-1 7 Lec 6- Programmng-1 Group 1999-7

配列の引数 ( ( *) *) a[] a[] 1 1 3 3 ++) ++) prf("a[%d] prf("a[%d] %d\n"a[]) %d\n"a[]) (a) (a) ++) ++) prf("a[%d] prf("a[%d] %d\n"a[]) %d\n"a[]) ( ( *) *) ++) ++) [] [] * * [] [] return return 呼び出し前の要素値の表示 配列 a を引数にして関数 を呼ぶ 呼び出し後の要素値の表示 ポインタを配列風に使用している 配列の先頭アドレスを アドレス渡し することで配列を引数にすることが出来る 関数側の引数はポインタ この関数は配列の各々の要素を 倍する 実行結果実行結果 s11std1ss11 s11std1ss11 a[] a[] 1 1 a[1] a[1] 関数 a[] a[] 3 3 呼び出し前 a[3] a[3] a[] a[] a[1] a[1] 関数 a[] a[] 6 呼び出し後 6 a[3] a[3] s11std1ss1 s11std1ss1 Prog-1 7 Lec 6-9 Programmng-1 Group 1999-7

配列の引数 ( ( []) []) a[] a[] 1 1 3 3 ++) ++) prf("a[%d] prf("a[%d] %d\n"a[]) %d\n"a[]) (a) (a) ++) ++) prf("a[%d] prf("a[%d] %d\n"a[]) %d\n"a[]) 関数の引数を配列風に書く事も出来る これは前ページの例と全く同じ動作をする 関数 の仮引数 は配列ではなく ポインタである ( ( []) []) ++) ++) [] [] * * [] [] return return Prog-1 7 Lec 6-1 Programmng-1 Group 1999-7

配列の引数サンプル 以下は今日出てきた関数へのアドレス渡し 配列の引数を利用したプログラムである かなり実用的なプログラムであるので 是非サンプルプログラムを各自のディレクトリにコピーし 色々と変更して動作を試してみて欲しい Prog-1 7 Lec 6-11 Programmng-1 Group 1999-7

man 関数への引数 これまで man 関数はただ と書いてきたが 本当は以下のようになる ( 戻り値の は省略しても構わない 引数も使用しない場合は省略出来る ) man( argc *argv[]) *argv[] は第五回授業の最後に出てきたポインタの配列 ( 文字列定数の配列 ) である man 関数への引数は実行時のオプションとして与えることが出来る 例えば プログラムの実行モジュール名が proge だとして コマンドラインから./proge abc def gdsf t7jk のように入力すると以下のように数値 ( 文字列 ) が代入される 1. argc には自分 (proge) を含んだ引数の数 ( この場合 5). argv[] にはコマンド自身の文字列 ("./proge") 3. argv[1] には 1 番目の引数の文字列 ("abc"). argv[] には 番目の引数の文字列 ("def") 5. argv[3] には 3 番目の引数の文字列 ("gdsf") 6. argv[] には 番目の引数の文字列 ("t7jk") Prog-1 7 Lec 6-1 Programmng-1 Group 1999-7

man 関数の引数 以下のプログラムによって argv に入った文字列をすべて出力することが可能である 関数への引数によって プログラムにいろいろな指示を与えることが出来る 例えば以下のようなプログラムが考えられる prog 1 などのように ( ループ回数のような ) 渡したい情報を与える prog3 test/test.data などのように使いたいファイル名を指定してもらう prog1 -a -bcd などのようなオプションを入力し プログラムの動作を変える #nclude #nclude stdo.h> stdo.h> man( man( argc argc *argv[]) *argv[]) for for ( ( argc argc ++) ++) prf("argv[%d] prf("argv[%d] %s\n"argv[]) %s\n"argv[]) 番目の文字列 実行結果実行結果 s11std1ss11 s11std1ss11./proge./proge abc abc def def gdsf gdsf t7jk t7jk argv[] argv[]./proge./proge argv[1] argv[1] abc abc argv[] argv[] def def argv[3] argv[3] gdsf gdsf argv[] argv[] t7jk t7jk s11std1ss1 s11std1ss1 Prog-1 7 Lec 6-13 Programmng-1 Group 1999-7

#nclude #nclude stdo.h> stdo.h> #nclude #nclude stdlb.h> stdlb.h> m_strlen( m_strlen( *) *) man( man( argc argc *argv[]) *argv[]) buf[1] buf[1] count count acu_leng acu_leng FILE FILE *fp *fp f(argc f(argc!! ) ) prf("usage prf("usage %s %s flename\n"argv[]) flename\n"argv[]) et() et() f((fp f((fp fopen(argv[1]"r")) fopen(argv[1]"r")) NULL) NULL) prf("fle prf("fle %s %s not not found\n"argv[1]) found\n"argv[1]) et() et() whle(fscanf(fp"%s"buf) whle(fscanf(fp"%s"buf) 1) 1) count++ count++ acu_leng acu_leng + + m_strlen(buf) m_strlen(buf) prf("total prf("total %d %d word(s) word(s) average average length length %f\n" %f\n" count count (double)acu_leng/count) (double)acu_leng/count) m_strlen( m_strlen( *buf) *buf) *p *p buf buf p[] p[]!! '\' '\' ++) ++) return return サンプル 実行結果実行結果 std1ss1s11 std1ss1s11 cat cat n1.data n1.data In In 19 19 Apple Apple Computer Computer roduced roduced the the Macosh Macosh desktop desktop computer computer wth wth a a ver ver "frendl" "frendl" graphcal graphcal user user erface. erface. Graphcal Graphcal user user erfaces(guis) erfaces(guis) began began to to change change the the compleon compleon of of the the software software ndustr. ndustr. std1ss1s1 std1ss1s1 n1.data n1.data total total word(s) word(s) average average length length 6.5 6.5 std1ss1s13 std1ss1s13 wc wc n1.data n1.data 7 7 n1.data n1.data std1ss1s1 std1ss1s1 このプログラムは以下の特徴がある ( オリジナル lec-5.c を参照 ) man 引数を利用してファイル名を入力 関数への配列引数を利用して文字列の長さを知る関数 m_strlen を作成 scanf( %s ) を使用して 文中の単語の数を数える Prog-1 7 Lec 6-1 Programmng-1 Group 1999-7

無駄な配列要素 右は引数の文字列を数字とみなして データの個数を指定し 最大 1 個までのデータをscanfで読み込むことが出来るプログラムである ところが例えば要素数が5 個なら配列の995 個の要素は無駄になる なお 右のプログラム中 関数 atoは数字の文字列 ( 例えば "3" など ) を 型の数字に変換する関数である (stdlb.h に定義されている ) 実行結果実行結果 s11std1ss11 s11std1ss11 5 5 arra arra btes btes 6 6 1 1 6 6 1 1 s11std1ss1 s11std1ss1 #nclude #nclude stdo.h> stdo.h> #nclude #nclude stdlb.h> stdlb.h> #defne #defne MAX MAX 1 1 man( man( argc argc *argv[]) *argv[]) arra[max] arra[max] f(argc f(argc!! ) ) prf("parameter prf("parameter error. error. Usage\n") Usage\n") prf(" prf(" %s %s ent-su\n"argv[]) ent-su\n"argv[]) et(1) et(1) ato(argv[1]) ato(argv[1]) prf("arra prf("arra %d %d btes" btes" szeof(arra)) szeof(arra)) ++) ++) scanf("%d"&arra[]) scanf("%d"&arra[]) ++) ++) prf("%d prf("%d "arra[]) "arra[]) prf("\n") prf("\n") Prog-1 7 Lec 6-15 Programmng-1 Group 1999-7

動的メモリ割り当て 大きさを読み込んで ( 又は計算して ) から配列を取りたい場合が出てくる プログラムが作動しだしてから状況に応じて配列の大きさを変更することからこれを 動的メモリ割り当て と呼ぶ しかし 以下のようなコードを書くことはCでは許されない ( エラーになる ) n n scanf("%d"&n) scanf("%d"&n) a[n] a[n] そこで 動的メモリ割り当てを関数とポインタによって実現している ( この関数はライブラリ stdlb.h に含まれる ) Prog-1 7 Lec 6-16 Programmng-1 Group 1999-7

動的メモリ割り当て関数 (1) 動的メモリ割り当てのための関数として 代表的なものは malloc と free ( 次頁 ) の つである *malloc(sze) これは sze バイト分の領域をメモリ上に確保して その先頭アドレスを戻り値として返すものである 例えば 型の領域を 5 個確保してその場所を arra という名前にしたいなら 以下のようにする *arra arra malloc(5 * szeof()) ここで 5 * szeof() はその配列全体のバイト数を意味している 関数関数 malloc mallocの戻り値は * ( ( 型ポインタ ) という型で どんな型でもないポインタ と言う意味である 確保した領域を 型として使用する場合は arra arra ( ( *)malloc(..) のように 型ポインタ ( (*) *) でキャストするか 上のように 暗黙のキャスト を使用してそのまま代入する Prog-1 7 Lec 6-17 Programmng-1 Group 1999-7

動的メモリ割り当て関数 () free( *p) これは引数で指定されたポインタが指す領域 ( 正確にはポインタは領域の先頭アドレスを指す ) を解放することを意味する 上の例の配列 arra を解放するには以下のようにすれば良い free(arra) 動的メモリ割り当ての手順は以下のようになる 配列名となるポインタを宣言 malloc で配列となる領域を確保 領域の場所をポインタに代入 ポインタを配列名として配列を使用 使用が終了したら free で領域を解放 Prog-1 7 Lec 6-1 Programmng-1 Group 1999-7

無駄なく配列を使う 右のプログラムは先ほどの例を動的メモリ割り当てを使用して書き換えたもので この方法では余分な配列要素を作成しないので 無駄が無い 実行結果実行結果 s11std1ss11 s11std1ss11 5 5 arra arra btes btes 6 6 1 1 6 6 1 1 s11std1ss1 s11std1ss1 注 動的メモリ割り当ての場合 szeof(arra) は配列の大きさではなく ポインタの大きさ () を返すので注意! #nclude #nclude stdo.h> stdo.h> #nclude #nclude stdlb.h> stdlb.h> man( man( argc argc *argv[]) *argv[]) *arra *arra f(argc f(argc!! ) ) prf("parameter prf("parameter error. error. Usege\n") Usege\n") prf(" prf(" %s %s ent-su\n"argv[]) ent-su\n"argv[]) et(1) et(1) ato(argv[1]) ato(argv[1]) arra arra malloc( malloc( * * szeof()) szeof()) prf("arra prf("arra %d %d btes" btes" * * szeof()) szeof()) ++) ++) scanf("%d"&arra[]) scanf("%d"&arra[]) ++) ++) prf("%d prf("%d "arra[]) "arra[]) prf("\n") prf("\n") free(arra) free(arra) Prog-1 7 Lec 6-19 Programmng-1 Group 1999-7