Document

プログラミング入門2
ファイルの入出力
ポインタ
芝浦工業大学情報工学科
青木 義満
前回演習問題,課題についての注意事項
 演算の優先順位について
radian = acos(naiseki/p1*p2);
naiseki = x1*x2 + y1*y2;
p1 = sqrt(x1*x1+y1*y1);
p2 = sqrt(x2*x2+y2*y2);
naiseki
* p2
p1
()を使って計算の
優先順位を決める
radian = acos(naiseki/(p1*p2)); naiseki
p1 * p2
 配列の要素数について
int num;
char name[num][128];
printf(“人数を入力してください:”);
scanf(“%d”, &num);
コンパイルエラー
重要
配列の要素数に変数は使用できない。
定数のみ使用可能
(直接数字を書くか,#defineで定数を定義するか)
※必要なサイズの配列を動的に確保することも可能
alloc, malloc関数
プログラミング入門2
2
今回の講義内容
 ファイル入出力


ファイルからのデータ読込み
ファイルと配列
 ポインタ

ポインタの基本
プログラミング入門2
3
ファイルへのデータ書き込み(復習)
 ソースファイル名:fileio1.c
 データをファイルに書き込み
#include <stdio.h>
100 morishima 95.5
int main(void)
ファイルポインタ宣言
{
FILE *fp;
int student_id = 100;
char name[ ]= "morishima";
ファイルに書き込むデータ
double tensu = 95.5;
fp = fopen("test.txt","w");
“test.txt”という名前でファイルをオープン
(書き込み用)
fprintf( fp, "%d\n", student_id );
fprintf( fp, "%s\n", name );
fprintf( fp, "%f\n", tensu );
データをファイルに書き込み
fprintf( fp, "%d %s %f\n", student_id, name, tensu );
fprintf( fp, "%d\t%s\t%f\n", student_id, name, tensu );
fclose(fp);
ファイルを閉じる
return(0);
}
プログラミング入門2
4
ファイルからのデータの読込みの必要性
 ファイルに格納されているデータを,プログラム中に
読み込んで処理
プログラム~xxx.c
ファイル~成績表リスト
1
aoki
80.5
100 morishima 95.5
50
tokunaga 70.4
・・・・・・
・・・・・・
・・・・・
・・・・・
int student_id[NUMBER];
char name[NUMBER][256];
double score[NUMBER];
・・・・・・・・・・・
・・・・・・・・・・
・・・・・・・・・・
・・・・・・・・・・
プログラミング入門2
5
データの作成(野球選手成績リスト)
 ソースファイル名:player1.c
 チーム名,選手名,ホームラン数をファイルに書き込み
#include <stdio.h>
#define NUM 100 /* 最大100人までの選手データを扱う */
for(i=0; i < 5; i++){
/* 読み込んだデータを画面表示 */
printf( "%s %s %d\n", team[i], name[i], hr[i]);
/* 読み込んだデータをファイルへ書き込み */
fprintf( fp, "%s %s %d\n", team[i], name[i], hr[i]);
int main(void)
{
FILE *fp;
char team[NUM][256];
char name[NUM][256];
int hr[NUM];
int i;
}
fclose(fp);
return(0);
fp = fopen("player.txt","w");
}
/* キーボードから選手データを読込み */
for(i=0; i < 5; i++){
printf("Input Players' Data\n");
printf("Team : ");
scanf("%s", team[i]);
printf("name : ");
scanf("%s", name[i]);
printf("Homerun : ");
scanf("%d", &hr[i]);
}
player.txt
G
Matsui 50
L
Matsui 33
D
Fukudome 20
・・・・・・
・・・・・・
・・・・・
・・・・・
プログラミング入門2
6
ファイルからのデータの読み込み
 ファイルからデータを読み込む際の手順


ファイルを開く (読込みモードで)
変数へのデータの読込み


fscanf関数等を使用
ファイルを閉じる
プログラミング入門2
7
ファイルを開く ~ fopen関数
 データを読み込む対象の ”ファイル名” を指定
 読み込みモードを指定(2つ目の引数に”r”を指定)
読み込みモードでファイルを開く操作
FILE *fp
FILE *fp;
(ファイルポインタ)
fp = fopen( “file.txt”, “r” );
ファイルを指定
file.txt
(ファイル)
読込みモード
ファイル名
fp を介して,ファイルにアクセスが可能!
プログラミング入門2
8
ファイルを開く際のモードの種類 (テキストファイル)
モード
意味
“r”
読込み用にファイルを開く。ファイルが存在しない場合や
見つからない場合は失敗する。
“w”
書き込み用にファイルを作成。ファイルが存在する場合は
そのファイルの内容は破棄する。
“a”
追加書き込みのために既存ファイルを開く。ファイルが存
在しない場合には作成する。
“r+”
読み書き用にファイルを開く。ファイルは存在していなけ
ればならない。
“w+”
読み書き用にファイルを作成。ファイルが存在する場合に
は,そのファイルの内容は破棄する。
“a+”
読込みと追加の両方のモードでファイルを開く。ファイル
が存在しない場合は作成する。
プログラミング入門2
9
ファイルからのデータの読込み
~ fscanf関数
 scanf関数(キーボードからのデータ入力)
→ fscanf関数(fileからのデータ入力)
 fscanf関数の書式

fp = fopen( “file.txt”, “r” );
file.txt
scanf関数
100
scanf( “%d”, &x);

fscanf関数
fscanf( fp, “%d”, x );
fscanf
プログラム中の変数
データを読み込む対象の
のファイル(ポインタ)
int x
プログラミング入門2
10
fscanf関数の使用例
 実数データの読み込み
ファイル:fscanf( fp, “%lf”, x );
double x
 文字列データの読込み
文字配列1つ: char name[256] ← fscanf( fp, “%s”, str );
複数の文字配列: char name[5][256] ← fscanf( fp, “%s”, str[i] );
 1行に並んでいる複数の型のデータを読み込み
fscanf( fp, “%d %s %f”, student_id, name, tensu );
file
1
aoki
80.5
char name[ 256] ;
int student_id;
double tensu;
プログラミング入門2
11
ファイルを閉じる
 使い終わったら,後片付け



ファイルを閉じる
ファイルを開く時に指定したファイルポインタを指定
fclose(fp);
プログラミング入門2
12
ファイルからのデータの読込み 例題
 ソースファイル名:player2.c
 データをファイルから読み込み,変数に格納, 表示
for(i=0; i < 5; i++){
/* 読み込んだデータを画面表示 */
printf( "%s\t%s\t%d\n", team[i], name[i], hr[i]);
}
#include <stdio.h>
#define NUM 100
int main(void)
{
FILE *fp;
char team[NUM][256];
char name[NUM][256];
int
hr[NUM];
int
i;
fp = fopen("player.txt","r");
fclose(fp);
return(0);
}
読込みモードで
ファイルをオープン
/* ファイルから選手データを読込み */
for(i=0; i < 5; i++){
fscanf(fp, "%s %s %d", team[i], name[i], &hr[i]);
}
プログラミング入門2
13
入出力ファイル名の指定
 これまでのプログラム

入出力ファイル名をプログラム中で指定
fp = fopen("player.txt","r");
キーボードからファイル名を指定できれば便利!
 ファイル名の指定
char
filename[256];
printf(“input filename : ”);
scanf( “%s”, filename );
fp = fopen( filename, “r” );
プログラミング入門2
14
入出力ファイル名の指定 例題
 ソースファイル名:filename.c
 ファイル名を指定して開く
#include <stdio.h>
int main(void)
{
FILE *fp;
char filename[256];
ファイル名格納用変数
printf( "Input file name : " );
scanf( "%s", filename );
fp = fopen(filename, "r");
キーボードから入力した文字列を
filenameに格納
Filenameでファイル名を指定して開く
printf("ファイル名は%sです", filename);
/* ファイルからのデータ読込み */
/* データ処理 */
return(0);
}
指定したファイルが存在しなかったら?
プログラミング入門2
15
ファイルが開けるかどうかのチェック
 fopen関数 の仕様
fp = fopen(filename, "r");
ファイル”filename”が存在し,開ける場合
fpにそのファイルを指定するファイルポインタを格納
(fpには,そのファイルを指定可能にするための何らかの値が入る)
ファイル”filename”が存在しない,開けない場合
fpにはNULL(空)が代入される
 ファイルが開けるかどうかの判定
fp = fopen(filename, “r”)
== NULL
== それ以外の値
if文を使って判定
プログラミング入門2
16
ファイルが開けるかどうかのチェック 例題
ソースファイル名: filecheck.c
 指定したファイルが開けるかどうかを判定

#include <stdio.h>
#include <stdlib.h>
ヘッダーを追加(exit関数使用のため)
int main(void)
{
FILE *fp;
char filename[256];
printf( "Input file name : " );
scanf( "%s", filename );
フ
ァ
イ
ル
が
開
け
る
か
ど
う
か
の
判
定
if( (fp = fopen(filename, "r") ) == NULL ){
printf("指定したファイル%sは開けません\n", filename);
printf("プログラムを終了します\n");
exit(1);
プログラムを終了
}
else{
printf( "file open成功!\n" );
printf( "ファイル名は%sです", filename );
}
fp=NULL,
ファイルが開けなかった場合
fp != NULL : ファイルが開けた場合
/* ファイルからのデータ読込み,データ処理 */
return(0);
}
プログラミング入門2
17
ポインタ
ポインタ
 C言語の理解を妨げる難敵の一つ
 更にプログラミングの勉強を進めるためには,
超えなければならない壁
 理解できれば,C言語の機能をフルに活用できるようになる
 これまで,流して説明してきた部分を理解できる




scanf関数でなぜ変数に&をつけるの?
文字列をscanfで読み込む場合にはなぜ&が不要?
関数に配列を渡すとき,どうして配列名だけを書いて渡すの?
ファイルポインタとは?
その他
変数のメモリ空間上での振舞いを意識!
プログラミング入門2
19
ポインタ
の必要性
 ソースファイル名: list1001.c (p.226)
 2つの整数の和と差を求める関数(間違い)
#include <stdio.h>
void sum_diff(int n1, int n2, int sum, int diff)
{
sum = n1 + n2;
diff = n1 - n2;
}
int main(void)
{
int na, nb;
int wa = 0, sa = 0;
puts("二つの整数を入力してください。");
printf("整数A:");
scanf("%d", &na);
printf("整数B:");
scanf("%d", &nb);
sum_diff(na, nb, wa, sa);
printf("wa = %d\n", wa);
printf("sa = %d\n", sa);
return (0);
和と差の値は表示されない!
どうして?
}
プログラミング入門2
20
関数呼び出しと引数の引渡し過程(復習)
main関数
int main(void)
重要
{
int na, nb;
実引数の値が,仮引数にそれぞれ
コピーされる
int sa=0, wa=0;
na = 10;
(変数そのものでなく,中に格納されている値
が受け渡される!)
nb = 20;
実引数
sum_diff( na, nb, wa, sa );
10
20
0
0
仮引数
printf("wa = %d\n", wa);
printf("sa = %d\n", sa);
void sum_diff( int n1, int n2, int sum, int diff )
{
}
sum = n1 + n2;
Main文のwa, saの値は
書き換えられない!
diff = n1 – n2;
この関数内では,sumは30,
diffは-10となるが。。。
}
解決にはポインタが必要!
プログラミング入門2
21
変数 と オブジェクト
(p.227)
 変数の型とオブジェクト
型
オブジェクト
型
オブジェクト
int
m;
double
x;
int 型
m
double型
x
 設計図と実体
設計図
実体
型は設計図,オブジェクトは設計図に基づいて作られた実体
プログラミング入門2
22
論理的なオブジェクトと物理的なオブジェクト
 変数(オブジェクト)は,記憶域(メモリ)中の一部を占める箱
int
m;
double x;
イメージ
現実
オブジェクトは独立した個別の箱
オブジェクトは記憶域中の一部を占有する箱
1000番地
m
m
x
1008番地
メ
モ
リ
空
間
x
論理的なオブジェクトの概念
アドレス(番地)
物理的なオブジェクトの概念
プログラミング入門2
23
アドレスとは?
 オブジェクトのアドレス
オブジェクト(実体)が格納されているメモリ上の
番地のこと
 プログラム中で変数を宣言
コンピュータのメモリ内にある場所(アドレス)に,
ある大きさの領域を確保すること

プログラミング入門2
24
アドレスを表示
 ソースファイル名: list1002.c (p.228)
 オブジェクトのアドレスを表示
#include <stdio.h>
int main(void)
{
int
double
int
nx;
dx;
vc[3];
printf("nxのアドレス:%p\n", &nx);
printf("dxのアドレス:%p\n", &dx);
printf("vc[0]のアドレス:%p\n", &vc[0]);
printf("vc[1]のアドレス:%p\n", &vc[1]);
printf("vc[2]のアドレス:%p\n", &vc[2]);
return (0);
}
プログラミング入門2
25
アドレス演算子(&)
 オブジェクトの頭に&をつけると,そのオブジェクトの格納されてい
るアドレスを取り出すことが可能
 アドレスをprintfで表示するための変換指定は%p
int
m;
double x;
&m
1000番地
&x
m
1008番地
メ
モ
リ
空
間
x
アドレス(番地)
printf("nxのアドレス:%p\n", &nx);
プログラミング入門2
nxのアドレスを16進数で表示
26
ポインタとは?
 ポインタ変数

オブジェクトのアドレス(メモリ上の位置)を格納する
ためのもの
 ポインタの宣言
int nx;
int
*p;
int型 : 整数の値を格納するための変数nx
int型のオブジェクトのアドレスを格納する
ポインタ変数pを宣言
ポインタ変数pの型は? → 「int *」型,int型オブジェクトへのポインタ型
プログラミング入門2
27
最初のポインタ・プログラム
 ソースファイル名:pointer1.c
 整数の値とポインタの値を表示
#include <stdio.h>
int main(void)
{
int nx;
int *pt;
int型オブジェクトのアドレスを格納するための
int型へのポインタ型=(int *)型
nx = 57;
pt = &nx;
printf("nxの値:%d\n", nx);
printf("nxのアドレス:%p\n", &nx);
printf("ptの値:%p\n", pt);
return (0);
表示される値を確認!
}
プログラミング入門2
28
プログラムの解説
int
int
nx;
*pt;
57
メモリ上の番地
1000番地
nx
=
nx = 57;
pt = &nx;
&nx
代入
pt
nxのアドレス
int *型 = int型のアドレスを格納するための変数
printf("nxの値:%d\n", nx);
printf("nxのアドレス:%p\n", &nx);
printf("ptの値:%p\n", pt);
プログラミング入門2
57
同じアドレスを示す
29
int型とintへのポインタ型
int *型
int型
int
nx;
int
nx
*pt;
pt
その値は整数を格納する
オブジェクトのアドレス
その値は整数
&nx は(int *)型
pt (int *)型
プログラミング入門2
30
ポインタがオブジェクトを「指す」
 ポインタptの値がオブジェクトnxのアドレスであるとき,
pt は nx を指す
という。
57
メモリ上の番地
int nx;
int *pt;
pt = &nx;
1000番地
=
nx
&nx
代入
nxのアドレス
pt
ptにはオブジェクトnxのアドレスが格納されているので,
ptはnxを指している といえる。
プログラミング入門2
31
間接演算子
 ソースファイル名:pointer2.c
 ポインタが指すオブジェクトの値を表示
#include <stdio.h>
int main(void)
{
int nx;
int *pt;
nx = 57;
pt = &nx;
ptに,int型の変数nxのアドレスを代入
pt は nx を指す
printf( "nxのアドレス:%p\n", &nx);
printf( "nxの値:%d\n", nx );
printf( "ptの値:%p\n", pt );
printf( "*ptの値:%d\n", *pt );
return(0);
}
プログラミング入門2
32
ポインタとエイリアス(別名)
int nx;
int *pt;
nx = 57;
pt = &nx;
pt は x を指す
*pt はptが指すオブジェクトの
エイリアス(別名)
x
x
pt
*pt
pt
*ptはxの別名(エイリアス)
重要
ポインタpがオブジェクトxを指すとき,*pはxのエイリアス(別名)となる
プログラミング入門2
33
ポインタが指すオブジェクトへの代入


ソースファイル名:pointer3.c
ポインタを介して,オブジェクトの値を変更
#include <stdio.h>
int main(void)
{
int nx, ny;
int *pt;
*ptはnxのエイリアス
ptはnxを指す
pt = &nx;
*pt = 100;
printf( "nxの値:%d\n", nx );
printf( "*ptの値:%d\n", *pt );
nx
pt = &ny;
*pt = 300;
printf( "nyの値:%d\n", ny );
printf( "*ptの値:%d\n", *pt );
return(0);
}
*pt
300
pt
*ptに300を代入することは,
nxに300を代入することと同じ
プログラミング入門2
34
演習課題(第9回)
1. 以下のようなサッカー選手のデータファイルをエディタ(emacs)で作成せよ
。そのファイルから,選手名,アシスト数,ゴール数を読み込み,アシスト王
,得点王,MVP(アシスト+得点がMAX)の選手を判定し,画面に結果を
表示するプログラムを作成せよ。(kadai9-1.c)
選手数は各自で決めて良い
最大値を求める関数を自分で設計し、使用すること
名前
アシスト
Takahara
Nakayama
Magron
Kazu
・・・・・・・
・・・・・・・
プログラミング入門2
7
5
2
6
ゴール
20
13
8
10
ファイル:player.txt
35
演習課題
2. ポインタの理解(kadai9-2.c)
 次の手順でプログラムを作成せよ。











Int型のオブジェクト x, y を宣言
Intへのポインタ型 ptr を宣言
x, yにそれぞれ,100,500を代入
ptr がオブジェクトxを指すようにする
*ptrの値を表示
ptrを介して,xの値を400に変更
x, *ptrの値を表示
ptr がオブジェクトyを指すようにする
*ptrの値を表示
ptrを介して,yの値を200に変更
y, *ptrの値を表示
プログラミング入門2
36
提出方法
演習課題1〜2のプログラムを作成し,動作確認した上で
ソースファイル(kadai9-1.c 〜 kadai9-2.c) をメールに添付して提出せ
よ。
提出方法:
メールの題名(subjet)を, “pro2-9” + “学籍番号”+”自分の苗字”(全て半角英
数文字にて)とする。
例) pro2-9 L02001 aoki
提出先: [email protected] (青木アドレス)
提出期限: 12月10日(月) 13:00まで(時間厳守)
プログラミング入門2
37