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

Similar documents
slide5.pptx

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

Microsoft Word - no15.docx

PowerPoint Presentation

gengo1-12

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

Microsoft Word - no204.docx

プログラミング基礎

gengo1-12

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

ファイル入出力

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

ファイル入出力

gengo1-12

情報処理演習 B8クラス

演算増幅器

Microsoft Word - 3new.doc

PowerPoint プレゼンテーション

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

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

Microsoft PowerPoint - prog04.ppt

02: 変数と標準入出力

Microsoft PowerPoint - kougi2.ppt

02: 変数と標準入出力

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

memo

C言語入門

2006年10月5日(木)実施

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

PowerPoint プレゼンテーション

<4D F736F F D20438CBE8CEA8D758DC F0939A82C282AB2E646F63>

Microsoft PowerPoint - lec10.ppt

プログラミング実習I

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

Microsoft PowerPoint - 11.pptx

Microsoft PowerPoint - prog06.ppt

PowerPoint Presentation

Prog1_12th

memo

02: 変数と標準入出力

PowerPoint プレゼンテーション

C 言語の式と文 C 言語の文 ( 関数の呼び出し ) printf("hello, n"); 式 a a+4 a++ a = 7 関数名関数の引数セミコロン 3 < a "hello" printf("hello") 関数の引数は () で囲み, 中に式を書く. 文 ( 式文 ) は

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

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

Microsoft PowerPoint pptx

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

計算機プログラミング

Microsoft PowerPoint - C言語の復習(配布用).ppt [互換モード]

1. ファイルにアクセスするには ファイルにアクセスするには 1. ファイルを開く 2. アクセスする 3. ファイルを閉じるという手順を踏まなければなりません 1.1. ファイルを読み込む まずはファイルの内容を画面に表示させるプログラムを作りましょう 開始 FILE *fp char fname

02: 変数と標準入出力

ohp07.dvi

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

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

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

Microsoft PowerPoint - kougi6.ppt

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

※ ポイント ※

memo

Microsoft PowerPoint - kougi9.ppt

memo

kiso2-03.key

gengo1-8

PowerPoint プレゼンテーション

r07.dvi

ポインタ変数

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

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

Microsoft PowerPoint - kougi4.ppt

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

02: 変数と標準入出力

program7app.ppt

4 分岐処理と繰返し処理 ( 教科書 P.32) プログラムの基本的処理は三つある. (1) 順次処理 : 上から下に順番に処理する ぶんきそろ (2) 分岐処理 : 条件が揃えば, 処理する はんぷく (3) 反復処理 : 条件が揃うまで処理を繰り返す 全てのプログラムは (1) から (3) の

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

PowerPoint プレゼンテーション

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

Microsoft PowerPoint - bp02.ppt

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

PowerPoint プレゼンテーション

データ構造

デジタル表現論・第6回

講習No.12

練習&演習問題

PowerPoint Presentation

Microsoft Word - no11.docx

第2回講義:まとめ

Microsoft PowerPoint - prog03.ppt

cp-7. 配列

プログラミングI第6回

Cプログラミング1(再) 第2回

PowerPoint プレゼンテーション

Microsoft Word - no103.docx

gengo1-11

02: 変数と標準入出力

PowerPoint Template

Prog1_10th

プログラミングI第10回

プログラミング基礎

kiso2-09.key

問 2 ( 型変換 ) 次のプログラムを実行しても正しい結果が得られない 何が間違いかを指摘し 正しく修正せよ ただし int サイズが 2 バイト long サイズが 4 バイトの処理系での演算を仮定する #include <stdio.h> int main( void ) { int a =

02: 変数と標準入出力

Transcription:

Outline プログラミング演習第 8 回やり残したこと on 2012.12.13 ファイルを使う メモリの管理 簡単なデバッグの方法 演習課題 電気通信大学情報理工学部知能機械工学科長井隆行 2 入出力 ( ファイルを使う ) ハードディスクにあるデータを使ったり ハードディスクに結果を記録するためには ファイルを読み書きできないといけない 細かいことはどうでもいいので まずやるべきことは 操作するファイルの名前を指定して ファイルをオープンし ファイルポインタを取得する 最後に必ずクローズする ファイルポインタとは FILE 構造体へのポインタ FILE 構造体は 入出力の現在位置 ファイルの終端に達したかの情報 エラー情報 関連するバッファへのポインタなどのファイルの入出力を行う上での必要不可欠な情報を管理 ファイル名との関連付けを行う fopen(const char *filename, const char *mode ) ファイル名 (filename) で示されるファイルを 指定モード (mode) で オープンする モード 動作 ファイルがあるとき ファイルがないとき "r" 読み出し専用 正常 エラー (NULL 返却 ) "w" 書き込み専用 サイズを 0 にする ( 上書き ) 新規作成 "a" 追加書き込み専用 最後に追加する 新規作成 fclose(file *fp); fopen でオープンされたファイルポインタ (fp) で示されるファイルをクローズする 3 4

実際の読み書きをする関数 fprintf(file *fp, const char *format,...); ファイルポインタ (fp) で指定したファイルへ書式つきで出力する printf のファイル版 ファイルポインタを指定する以外は printf と同じ ファイルへの出力例 #include<stdio.h ファイルポインタの宣言 FILE* fp; ファイルのオープン char moji[] = "software engineering"; int hoge = 100; float foo = 153.5f; 実際に書き込み fscanf(file *fp, const char *format,...); ファイルポインタ (fp) で指定したファイルから書式つきで入力する scanf のファイル版 ファイルポインタを指定する以外は scanf と同じ 5 fp = fopen("out_file.txt", "w"); fprintf(fp, "%s n", moji); fprintf(fp, "hoge is %d ", hoge); fprintf(fp, "foo is %f n", foo); fclose(fp); p8-1.c gcc -o p8-1 p8-1.c./p8-1 cat out_file.txt software engineering hoge is 100 foo is 153.500000 ファイルのクローズ 6 メモリを確保する メモリの動的確保 配列の欠点は何でしょう? 要素数を予め決めておく必要がある プログラムを実行しないとデータの数が分からない場合がたくさんある ( 例 ) 画像ファイルを開いて表示 画像サイズは開いてみないと分からない ものすごく大きな要素数の配列をその都度用意するのは大変 ( 時間がかかる ) 関数が呼ばれる毎にスタックに積むのは大変 スタック領域ではなくヒープ領域を使い長期的 にメモリを使用する 関数 malloc( サイズ ) を使用する malloc(size) を実行すると size バイト分のメモリ領域が確保され (OS が確保してくれる ) その先頭を指すポインタが返される 不必要になった段階でメモリを開放する必要がある free( ポインタ ) を使用する 0 番 1 番 2 番 3 番 4 番 data[0] data[1] data[2] data[3] data[4] data = malloc(sizeof(int)*5); ヒープ領域 : 長期的に使用される大きなサイズのメモリを格納する領域 7 dataはポインタ ( 確保された領域の先頭のアドレスが入る ) 確保された領域は data[i] や *(data+i) のように配列と同じ方法で使うことができる 8

変数のスコープと寿命 ( 復習 ) malloc の使用例 スコープのお話 宣言方法 寿命 スコープ 初期化 全てのブロック外 プログラム実行中 プログラム全体 宣言時の一度だけ 全てのブロック外でstatic プログラム実行中 モジュール内 プログラム開始時の一度だけ (static+global) ブロック内 ブロック内のみ一時的 ブロック内 ブロックに入るたび ブロック内でのstatic プログラム実行中 ブロック内 プログラム開始時の一度だけ malloc 関数の使用 malloc() からfree() まで ポインタ変数の宣言による 関数の仮引数として 関数ブロック内のみ 関数ブロック内 注 ) モジュール : プログラムをいくつかのファイルに分割した場合の各ファイルに相当する malloc(), free() に関しては後日説明予定 9 int* data; int I, memsize; scanf("%d", &memsize); data= malloc(sizeof(int)*memsize); /* エラー処理 ( メモリが確保できなかった場合 )*/ if(data==null) printf(" メモリが足りません n"); /* 確保したメモリに順番に値を格納する */ for(i=0; i<memsize; i++) data[i]=i /* 確保したメモリの開放 */ free(data); int data[memsize]; メモリが確保できなかった場合 malloc は NULL を返す 配列と同じ使い方ができる p8-2.c 10 練習問題 テキストファイルの値を見てメモリを確保しデータを読み込むプログラム データ数 5 123 456 789 321 654 data.txt データ本体 int* Data; int i, DataSize; FILE* fp; fp=fopen("data.txt", "r"); if(!fp) printf(" ファイルが開けません "); /* データサイズを読み込み */ fscanf(fp,"%d", &DataSize); /* メモリの確保 */ Data= malloc(sizeof(int)*datasize); /* データの読み込み */ fscanf(fp,"%d", Data+i); /* データの表示 */ printf("%d n", Data[i]); p8-3.c free(data); fclose(fp); 11 int* Data; int i, DataSize; FILE* fp; fp=fopen("data.txt", "r"); if(!fp) printf(" ファイルが開けません "); /* データサイズを読み込み */ fscanf(fp,"%d", &DataSize); /* メモリの確保 */ Data= malloc(sizeof(int)*datasize); 解答例 p8-3.c /* データの読み込み */ fscanf(fp,"%d", Data+i); /* データの表示 */ printf("%d n", Data[i]); free(data); fclose(fp); &Data[i] も可 *(Data+i) も可 12

こんなときどうする? プログラムを書いたがコンパイルがうまくいかない ( エラーが出る ) もーやめた と言う前に どんなに間違いを見つけようとしてもどうしても見つからない もーやめた! とりあえず落ち着きましょう bcc32 EXerror.c Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland EXerror.c: エラー E2451 EXerror.c 9: 未定義のシンボル hoge1( 関数 main ) 警告 W8004 EXerror.c 11: 'foo' に代入した値は使われていない ( 関数 main ) 警告 W8004 EXerror.c 11: 'hoge' に代入した値は使われていない ( 関数 main ) *** 1 errors in Compile *** ちょっと休憩するかその日はやめて次の日取り組む ( 間をおく ) 休憩後ソースファイルを印刷して眺めてみる 以外に簡単な間違いだったことに気づく こともある 最初から作り直す もっと具体的な対処方法はないの? 13 14 対処法その 1 プログラムを書いたがコンパイルがうまくいかないこれはデバッグというよりは 言葉 ( 文法 ) の問題です エラーメッセージをよーく見る とにかく間違いを探す どこに間違いがあるかをはっきりさせることが先決 怪しいところをコメントアウトしてコンパイルしてみる 対処法その 1 つづき よくある間違い セミコロン (;) 忘れ [] () などの不整合 変数や関数の宣言忘れ 変数の綴りの間違い 記号の打ち間違え 代入の際に型があっていない 全角文字が入ってしまっている 引数の間違え 15 16

エラーメッセージ (borlandc++ の場合 ) デバッグライトによるデバッグ #include<stdio.h double hoge = 123.456 /* 変数の宣言 */ int foo =100; /* 変数の宣言 */ double* hoge_p; /* ポインタ変数の宣言 */ hoge_p = &foo; printf("%f n", hoge1); return 0 bcc32 p8-4.c Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland p8-4.c: エラー E2141 p8-4.c 6: 宣言の構文エラー ( 関数 main ) エラー E2451 p8-4.c 9: 未定義のシンボル foo( 関数 main ) エラー E2451 p8-4.c 11: 未定義のシンボル hoge1( 関数 main ) エラー E2378 p8-4.c 13: Return 文に ; がない ( 関数 main ) 警告 W8004 p8-4.c 13: 'hoge' に代入した値は使われていない ( 関数 main ) *** 4 errors in Compile *** p8-4.c Borland C++ の場合 コンパイルはできたが実行すると結果がおかしい デバッグしましょう 怪しいところをコメントアウトしてみる 間違いのある場所を徐々に特定していく printfを使ったデバッグ デバッグライト とにかく計算の途中結果を確認することが大事 多くの場合はこれで間違いを探すことができる 警告 (warning) は無視してよい場合とそうでない場合がある 17 18 デバッグライトによるデバッグ int value; /* キーボードから入力された数値 */ printf("enter number : "); scanf("%d", value); if(value = 10) /* 数値が10であるか判定 */ printf("input number is 10. n"); else printf("input number is not 10. n"); p8-5.c どこに printf を入れますか? どこがいけないのでしょう? bcc32 p8-5.c Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland p7-5.c: 警告 W8060 p7-5.c 12: おそらく不正な代入 ( 関数 main ) Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland p8-5 Enter number : 2 Input number is 10. おかしい! 19 練習問題 1 から 10 までに奇数がいくつあるか数えるプログラム int count; /* 奇数の数 */ int odd; /* 現在の奇数値 */ count = 0; odd = 1; /* 奇数の初期値 */ while(odd!= 10) /* 10 になるまで */ count++; /* 奇数の数を加算 */ odd = odd+2; /* 次の奇数へ */ printf("count = %d n", count); /* 奇数の数を表示 */ p8-6.c このままだと無限ループにはまりますどうやって間違いを探せばよいでしょう? 間違いはどこにあるのでしょう? 20

解答例 1 から 10 までに奇数がいくつあるか数えるプログラム int count; /* 奇数の数 */ int odd; /* 現在の奇数値 */ count = 0; odd = 1; While (odd < 10) /* 奇数の初期値 */ while(odd!= 10) /* 10になるまで */ count++; /* 奇数の数を加算 */ odd = odd+2; /* 次の奇数へ */ printf("count = %d n", count); /* 奇数の数を表示 */ p8-7.c ここがまずい! oddが10になることはない このままだと無限ループにはまりますどうやって間違いを探せばよいでしょう? 間違いはどこにあるのでしょう? 21 デバッガを使う 対処法その 3 デバッガは プログラムの実行時の動作を確認し エラーの場所を特定できる強力なツール デバッグライトは有効なデバッグ方法だが 問題の場所を特定して解決した後に コード全体を見直して余分な関数呼び出しをすべて削除する必要がある printf などの呼び出しを1つ追加しただけでも 新しいコードが追加されたことで デバッグを行っているコードの動作が変更されることがある デバッガを使用すると 変数値を出力する追加の呼び出しを挿入せずに プログラムの変数値をチェックできる! コードにブレークポイントを挿入すると 調べたい位置で実行が中断される 22 gcc の場合 gdb を使う 基本は ブレークポイントをつけてステップ実行 変数の中身 ( 値 ) をチェックしていく コンパイル時に g オプションをつける gcc g ファイル名 (xxx.c) int i, count; count = 0; for(i=0; i<3; i++) count++; printf("count = %d n", count); gdb: デバッガの起動 run: プログラムの実行 next: 次の1 行を実行 ( 関数は1 行とみなす ) step: 次の1 行を実行 ( 関数内も順次実行 ) quit: デバッガの終了 list: プログラムの表示 break: ブレイクポイントの設定 delete: ブレイクポイントの削除 print: 変数の値を調べる whatis: 変数の型を調べる gdbの主要なコマンド このプログラムをトレースしてみる 23 gcc -g deb.c gdb a.exe GNU gdb 2003-09-20-cvs (cygwin-special) Copyright 2003 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i686-pc-cygwin"... (gdb) list 1 2 3 4 int i, count; 5 count = 0; 7 9 10 printf("count = %d n", count); (gdb) break 5 Breakpoint 1 at 0x40108a: file deb.c, line 5. (gdb) run Starting program: /home/tnagai/soft_eng/a.exe Breakpoint 1, main () at deb.c:5 5 count = 0; $1 = 0 $2 = 1 (gdb) print i $3 = 0 $4 = 2 (gdb) print i $5 = 1 $6 = 3 (gdb) print i $7 = 2 10 printf("count = %d n", count); (gdb) continue Continuing. count = 3 Program exited normally. (gdb) quit 24

本日の演習 ー準備ー まずは p8-8.c(check_maxまでの整数からすべての素数を探すプログラム ) をダウンロードする 配列を使っていくつまでできるか試してみる CHECK_MAXを10 倍しながら実行してみる 変な挙動をしたら ( 多分 ) 配列の数が限界を超えている ー課題ー ( ここから先をメールで送る ) p8-9.cをダウンロード P8-8.cをメモリ確保することで実現する 配列でできなかったものでもメモリを確保すればできることを確かめてみる 見つかった素数をファイルに書き出してみる p8-3.cのdata.txtを参考にする ( 余裕があれば書き出した素数を再度プログラムで読み込んでみる ) ソースコードと実行結果をメールで送る 送る際には注意事項をよく確認すること http://apple.ee.uec.ac.jp/comprog 諸注意 今日の講義の感想 質問をメール本文に書いてください よく分かった ここが分からない など 25 #include <math.h #define CHECK_MAX 10000 /* この値までの素数を探す */ int count; int i, j, k; int prime[check_max]; /*CHECK_MAX 個の配列を用意しておく */ printf("2 "); /* 最初の素数 */ count = 1; /*1 カウント */ prime[0]=2; /*2 を登録 */ #define CHECK_MAX 10000 マクロ定義プログラム中の CHECK_MAX という文字列を 10000 で置き換えろという ( プリプロセッサ ) 命令 /* 素数計算メイン */ for(i=3; i<=check_max; i+=2) k=0; for(j=3; j<=sqrt(i); j+=2) if(i%j==0) k=1; break; /* 素数じゃない */ if(k==0) count++; /* 素数発見 */ prime[count-1]=i; printf("%d ",prime[count-1]); printf(" n"); p8-8.c 26 #include <string.h #include <math.h int check_max, count; int i, j, k; int* prime; scanf("%d", &check_max); /* キーボードからの入力待ち */ /********************************************************/ /* ここで malloc を使って必要なメモリを確保する */ /* prime = malloc(????????????????????); */ /********************************************************/ memset(prime, 0, sizeof(int)*check_max); /* ゼロで埋める ( 初期化 )*/ printf("2 "); count = 1; prime[0]=2; p8-9.c /* 素数判定 */ for(i=3; i<=check_max; i+=2) k=0; for(j=3; j<=sqrt(i); j+=2) if(i%j==0) k=1; break; if(k==0) count++; prime[count-1]=i; printf("%d ",prime[count-1]); printf(" n"); /**************************/ /* ここでファイルに書き出す */ /**************************/ /******************/ /* ここでメモリ解放 */ /******************/ 27