1
Cプログラミング演習
第6回 ファイル処理と配
2
ファイル処理
3
ファイル読み込み
ファイル
プログラム
ファイルの中身は変わらない
4
ファイル書き出し
ファイル
プログラム
ファイルの中身が変わる
ファイルは伸び縮みすることがある
5
例題1.テキストファイル形式の
ファイルからのデータ読み込み
次のよ名簿ファイル(テキストファイル形
式)を読み込んで,1列目の氏名と,3列目の
住所だけを表示するプログラムを作る
各データは,半角の空白文字(1つまたは複数)で
区切られる
金子邦彦 1200/01/01 福岡市東区箱崎3丁 392-123-8234
○○×× 1300/12/31 福岡市東区貝塚団地 492-252-7188
●●■■ 0800/05/31 福岡市東区香椎浜1丁目 592-824-7144
3行のテキストファイル
6
テキストファイル形式
行単位での読み書きに意味がある。
人間が「目で見て」読むことができるファイル。
MPL 40
pattern1 = 786
pattern2 = 1
pattern3 = 979
pattern4 = 0
テキストファイルの例
<FF>0<FF><E0>^@^
PJFIF^@^A^B^A^@<
96>^@<96>^@^@<FF
><E0>~JFXX^@^P<F
F>00<FF>U^@^C^@^
テキストファイルでない
バイナリファイルの例
画像のファイル
7
#include "stdafx.h"
#include <math.h>
#pragma warning(disable:4996)
int _tmain()
{
char line[100];
char name[100];
char birth[100];
char address[100];
FILE *in_file;
int ch;
in_file = fopen("d:\\Book1.txt", "r");
if ( in_file == NULL ) {
return 0;
}
while( fgets( line, 100, in_file ) != NULL ) {
sscanf_s( line, "%s %s %s", name, birth, address );
printf( "name=%s, address=%s\n", name, address );
}
fclose(in_file);
ch = getchar();
ch = getchar();
return 0;
}
8
例題1の手順
1.準備
演習用のデータファイル d:\Book1.txt を各自で作
(本資料のページ9,10,11,12,1
3)
2.ビルドと実行
例題1のプログラムを各自で実行し,実行結果を
確認
(本資料のページ14,15)
各自で行ってください
(実行結果の確認まで)
9
まず,データファイル
d:\Book1.txt を準備する
(テキストファイル形式)
金子邦彦 1200/01/01 福岡市東区箱崎3丁目 392-123-8234
○○×× 1300/12/31 福岡市東区貝塚団地 492-252-7188
●●■■ 0800/05/31 福岡市東区香椎浜1丁目 592-824-7144
d:\Book1.txt の例
(全角の空白文字が混ざっていると
動かないことがあるので注意してください)
半角の
空白文字
10
「メモ帳」を起動している
11
コピーして ・・・
12
貼り付ける
13
「ファイル」
「名前を付けて保存」
保存する場所
は,Zドライブ
ファイル名は
Book1.txt
14
ビルド後の画面
ビルドが正常終了したことを示
すメッセージ
ビルドの手順:
「ビルド」「○○のビルド」
「1.正常終了」を確認
15
実行中の画面
実行の手順:
「デバッグ」
「実行」
実行ウインドウが現れる
16
while による繰り返し部分
ファイルオープンに失敗した
ときのみ実行される部分
#include "stdafx.h"
#include <math.h>
#pragma warning(disable:4996)
int _tmain()
{
char line[100];
char name[100];
char birth[100];
char address[100];
FILE *in_file;
int ch;
in_file = fopen("d:\\Book1.txt", "r");
if ( in_file == NULL ) {
return 0;
}
while( fgets( line, 100, in_file ) != NULL ) {
sscanf_s( line, "%s %s %s", name, birth, address );
printf( "name=%s, address=%s\n", name, address );
}
fclose(in_file);
ch = getchar();
ch = getchar();
return 0;
}
17
NULLの意味
fopen 関数では「ファイルオープンの失敗
fgets 関数では「ファイルの終わり
#include "stdafx.h"
#include <math.h>
#pragma warning(disable:4996)
int _tmain()
{
char line[100];
char name[100];
char birth[100];
char address[100];
FILE *in_file;
int ch;
in_file = fopen("d:\\Book1.txt", "r");
if ( in_file == NULL ) {
return 0;
}
while( fgets( line, 100, in_file ) != NULL ) {
sscanf_s( line, "%s %s %s", name, birth, address );
printf( "name=%s, address=%s\n", name, address );
}
fclose(in_file);
ch = getchar();
ch = getchar();
return 0;
}
== 等しいという意味
!=」は等しくないという意味
18
fopen 関数では「ファイルオープンの失敗
fgets 関数では「ファイルの終わり
#include "stdafx.h"
#include <math.h>
#pragma warning(disable:4996)
int _tmain()
{
char line[100];
char name[100];
char birth[100];
char address[100];
FILE *in_file;
int ch;
in_file = fopen("d:\\Book1.txt", "r");
if ( in_file == NULL ) {
return 0;
}
while( fgets( line, 100, in_file ) != NULL ) {
sscanf_s( line, "%s %s %s", name, birth, address );
printf( "name=%s, address=%s\n", name, address );
}
fclose(in_file);
ch = getchar();
ch = getchar();
return 0;
}
ファイルオープンに失敗したら,
プログラムが終わる
ファイルの終わりになるまで,
gets, sscanf, printf を繰り返す
19
ファイル操作
ファイルのオープンとクローズ
fopen ファイルの読み書きを行に、ファイ
ルはオープンされねばならない
fclose ファイルの読み書きが終わったら
ファイルはクローズされねばならない
ファイルの読み込み
fgets 1行単位の読み込み
fread バイト単位での読み込み(1バイト,複
バイト)
ファイルの書き出し
fputs 1行単位での書き出し
fwrite バイト単位での書き出し(1バイト,複
バイト)
fprintf 整形しての書き出し
20
オープンモード
“rモード
読み込みモード
引数fileで指定したファイルが存在しないか,読み
込み不可能な場合には,オープンすることができ
ない.
w” モード
書き出しモード
引数fileで指定したファイルが存在しない場合には,
ファイルが新たに作成される.ファイルがすでに
存在した場合,ファイル中のデータはすべて捨て
られる(ファイルの長さは0になる).
in_file = fopen("d:\\Book1.txt", "r");
ファイル名
(文字列)
オープンモード
(文字列)
21
ファイルポインタ
ファイルのオープン
ファイルの読み込み(1行単位)
ファイルのクローズ
while による繰り返し部分
#include "stdafx.h"
#include <math.h>
#pragma warning(disable:4996)
int _tmain()
{
char line[100];
char name[100];
char birth[100];
char address[100];
FILE *in_file;
int ch;
in_file = fopen("d:\\Book1.txt", "r");
if ( in_file == NULL ) {
return 0;
}
while( fgets( line, 100, in_file ) != NULL ) {
sscanf_s( line, "%s %s %s", name, birth, address );
printf( "name=%s, address=%s\n", name, address );
}
fclose(in_file);
ch = getchar();
ch = getchar();
return 0;
}
22
#include "stdafx.h"
#include <math.h>
#pragma warning(disable:4996)
int _tmain()
{
char line[100];
char name[100];
char birth[100];
char address[100];
FILE *in_file;
int ch;
in_file = fopen("d:\\Book1.txt", "r");
if ( in_file == NULL ) {
return 0;
}
while( fgets( line, 100, in_file ) != NULL ) {
sscanf_s( line, "%s %s %s", name, birth, address );
printf( "name=%s, address=%s\n", name, address );
}
fclose(in_file);
ch = getchar();
ch = getchar();
return 0;
}
char 型の配列(サイズ100)
を4つ宣言している
(配列についての詳細は後述)
23
例題1のプログラムが
行っているこ
プログラムが使う
メモリ空間
line
name
birth
address
100バイトの
メモリエリア
100バイトの
メモリエリア
100バイトの
メモリエリア
100バイトの
メモリエリア
24
例題1のプログラムが
行っているこ
データファイル
プログラムが使う
メモリ空間
fgets
読み出し
(1行分)
line
name
birth
address
100バイトの
メモリエリア
100バイトの
メモリエリア
100バイトの
メモリエリア
100バイトの
メモリエリア
金子邦彦 1200/01/01 福岡市東区箱崎3丁目 392-123-8234
○○×× 1300/12/31 福岡市東区貝塚団地 492-252-7188
●●■■ 0800/05/31 福岡市東区香椎浜1丁目 592-824-7144
金子邦彦 ・・・
25
例題1のプログラムが
行っているこ
データファイル
プログラムが使う
メモリ空間
fgets
読み出し
(1行分)
line
name
birth
address
100バイトの
メモリエリア
100バイトの
メモリエリア
100バイトの
メモリエリア
100バイトの
メモリエリア
金子邦彦 1200/01/01 福岡市東区箱崎3丁目 392-123-8234
○○×× 1300/12/31 福岡市東区貝塚団地 492-252-7188
●●■■ 0800/05/31 福岡市東区香椎浜1丁目 592-824-7144
金子邦彦 ・・・
金子邦彦
1200/01/01
福岡市東区箱崎3丁目
2行目以降も
同様の処理が続く
sscanf での
処理
26
実際のメモリの中身
メモリの中身を画面表示したもの
27
実際のメモリの中身
メモリの中身を画面表示したもの
ここでは,16バイトごとに
区切って,1行で表示
28
実際のメモリの中身
メモリの中身を画面表示したもの
1バイト
16進数2桁 00からFF
2進数では8桁 00000000 から 11111111
10進数では 0 から 255 までの256通り
「バイト」は,データの基本単位
29
実際のメモリの中身
address
100バイト)
birth
100バイト)
name
100バイト)
line
100バイト)
30
プログラムとデー
プログラムが使うメモリ空間
fgets( line, 100, in_file )
ファイルの
読み込み
(1行単位)
line[0]
line[1]
line[99]
sscanf_s( line, "%s %s %s", name, birth, address );
1行分の表示
データの取り出し name birth address
printf( "name=%s, ...
31
変数は3種類使っている
整数を扱う int
文字を扱う char
ファイルポイン
#include "stdafx.h"
#include <math.h>
#pragma warning(disable:4996)
int _tmain()
{
char line[100];
char name[100];
char birth[100];
char address[100];
FILE *in_file;
int ch;
in_file = fopen("d:\\Book1.txt", "r");
if ( in_file == NULL ) {
return 0;
}
while( fgets( line, 100, in_file ) != NULL ) {
sscanf_s( line, "%s %s %s", name, birth, address );
printf( "name=%s, address=%s\n", name, address );
}
fclose(in_file);
ch = getchar();
ch = getchar();
return 0;
}
32
fgetsの振る舞い
ファイルの1行読み込み
ファイルの一行分を読み込んで、末端の\0を付ける
ファイルには、各行の終わりに、改行文字(\n)が付
いている(目には見えない)
読み込み先(文字の配列)のサイズが、ファイルの1
行の長さより長いときは、「残りの部分」は変化しな
文字の配列
line
ファイル
M a r k
改行文字 文字列の末端
変化しない
Mark\n 1行読み込むと・・・
16進数
の「0A
16進数
の「00
33
fgets での「100
文字の配列
ファイル
文字列の末端
fgets( line, 100, in_file )
配列のサイズが100ならば、読み込めるデータの
本体(「改行文字」を除く)は,最大で98文字まで
100バイトに達したら
行末になっていなくても読み込み終了せよ
16進数
の「00
16進数
の「0A
改行文字
34
#include "stdafx.h"
#include <math.h>
#pragma warning(disable:4996)
int _tmain()
{
char line[100];
char name[100];
char birth[100];
char address[100];
FILE *in_file;
int ch;
in_file = fopen("d:\\Book1.txt", "r");
if ( in_file == NULL ) {
return 0;
}
while( fgets( line, 100, in_file ) != NULL ) {
sscanf_s( line, "%s %s %s", name, birth, address );
printf( "name=%s, address=%s\n", name, address );
}
fclose(in_file);
ch = getchar();
ch = getchar();
return 0;
}
それぞれ対応
char 型の配列については,
sscanf, printf , fprintf
では「%s」を,使う決まりになっている
それぞれ対応
35
配列
36
一次元配列
配列の要素には型がある
例) int, char, double など
配列 a
0
1
2
0から始まる番号がついたデータの並び
0から
開始
サイズは
37
例題2.ベクトルの内積
ベクトル(1.9, 2.8, 3.7)と,ベクトル
4.6, 5.5, 6.4)の内積を表示するプログ
ラムを作る
2つのベクトルの内積の計算のために,
イズ3の一次元配列を2つ使
38
例題2:ベクトルの内積
#include "stdafx.h"
#include <math.h>
int _tmain()
{
int i;
double ip = 0.0;
double u[]={1.9, 2.8, 3.7};
double v[]={4.6, 5.5, 6.4};
int ch;
for (i=0; i<3; i++) {
ip = ip + u[i]*v[i];
}
printf("内積=%f\n", ip);
ch = getchar();
ch = getchar();
return 0;
}
変数の宣言
および初期化
整数を扱う int
浮動小数を扱う double
39
#include "stdafx.h"
#include <math.h>
int _tmain()
{
int i;
double ip = 0.0;
double u[]={1.9, 2.8, 3.7};
double v[]={4.6, 5.5, 6.4};
int ch;
for (i=0; i<3; i++) {
ip = ip + u[i]*v[i];
}
printf("内積=%f\n", ip);
ch = getchar();
ch = getchar();
return 0;
}
変数 u, v は,浮動小数
を要素とする配列で,
サイズは
v
0
1
2
4.6
5.5
6.4
u
0
1
2
1.9
2.8
3.7
メモリ確保および初期化が行われる。
40
for (i=0; i<3; i++) {
ip = ip + u[i]*v[i];
}
v
0
1
2
4.6
5.5
6.4
u
0
1
2
1.9
2.8
3.7
ip
0
i
0
0 + 1.9 * 4.6
i = 0 のときは
ip + u[0]*v[0]
i = 0, 1, 2 での繰り返し
(3回繰り返し)
最初は i = 0
41
for (i=0; i<3; i++) {
ip = ip + u[i]*v[i];
}
v
0
1
2
4.6
5.5
6.4
u
0
1
2
1.9
2.8
3.7
ip
8.74
i
1
8.74 + 2.8 * 5.5
i = 1 のときは
ip + u[1]*v[1]
i = 0, 1, 2 での繰り返し
(3回繰り返し)
次は i = 1
42
for (i=0; i<3; i++) {
ip = ip + u[i]*v[i];
}
v
0
1
2
4.6
5.5
6.4
u
0
1
2
1.9
2.8
3.7
ip
24.14
i
2
24.14 + 3.7 * 6.4
i = 2 のときは
ip + u[2]*v[2]
i = 0, 1, 2 での繰り返し
(3回繰り返し)
次は i = 2
43
ベクトルの内積
繰り返し
1回目 i = 0i < 3 が成り立つ ip = ip + u[0] * v[0];
繰り返し
2回目
繰り返し
3回目
繰り返し
4回目
i = 1i < 3 が成り立つ ip = ip + u[1] * v[1];
i = 2i < 3 が成り立つ ip = ip + u[2] * v[2];
i = 3 i < 3 が成り立たない
i の値 繰り返し条件式
が成り立つか ip の値
つまり ip の値は u[0]*v[0]
つまり ip の値は u[0]*v[0] + u[1]*v[1]
つまり ip の値は u[0]*v[0] + u[1]*v[1]
+u[2]*v[2]
for (i=0; i<3; i++) {
ip = ip + u[i]*v[i];
}
44
配列の使い方
添字をつけて、普通の変数のよに使
int a[3];
a[0] = i;
a[1] = 5;
fscanf(“%d”,&a[2]);
j = a[2];
printf(“%d %d\n”,a[0],a[1]);
配列 a
0
1
2
添字
a[0]
a[1]
a[2]
45
次のプログラムを実行してみなさい
#include "stdafx.h"
#include <math.h>
int _tmain()
{
int i;
double ip = 0.0;
double u[]={1.9, 2.8, 3.7};
double v[]={4.6, 5.5, 6.4};
int ch;
for (i=0; i<3; i++) {
ip = ip + u[i]*v[i];
}
printf("内積=%f\n", ip);
ch = getchar();
ch = getchar();
return 0;
}各自で行ってください(実行結果の確認まで)
終わったら,例題3を各自で行ってください
46
例題3.棒グラフを描
整数の配列から,その棒グラフを表示
するプログラムを作る.
ループの入れ子で,棒グラフの表示を
47
例題3:棒グラフ
#include "stdafx.h"
#include <math.h>
int _tmain()
{
int i;
int j;
int ch;
int a[]={6,4,7,1,5,3,2};
for (i=0; i<7; i++) {
for (j=0; j<a[i]; j++) {
printf("*");
}
printf("\n");
}
ch = getchar();
ch = getchar();
return 0;
}
配列の宣言
配列からの
読み出し
48
棒グラフを書く
実行結果の例
******
****
*******
*
*****
***
**
49
多重ループ
ループを入れ子構造にする
外側のループ
内側のループ
for (i=0 ; i < n ;i++)
{
}
for (j=0 ; j < m ;j++)
{
}
i j
0 0
0 1
0 2
0 m-1
1 0
1 1
1 2
1 m-1
n-1 m-1
i=0
i=1
i=n-1