PPT

情報処理Ⅱ
第10回:2004年1月13日(火)
本日のテーマ

標準入出力



記憶域管理関数



標準入力と標準出力
いくつかの標準入出力関数
malloc, freeなど
実行時に配列領域を確保する手法
落ち穂拾い




入力の与え方
コメントの書き方
制御文
知っておくべき「C言語の文法」
問題(授業がつまらない人のため
に)

ファイルを入力にとり,その中で最も長い行を出力
せよ.



最も長い行 = バイト数が最も多い行
複数ある場合は最初の一つのみ出力する.
標準入力に入力されたデータの中で,最も長い行を
出力せよ.
落ち穂拾い1:入力の与え方

プログラム内に書き込む.


コマンドライン引数から獲得する.


int main(int argc, char *argv[ ])
標準入力(キーボード入力)から獲得する.



int a = 44, b = 16;
scanfを用いる.
getcharやfgetsなどを用いる.
ファイルをアクセスする.

fopen, freadなどを用いる.
メリットとデメリット
入力の与え方:得失(1)

プログラム内に書き込む(埋め込む).





ハードコーティングとも呼ばれる.
手軽(原始的)であり,他の環境でも実行しやすい.
入力の値の型は,プログラム内で指定できる.
入力の値が変わるたびにコンパイルが必要.
コマンドライン引数から獲得する.




入力の値が変わってもコンパイル不要.
実行時に毎回引数指定が必要.ただしシェルのヒス
トリ機能を使えば省力化できる.
入力サイズには(現実的な)制限がある.
入力の値の型は必ず文字列.
入力の与え方:得失(2)

標準入力から獲得する.





入力の値が変わってもコンパイル不要.
入力サイズに制限がない.
実行時に毎回入力が必要.ただしシェルのリダイレ
クション機能を使えば省力化できる.
入力の値の型は原則として文字または文字列.
ファイルをアクセスする.




最も洗練された手法.
標準入力の特長を受け継ぐ.
ファイルの内容を変えなければ,同じ入力が得られ
る.
プログラムは複雑になる.
入力の与え方:比較
洗練
柔軟
コマンドライン引数
ファイルアクセス
標準入力
静的
動的
(main関数実行前に
入力値が決まる)
埋め込み
(実行中に入力値を
与える)
原始的
固定
標準入力と標準出力

標準入力(standard input, stdin)


標準出力(standard output, stdout)


通常はコンソール出力(画面表示)
シェルのリダイレクション機能を用いて変更可能.



通常はコンソール入力(キーボード入力)
実行例: find > files
実行例: patch -p0 < patch-2.4.20
シェルのパイプ機能を用いて,あるプログラムの標
準出力と別のプログラムの標準入力を接続できる.

実行例: echo '1+2*3' | bc
例題1

標準入力から入力を受け取り,各行の先頭に行番号
をつけて標準出力に出力する.
標準入力・標準出力とコンソール
標準入力
実行環境
(OSなど)
コンソール
a
b
c \n
...
実行プログラム
1
:
a
b
c \n
...
標準出力
実行コマンド
入力(エコーバック)
出力
は1バイト
標準入力に関するライブラリ関数

int getchar(void);



char *gets(char *s);



標準入力から1文字(1バイト)読み込む.
戻り値はunsigned char型の値,もしくは定数EOF.
標準入力から1行読み込み,sの指す領域に格納する.
1行が,sの領域サイズよりも大きいとしても,その
まま格納しようとする.
int scanf(const char *format, ...);


なるべく使わない!
なるべく使わない!
formatに従って標準入力から入力を読み込み,第2引
数以降が参照する領域に格納する.
読み込みに失敗すれば,入力が進まない.
標準出力に関するライブラリ関数

int putchar(int c);


char *puts(const char *s);


cをunsigned charに変換した上で,標準出力に(1文
字)出力する.
文字列sと改行文字を標準出力に出力する.
int printf(const char *format, ...);

formatに従って標準出力に出力する.
例題2



標準入力から入力を受け取り,最も長い行を出力す
る.
ただし,255バイト以上の行には対処できない.
対策



「1行は255バイトまで」を仕様にする.
配列に格納できる字数を大きくする.
配列領域を実行時に確保する.
実行時の領域確保について

プログラム実行時(main関数に制御が移る前)に

static変数のオブジェクトが確保,初期化される.


ブロックが実行されるときに

スタック領域を
用いる.
auto変数のオブジェクトが確保される.


プログラム終了時に破棄される.
ブロック終了時に破棄される.
記憶域管理関数(malloc, callocなど)を呼び出すと

オブジェクトとして使用できる領域が確保される.

freeなどの関数が呼び出されるか,プログラム終了時に
破棄される.
ヒープ領域を
用いる.
mallocの基本的な使い方

準備




#include <stdlib.h>
int *p;
p = (int *)malloc(sizeof(int));
とすると,*p がint型変数として利用可能.
p = (int *)malloc(sizeof(int) * 10);
とすると,p[0], ..., p[9] がint型変数として利用可能.
p
p[0] p[1] … p[9]
sizeof(int) *10 バイトの領域
malloc使用の注意点



領域の値は不定であるため,必要に応じて初期化す
る.代わりにcallocを使用すれば,すべて0に初期
化された領域が得られる.
pはポインタ変数なので,左辺値になり得る(p++;
などとできる).
領域確保に失敗するとNULLを返すので,
if ((p = (int *)malloc(sizeof(int) * 10)) == NULL) {
エラー処理
}
などとするのが一般的.
例題3(例題2の改良)



標準入力から入力を受け取り,最も長い行を出力す
る.
1行のバイト数制限をなくす.
ついでに,入力に '\0' があっても適切に処理するよ
うにする.
(一般的な)標準入出力関数

操作対象(関数への入力)は,ファイルポインタ.



stdio.h で定義されている「ファイル構造体」のポイ
ンタ.
型はFILE *
標準入力・標準出力に対する関数は,標準入出力関
数およびstdin, stdoutを用いた関数形式マクロによ
り定義されている(ことが多い).

例: #define
getchar( )
getc(stdin)
引数なしの関数形式マクロ
(voidを書かない)
落ち穂拾い2:コメントの書き方

コメント(注釈)の書き方




書くべき箇所





/* … */
// …
#if 0 … #endif
複数行可.入れ子にできない.
行末まで.最近の規格で認められた.
行単位.入れ子にできる.本来の使い方
ではないので,「清書」では書かない.
ファイルの先頭: ファイル名,作成者,作成日時など
関数定義の直前: 機能,入出力など
型,変数,定数などを定義する行: 意味・役割など
留意すべきプログラムコードの近辺: 処理内容
書いてはいけない

プログラムコードを見れば明らかな処理内容
落ち穂拾い3:制御文(1)

if (条件) 処理; と if (条件) {処理;} は,「処理」が
(文法的に,一つの)文であれば,同じ.常に後者
の書式を用いるプログラマも多い.


else, while, for にも当てはまる.
ifと,真のときに実行する文やelseとの対応に注意.
if (条件)
処理1;
処理2;
if (条件) {
処理1;
処理2;
}
違う!
条件の真偽にかかわらず
処理2を実行する.
if (条件1)
if (条件2)
処理1;
else
処理2;
if (条件1) {
if (条件2)
処理1;
} else
処理2;
違う!
条件1が真,条件2が偽のとき
に限り,処理2を実行する.
落ち穂拾い3:制御文(2)

whileやforのループ中に



無限ループの決まり文句



breakがあれば,そこでループを抜ける.
continueがあれば,それ以降の処理を行わずに条件判
定に戻る(forループでは増分処理を行う).
while (1) { 処理 }
for (;;) { 処理 }
通常,処理の中にbreakを置き,何らか
の条件でループから抜けるように書く.
空文を使ったループ


while (代入および条件判定);
for (初期化; 条件判定; 増分処理);
セミコロンの前で改
行する(セミコロン
のみの行を作る)書
法もある.
知っておくべき「C言語の文法」

型


制御文






算術型,ポインタ型,関数型,構造体(struct)と共用
体(union),typedef,列挙型(enum)
if, while, for, do~while, switch~case
return, break, continue
配列とポインタ
演算子および式評価
識別子(変数,関数,ラベル)
前処理指令
青線部: 主な出題範囲
今後の予定



1月20日(火):おさらい
1月27日(火):試験
2月3日(火) :補講.プログラミング能率向上
のノウハウについて(採点対象外)
試験について



日時:1月27日(火) 14:50~16:20
場所:A203
以下の2点の持ち込みを認める.


C言語に関する書籍 1冊
自筆ノート1冊,もしくは,シート1枚


ルーズリーフも許可するが,常にバインダに綴じておき,
シートを取り出さないこと(カンニング防止のため)
持ち込み不可のもの



計算機類(電卓,ノートPCなど)
2枚以上のシート(カンニング防止のため.ステー
プラなどで綴じていても不可とする.)
シートなどを貼り付けた書籍やノート
発展的な話題: なぜscanfはいけ
ないのか


http://www.cda.ics.saitamau.ac.jp/~maekawa/lect/C/file-io.html が詳しい.
while (scanf(…) != EOF) は厳禁!


変換に失敗すれば,無限ループになる.
代替案:

while (scanf(…) == 変換の個数)


変換に失敗すれば,そこでwhileループを抜ける.
fgetsで文字列領域に格納し,sscanfで変換する.

変換に失敗しても,その入力だけを読み飛ばせる.