1
Cプログラミング演習
第8回 構造体とレコードデータファイ
2
例題1.バイナリファイル形式
ファイルからのデータ読み込み
次のよ名簿ファイル(バイナリファイル形
式)を読み込んで,画面に表示するプログラム
を作る
名簿ファイル
name age address
Ken 20 NewYork
Bill 32 HongKong
Mike 35 Paris
3
#include "stdafx.h"
#include <math.h>
#pragma warning(disable:4996)
struct Person {
char name[20];
int age;
char address[20];
};
int _tmain()
{const int max_lines = 100;
const char file_name[] = "z:\\PersonData.bin";
struct Person a[max_lines];
FILE *fp;
int n;
int i;
int ch;
// ータファイル読み込み
fp = fopen( file_name, "r" );
if ( fp == NULL ) {
fprintf( stderr, " %s プンまし" );
return -1;
}
n = 0;
while( 1 ) {
if ( ( fread( &(a[n]), sizeof(struct Person), 1, fp ) == 0 )
|| ( n >= max_lines ) ) {
break;
}
n = n + 1;
}
fclose( fp );
// 画面表示
for( i=0; i<n; i++ ) {
printf( "name: %s, age: %d, address: %s\n",
a[i].name, a[i].age, a[i].address );
}
printf( "Enter キーを1,2回押してください. プログラムを終了します\n");
ch = getchar();
ch = getchar();
return 0;
}
この fread はバイナリファイル形式のファイルを読み出す
4
ビルド後の画面
ビルドが正常終了したことを示
すメッセージ
ビルドの手順:
「ビルド」「○○のビルド」
「1.正常終了」を確認
5
実行中の画面
実行の手順:
「デバッグ」
「実行」
実行ウインドウが現れる
6
実行結果の例
7
例題1のプログラムが
行っていること
データファイル
(バイナリファイル形式)
プログラムが使う
メモリ空間
fread
読み出し
fread
3回実行
読み出しが終わったら
実行ウインドウに表示
例題1では
人分のデータ
8
name age address
Ken 20 NewYork
Bill 32 HongKong
Mike 35 Paris
name age address
Ken 20 NewYork
Bill 32 HongKong
Mike 35 Paris
name, age, address の3つの「メンバ」から構成される
構造体 Person の配列 a
a[0]
a[1]
a[2]
つの
ファイル
132バイト)
9
int _tmain()
{const int max_lines = 100;
const char file_name[] = "z:\\PersonData.bin";
struct Person a[max_lines];
FILE *fp;
int n;
int i;
int ch;
// データファイル読み込
fp = fopen( file_name, "r" );
if ( fp == NULL ) {
fprintf( stderr, " %s プン失敗まし" );
return -1;
}
n = 0;
while( 1 ) {
if ( ( fread( &(a[n]), sizeof(struct Person), 1, fp ) == 0 )
|| ( n >= max_lines ) ) {
break;
}
n = n + 1;
}
fclose( fp );
// 画面表示
for( i=0; i<n; i++ ) {
printf( "name: %s, age: %d, address: %s\n",
a[i].name, a[i].age, a[i].address );
}
printf( "Enter キーを1,2回押てください. プログラム終了します\n");
ch = getchar();
ch = getchar();
return 0;
}
#include "stdafx.h"
#include <math.h>
#pragma warning(disable:4996)
struct Person {
char name[20];
int age;
char address[20];
};
この fread はバイナリファイル形式のファイルを読み出す
Person構造体を, 1度に1つ
10
実際のメモリの中身
元々のファイルサイズ: 132バイト
実メモリでのサイズ: 132バイト
name age address
Ken 20 NewYork
Bill 32 HongKong
Mike 35 Paris
バイナリファイル形式性質
11
実際のメモリの中身
元々のファイルサイズ: 132バイト
実メモリでのサイズ: 132バイト
name age address
Ken 20 NewYork
Bill 32 HongKong
Mike 35 Paris
バイナリファイル形式の性質
a[0]
a[1]
a[2]
a[3]
a[4]
12
int _tmain()
{const int max_lines = 100;
const char file_name[] = "z:\\PersonData.bin";
struct Person a[max_lines];
FILE *fp;
int n;
int i;
int ch;
// データファイル読み込み
fp = fopen( file_name, "r" );
if ( fp == NULL ) {
fprintf( stderr, "ファイル %s オープンに失敗しました" );
return -1;
}
n = 0;
while( 1 ) {
if ( ( fread( &(a[n]), sizeof(struct Person), 1, fp ) == 0 )
|| ( n >= max_lines ) ) {
break;
}
n = n + 1;
}
fclose( fp );
// 画面表示
for( i=0; i<n; i++ ) {
printf( "name: %s, age: %d, address: %s\n",
a[i].name, a[i].age, a[i].address );
}
printf( "Enter キーを1,2回押してください. プログラムを終了します\n");
ch = getchar();
ch = getchar();
return 0;
}
#include "stdafx.h"
#include <math.h>
#pragma warning(disable:4996)
struct Person {
char name[20];
int age;
char address[20];
};
構造体 Person の定義(説明は後述
13
int _tmain()
{const int max_lines = 100;
const char file_name[] = "z:\\PersonData.bin";
struct Person a[max_lines];
FILE *fp;
int n;
int i;
int ch;
// データファイル読み込
fp = fopen( file_name, "r" );
if ( fp == NULL ) {
fprintf( stderr, "ファイル %s オープン失敗ました" );
return -1;
}
n = 0;
while( 1 ) {
if ( ( fread( &(a[n]), sizeof(struct Person), 1, fp ) == 0 )
|| ( n >= max_lines ) ) {
break;
}
n = n + 1;
}
fclose( fp );
// 画面表示
for( i=0; i<n; i++ ) {
printf( "name: %s, age: %d, address: %s\n",
a[i].name, a[i].age, a[i].address );
}
printf( "Enter キーを1,2回押てください. プログラム終了します\n");
ch = getchar();
ch = getchar();
return 0;
}
#include "stdafx.h"
#include <math.h>
#pragma warning(disable:4996)
struct Person {
char name[20];
int age;
char address[20];
};
構造体 Person の定義(説明は後述)
14
#pragma warning(disable:4996)
int _tmain()
{const int max_lines = 100;
const char file_name[] = "z:\\PersonData.bin";
struct Person a[max_lines];
FILE *fp;
int n;
int i;
int ch;
// データファイル読み込
fp = fopen( file_name, "r" );
if ( fp == NULL ) {
fprintf( stderr, "ァイ %s のオープンに失敗しまし" );
return -1;
}
n = 0;
while( 1 ) {
if ( ( fread( &(a[n]), sizeof(struct Person), 1, fp ) == 0 )
|| ( n >= max_lines ) ) {
break;
}
n = n + 1;
}
fclose( fp );
// 画面表示
for( i=0; i<n; i++ ) {
printf( "name: %s, age: %d, address: %s\n",
a[i].name, a[i].age, a[i].address );
}
printf( "Enter キーを1,2回押してください. プログラムを終了しま\n");
ch = getchar();
ch = getchar();
return 0;
}
ファイルオープンに失敗した
ときのみ実行される部分
ファイルオープンに失敗したら,
プログラムが終わる
15
#pragma warning(disable:4996)
int _tmain()
{const int max_lines = 100;
const char file_name[] = "z:\\PersonData.bin";
struct Person a[max_lines];
FILE *fp;
int n;
int i;
int ch;
// データファイル読み込み
fp = fopen( file_name, "r" );
if ( fp == NULL ) {
fprintf( stderr, "ファイル %s のオープンに失敗しました" );
return -1;
}
n = 0;
while( 1 ) {
if ( ( fread( &(a[n]), sizeof(struct Person), 1, fp ) == 0 )
|| ( n >= max_lines ) ) {
break;
}
n = n + 1;
}
fclose( fp );
// 画面表示
for( i=0; i<n; i++ ) {
printf( "name: %s, age: %d, address: %s\n",
a[i].name, a[i].age, a[i].address );
}
printf( "Enter キーを1,2. ムを了しま\n");
ch = getchar();
ch = getchar();
return 0;
}
while による繰り返し部分
while ( 1 ) , 無条件に繰り返す
という意味になる
(「1」が,常に成り立つ条件式の意味)
この「break;」は,while による繰り返し処理
から抜け出すという意味になる.
if 文の条件が成り立ったときにのみ実行される)
fread は,バイナリファイル形式での読み出し
16
#pragma warning(disable:4996)
int _tmain()
{const int max_lines = 100;
const char file_name[] = z:\\PersonData.bin";
struct Person a[max_lines];
FILE *fp;
int n;
int i;
int ch;
// データファイル読み込
fp = fopen( file_name, "r" );
if ( fp == NULL ) {
fprintf( stderr, "ファイル %s 失敗" );
return -1;
}
n = 0;
while( 1 ) {
if ( ( fread( &(a[n]), sizeof(struct Person), 1, fp ) == 0 )
|| ( n >= max_lines ) ) {
break;
}
n = n + 1;
}
fclose( fp );
// 画面表示
for( i=0; i<n; i++ ) {
printf( "name: %s, age: %d, address: %s\n",
a[i].name, a[i].age, a[i].address );
}
printf( "Enter キーを1,2回押してください. プログラムを終了します\n");
ch = getchar();
ch = getchar();
return 0;
}
変数 max_lines の値は 100
サイズ 100 の配列
fread の結果,1倍とも読み出さ
れなかった(ファイルの終わりが
来たなどの理由)
|| は,「または」の意味 すでに, 100回読み
込みを終えた
n の値は,読み込ん
回数と等しくなる
17
#pragma warning(disable:4996)
int _tmain()
{const int max_lines = 100;
const char file_name[] = "z:\\PersonData.bin";
struct Person a[max_lines];
FILE *fp;
int n;
int i;
int ch;
// データファイル読み込
fp = fopen( file_name, "r" );
if ( fp == NULL ) {
fprintf( stderr, "ファイル %s のオープンに失敗しました" );
return -1;
}
n = 0;
while( 1 ) {
if ( ( fread( &(a[n]), sizeof(struct Person), 1, fp ) == 0 )
|| ( n >= max_lines ) ) {
break;
}
n = n + 1;
}
fclose( fp );
// 画面表示
for( i=0; i<n; i++ ) {
printf( "name: %s, age: %d, address: %s\n",
a[i].name, a[i].age, a[i].address );
}
printf( "Enter キーを1,2回押してくださ. プログラムを終了しま\n");
ch = getchar();
ch = getchar();
return 0;
}
for による繰り返し部分
18
#pragma warning(disable:4996)
int _tmain()
{const int max_lines = 100;
const char file_name[] = "z:\\PersonData.bin";
struct Person a[max_lines];
FILE *fp;
int n;
int i;
int ch;
// データファイル読み込み
fp = fopen( file_name, "r" );
if ( fp == NULL ) {
fprintf( stderr, "ファイル %s のオープンに失敗しました" );
return -1;
}
n = 0;
while( 1 ) {
if ( ( fread( &(a[n]), sizeof(struct Person), 1, fp ) == 0 )
|| ( n >= max_lines ) ) {
break;
}
n = n + 1;
}
fclose( fp );
// 画面表示
for( i=0; i<n; i++ ) {
printf( "name: %s, age: %d, address: %s\n",
a[i].name, a[i].age, a[i].address );
}
printf( "Enter キーを1,2回押してください. プログラムを終了しま\n");
ch = getchar();
ch = getchar();
return 0;
}
for による繰り返し部分
n 回の繰り返し
19
配列とメモリアドレス
配列 a
(サイズは100
a[0]
a[1]
a[2]
メモリアドレス
0012ED80
0012EDAC
0012EDD8
プログラムが使う
メモリ空間
構造体の配列
20
構造体struct
データの集合を一つのデータ型として
仕組み。新たな型名を付けて登録
することができる。
構造体の要素メンバと呼び、それぞ
れに型を指定し、名前を付ける。
構造体のメンバとして他の構造体を含
むことが許される。特に、同じ構造体
をメンバとするもの(再帰的構造
も許される。
21
構造体の例(非再帰的
name
age
address
例題1の
構造体
これで1つの
データ
22
演算子 .の意味
構造体のメンバを指定
例題1では
a[i].name
a[i].age
a[i].address
23
演算子 -> の意味
ポインタの指す構造のメンバを指定
z->re_part = x;
zstruct complex なる構造体を指すポイ
ンタ
であるとして、
そのメンバ re_part xの値を代入。
24
例題2.構造体データの
メモリ配置を見る
下記の構造体 ImaginaryNumber につい
て,メモリアドレスを表示してみる
1つの構造体は 16 バイト
real_part imaginary_part
3.1 -2.4
4.5 5.1
-2.4 6.3
8バイト 8バイト
25
#include "stdafx.h"
#include <math.h>
struct ImaginaryNumber {
double real_part;
double imaginary_part;
};
int _tmain()
{
struct ImaginaryNumber a[] = {{3.1, -2.4},
{4.5, 5.1},
{-2.4, 6.3}};
int i;
int ch;
for (i=0; i<3; i++ ) {
printf( "複素数 %3.1f + %3.1f i\n", a[i].real_part,
a[i].imaginary_part );
}
for (i=0; i<3; i++ ) {
printf( "address(a[%d]) = %p\n", i, &(a[i]) );
}
printf( "Enter キーを1,2回押してください. プログラムを終了します\n");
ch = getchar();
ch = getchar();
return 0;
}
&」はメモリアドレス
の取得
%p」はメモリアドレス
の表示
%3.1f」は, 小数点以上は最大3桁,
小数点以下は最大1桁の表示
各自で行ってください(実行結果の確認まで)
a[0] 3.1, -2.4
a[1] 4.5, 5.1
a[2] -2.4, 6.3 をセット
26
メモリアドレス表示
実行結果の例
表示された
メモリアドレ*
メモリアドレスの値が
ここでの「例」と違っている
ことはある(動作は正しい)
27
配列とメモリアドレス
配列 a
(サイズは3)
a[0]
a[1]
a[2]
メモリアドレス
0012FEA8
0012FEB8
0012FEC8
プログラムが使う
メモリ空間
構造体の配列
3.1 -2.4
4.5 5.1
-2.4 6.3
28
実際のメモリの中身
double 型の変数は
8 バイトになっている メモリアドレスの値が
ここでの「例」と違っている
ことはある
29
#include "stdafx.h"
#include <math.h>
struct ImaginaryNumber {
double real_part;
double imaginary_part;
};
int _tmain()
{
struct ImaginaryNumber a[] = {{3.1, -2.4},
{4.5, 5.1},
{-2.4, 6.3}};
int i;
int ch;
for (i=0; i<3; i++ ) {
printf( "複素数 %3.1f + %3.1f i\n", a[i].real_part,
a[i].imaginary_part );
}
for (i=0; i<3; i++ ) {
printf( "address(a[%d]) = %p\n", i, &(a[i]) );
}
printf( "Enter キーを1,2回押してください. プログラムを終了します\n");
ch = getchar();
ch = getchar();
return 0;
}
構造体 ImaginaryNumber
の型宣言
構造体の配列 a
の宣言と初期化
構造体のメンバ
30
構造体の型宣言
構造体には名前がある
それぞれのデータ(メンバとい)は
(データの種類のこと)がある.
struct Person {
char name[20];
int age;
char address[20];
};
名前
メンバ
31
参考.バイナリファイル形式の
ファイル読み出し,書き込み
最初にファイルの書き込みを行い,次に,書
き込んだファイルの読み出しを行プログラ
練習用の見本として示す
32
データファイル
(バイナリファイル形式)
プログラムが使う
メモリ空間
fwrite
書き込み
fwrite
3回実行
3人分のデータを
書き込む
変数 orig
最初は書き込み
33
データファイル
(バイナリファイル形式)
プログラムが使う
メモリ空間
fread
読み出し
例題1では
3人分のデータを書き込む
変数 a
次は読み出し
34
#include "stdafx.h"
#include "stdafx.h"
#include <math.h>
#pragma warning(disable:4996)
struct Person {
char name[20];
int age;
char address[20];
};
int _tmain()
{const int max_lines = 100;
const char file_name[] = "z:\\PersonData.bin";
struct Person a[max_lines];
FILE *fp;
int n;
int i;
int ch;
struct Person orig[3] = { {"kaneko", 38, "hazozaki"}, {"ken",
20, "kaizuka"}, {"mike", 30, "tenjin" } };
printf( "書きます.ファイル名は %s\n", file_name );
// データファイル書き込み
fp = fopen( file_name, "w" );
if ( fp == NULL ) {
fprintf( stderr, "ファイル %s のオープンに失敗しました" );
return -1;
}
// 書き出すのは3個(i = 0, 1, 2)
for ( i = 0; i < 3; i++ ) {
fwrite( &(orig[i]), sizeof(struct Person), 1, fp );
}
fclose( fp );
printf( "みます.ファイル名は %s\n", file_name );
// データファイル読み出し
fp = fopen( file_name, "r" );
if ( fp == NULL ) {
fprintf( stderr, "ファイル %s のオープンに失敗しました" );
return -1;
}
n = 0;
while( 1 ) {
if ( ( fread( &(a[n]), sizeof(struct Person), 1, fp ) == 0 )
|| ( n >= max_lines ) ) {
break;
}
n = n + 1;
}
fclose( fp );
// 画面表示
for( i=0; i<n; i++ ) {
printf( "name: %s, age: %d, address: %s\n",
a[i].name, a[i].age, a[i].address );
}
printf( "Enter キーを1,2回押してくださ. プログラムを終了します\n");
ch = getchar();
ch = getchar();
return 0;
}
最初は書き込み
次は読み出し
35
例題3.Windows ビットマッ
プファイルの読み出し,書き込
24ビットカラーの Windows ビットマップ
ファイルについて,簡単な計算を行ってみる
36
実行結果の例
z:\Mandrill.bmp z:\done.bmp
新しく生成されるファイル
37
画素の r, g, b
r'(x, y) = | r(x,y) - r(x-1, y) |
g'(x, y) = | g(x,y) - g(x-1, y) |
b'(x, y) = | b(x,y) - b(x-1, y) |
x > 0 に対し
r'(x, y) = 0
g'(x, y) = 0
b'(x, y) = 0
x = 0 に対して
横方向の差分
(差分の量が大きい
ほど,画素は「明るく」
なる)
38
例題3のプログラムが
行っていること
Windows ビットマップ
ファイル
プログラムが使う
メモリ空間
fread
3回実行
ファイルヘッダ
ヘッダ
本体
39
例題3のプログラムが
行っていること
Windows ビットマップ
ファイル
プログラムが使う
メモリ空間
ファイルヘッダ
ヘッダ
本体
計算
40
例題3のプログラムが
行っていること
Windows ビットマップ
ファイル
プログラムが使う
メモリ空間
ファイルヘッダ
ヘッダ
本体
41
画像本体の実メモリ上での配
24ビットカラーの Windows ビットマップ
実メモリ上では,バイト列のデータ
42
画像本体の実メモリ上での
24ビットカラーの Windows ビットマップ
実メモリ上では,バイト列のデータ
画素 (x,y) のデータは,先頭から 3xy バイト目にある
43
画像本体の実メモリ上での
24ビットカラーの Windows ビットマップ
ファイルヘッダ
ヘッダ
typedef struct tagBITMAPFILEHEADER {
unsigned short bfType;
unsigned long bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned long bfOffBits;
} BITMAPFILEHEADER
typedef struct tagBITMAPINFOHEADER{
unsigned long biSize;
long biWidth;
long biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned long biCompression;
unsigned long biSizeImage;
long biXPixPerMeter;
long biYPixPerMeter;
unsigned long biClrUsed;
unsigned long biClrImporant;
} BITMAPINFOHEADER;