• 検索結果がありません。

ex14.dvi

N/A
N/A
Protected

Academic year: 2021

シェア "ex14.dvi"

Copied!
11
0
0

読み込み中.... (全文を見る)

全文

(1)

● 先週の授業のキーポイント

【位取り記数法】 • 「位取り記数法」とは整数・実数などを「数値」として表示する方法であり, 種々の方法が知ら れている. • 位取り記数法が意味を持つためには, 表示可能な範囲の整数に対して(上位桁の不要な 0 を無 視して)一意な表示を持つことである. • 以下は, 種々の記数法の例である.b 進表示 (b は b ≥ 2 をみたす整数. この b のことを基数と呼ぶ.) – 非負整数 n が n = k  j=0 njbj, (0 ≤ nj≤ b − 1) と書けているとき,n = (nknk−1. . . n1n0)b と表示する. – この時, 各 njj 桁目(または j + 1 桁目)と呼ぶ. また, 各桁で使われる文字(この 場合は{0, . . . , b − 1})を「数字」 (digit) と呼ぶ. – b 進表示において「負の整数」を表すためには先頭に符号をつける. – b 進表示において, n の b − 1 の補数 ˜n とは, ˜ n =k j=0 (b − 1 − nj)bj と定義する. b 進 N 桁表示において, n の b の補数 ¯n とは, ¯n = bN−n と定義する. この時, ¯n = ˜n+1 が成り立つ. b 進 N 桁表示において, n − m ≡ n + ¯m (mod bN) が成り立つ. したがって,b 進 N 桁 表示では,b の補数を用いることにより, 減算を加算で計算することができる. – 非負実数 x が x = k  j=−∞ njbj, (0 ≤ nj≤ b − 1) と書けているとき,x = (nk. . . n1n0.n−1n−2. . .)b と表示する. これをx の b 進小数表 示と呼ぶ. – 非負実数 x が有限または循環 b 進小数表示を持つ必要十分条件は x が有理数であるこ とである. (この事実はb に依存しないが, 有理数の b 進小数表示は一意とは限らな い.)また, 非負実数x が有限 b 進小数表示を持つか否かは b に依存する. ★ 平衡 2B + 1 進表示 (B は B ≥ 1 をみたす整数) – 整数 n が n =k j=0 nj(2B + 1)j, (−B ≤ nj ≤ B) と書けているとき, n = (nknk−1. . . n1n0) と表示する. すなわち, (通常の)b 進表 示がZ/bZ の代表元として, 正の最小剰余を用いるのに対して, 平衡 2B + 1 進表示が Z/(2B + 1)Z の代表元として, {−B, . . . , 0, . . . , B} を用いている違いに過ぎない.

(2)

– 平衡 2B + 1 進表示では, n → −n の変換が, 各桁の数字の取り替えで行えるという特 徴を持つ. ★ −b 進表示 (n は b ≥ 2 をみたす整数) – 整数 n が n =k j=0 nj(−b)j, (0 ≤ nj≤ b − 1) と書けているとき,n = (nknk−1. . . n1n0) と表示する. – −b 進表示では, b 進表示とは異なり, 符号を用いなくても負の整数も表示できる. ★ 混合基数表示 – b = {bj}k−1j=0 (ただし,bj≥ 2) を与えたとき, 非負整数 n が n = n0+n1b0+n2b0b1+· · · + nkb0b1· · · bk−1 と書けているとき,n = (nknk−1. . . n1n0) と表示する. (すべてのbjB に等しいと き, 通常のB 進表示となる.) – 例として, b = {60, 60, 24, 7} と取ると, n = (n4, n3, n2, n1, n0) は, 「n4 weeksn3 days n2hoursn1 miniutesn0 seconds」を表すと考えることができる. (n はその全秒数)

– 混合基数においても「補数」を定義できる.Fibonacci 表示 – {Fj}j=0 Fn=Fn−1+Fn−2, F0= 0, F1= 1 によって定義された Fibonacci 数列とする. この時, 任意の非負整数n は, n =   j=0 Fkj, Fkj+1 Fkj と一意的に表すことができる. ただし,Fkj+1  Fkj とは,kj+1> kj+ 1 を意味する. – 非負整数 n が n = j=0 Fkj, Fkj+1 Fkj と書けているとき,n = (k. . . k1k0) と書く. 【再帰】 • C をはじめとする, 多くのプログラム言語では, 関数内から自分自身を呼び出すことができる. これを「再帰的関数呼び出し」または「再帰」と呼ぶ. • 関数呼び出しでは, 引数のコピーなどが発生し, 関数が利用するためのメモリ領域が必要となる ため, 関数呼び出しを行うと, 実行速度の低下や必要なメモリ量の増加などが発生する. • 一般に, 帰納的な定義を行うアルゴリズムを実現する場合には, 再帰を用いたほうがプログラム がわかりやすくなる. しかし, 再帰を用いると, 実行速度の低下が発生する場合がある. • 関数内での再帰呼び出しがただ1回に限る再帰を線型再帰と呼ぶ. また, 再帰呼び出しの後には 何も処理が行われない再帰を末尾再帰と呼ぶ.

(3)

• 末尾再帰をループに変えた場合, メモリ使用量が一定となる. • 他の再帰呼び出しもループに変えることが出来るが, 一般にはメモリ使用量を一定にすることが できない. • Fibonacci 数列の第 n 項を計算する再帰呼び出しでは, 同じ引数を取る呼び出しが何度も行わ れるため, 関数の呼び出し回数は n に対して指数関数的に増大する.

● 実習内容

【サンプルプログラム】 ★ ex14-1-1.c 標準入力からのテキストデータの読み込み. 1. このプログラムは「標準入力」からテキストデータを読み, それを標準出力に書き出すだけ のものである. 2. “feof(stdin)” とは標準入力 (stdin) が入力終了となるときに 1 を返し, そうでない状態 の時には 0 を返す関数である. 3. より正しい feof 関数の動きは以下の通りである. • ファイルに対して「ファイルポインタ」と呼ばれる「ファイル上で次の読み込みが行わ れる位置」という概念が存在する. • ファイルを開いたとき(標準入力の場合には, プログラム実行開始時)には, ファイル ポインタは, ファイルの先頭にある. • 各ファイルの末尾には, 仮想的に「ファイルの終端」を表す EOF という文字が付け加え られていると考える.

• 一旦 EOF を読むと feof 関数は, 値 1 を返す. EOF を読む以前には feof 関数は, 常に 値 0 を返す.

4. 標準入力から1行ごとまたは最大 MAX_CHAR_PAR_LINE 文字を一度に buf に読み込もうと している.

5. 実際に読み込みを行うのは fgets 関数であり, fgets は「データを格納する」 buf, 「最大 読み込みデータ量」 MAX_CHAR_PAR_LINE, 「読み込み先」 stdin を渡している. bufには「改行文字」を含めて読み込まれ, 末尾には NULL 文字が付加される. 6. fgets は現在のファイルポインタの位置から読み込みを始め, fgets は読み込みが終わる と, ファイルポインタを読み込んだ末尾の次の文字に移動する. したがって, 最後の行の末 尾まで読み込むと, ファイルポインタの位置は EOF に到達する. fgetsの返却値は, 読み込んだ文字列へのポインタである. ファイルポインタが EOF にあ るときに fgets を実行すると NULL が返却され, buf の中身は変更されない.

7. このプログラムを ex14-1-2.c のように書き直すと, 末尾の行が2度出力される. 8. ex14-1-3.c のように scanf を利用するとどのようになるかを考えてみよう. 9. 「標準入力から2つの整数を読む」ために ex14-1-4.c のようなプログラムを書いたとし よう. このプログラムに “ab” というデータを入力したとき, n, m の値がどうなるかは規 定されていない. このように scanf を利用してデータを読み込むと, そのデータが「正しい入力かどうか」 の判定ができないため, scanf またはその類似の関数を利用してデータ読み込みを行って

(4)

はならない. scanf は printf で出力された「フォーマットの確定したデータ」を読むた めの関数であり, フォーマットの確定しないデータを読むためのものではない. ★ ex14-2.c ファイルからのテキストデータの読み込み. 1. ex14-1-1.c の改良版である. 「標準入力」からではなく, 指定のファイルからテキストデー タを読み込む. 2. そのための違いは以下の通りである. • ファイルを指定し, ファイルを開くための関数 fopen を用いる. fopen の戻り値は, そ のファイルにアクセスするための「ファイルポインタ」である. ファイルポインタは FILE *型(これは stdio.h で定義されている)である. ここでの「ファイルポインタ」という用語は, 上に出てきた「ファイルポインタ」とは 異るものである.

• feof, fgets 関数の stdin のかわりに fopen で得られたファイルポインタを用いる. • ファイルの読み込みが終了したら fclose でファイルを閉じる必要がある. 3. fopen は2つの引数をとる. 第一引数は「ファイルパス」であり, 第二引数はファイルを開 くモードの指定である. この場合「読み込み専用」であるので "r" を指定する. 第一引数に指定したファイルが存在しない場合には NULL を返す. ★ ex14-3.c ファイルへのテキストデータの書き出し: (新規作成モード). 1. ex14-1-2.c の改良して, ファイルからテキストデータを読み, 異るファイルに書き出しを してみよう. この場合は, 読み込みファイルと, 書き出しファイルの両方を開くことが必要 となる. 2. 書き込み用(新規作成)としてファイルを開くためには, fopen の第二引数に "a" を指定 する. (fopen の仕様を調べてみよう. 他にどのようなモードがあるのだろうか?) 3. 出力は printf のかわりに fprintf を使えばよい. ★ ex14-4.c ファイルからのバイナリデータの読み込みと書き出し. 1. 今度は「必ずしもテキストファイルとは限らないファイル」の読み込みと書き出しを行っ てみよう. 2. テキストデータは fgets で読み込みができ, fprintf で書き出しが可能である. しかし, fgets では読み込んだデータの末尾に NULL 文字を付加するため, バイナリデータの読 み込みがうまくいかない. また, printf を用いて文字列を出力すると NULL 文字の直前 (0x00) まで出力する. したがって, バイナリデータが 0x00 を含んでいる場合には正しく出 力できない. 3. そのため, 読み込みには fread 関数, 書き出しには fwrite 関数を用いる必要がある. fread関数は読み込んだバイト数を返すので, その量だけを fwrite 関数で書き込めばよい. ★ ex14-5.c テキストデータの読み込みとデータの解析. 1. ここでは, 標準入力からファイルを読み込み, そこに含まれる「行数」, 「文字数」を表示 するプログラムを作ってみよう. これは UNIX の標準コマンド wc のオモチャである. 2. ただし, プログラムを簡単にするため, 入力されるファイルの1行の文字数は MAX_CHAR_PAR_LINE - 1 を越えないことを仮定する. 3. なお, Windows では改行文字が 2 バイトあるため, このプログラムが出力する文字数とファ イルのバイト数は一致しません.

(5)

★ ex-14-6 標準入力からの整数の読み込み. 1. 標準入力からテキストデータを読み込み, 1行ごとに, そこに書かれた「空白で区切られた 最大10個の整数」の和を求めるプログラム. ただし, テキストデータ中に「整数」ではな い文字列が書かれている場合や, 10個を越える「整数」が書かれている場合には, 正しい 結果を返しません. 2. ここでは, s に「整数」である文字列を読み込み, 標準関数 atoi で int に変換しています. 【入力例】 • “01-2+345-678+10” という入力を受け取った場合には, 整数 0, 1, −2, 3, 4, 5,−6, 7, 8, 10 が入力されたものとみなします. • “01-2+345-678+10” という入力を受け取った場合には, 整数 0, 1, −2, 3, 4, 5, −6, 7, 8, 10 が入力されたものとみなします. すなわち, 先頭に空白がある 場合があります. ★ ex-14-7 コマンドライン引数の読み込み. 1. コマンドライン引数は argv に読み込まれる. 有効な引数の数は argc で与えられる. 2. argv[0] には実行されたプログラム名が入っている. 【入力例】

• “./a.out123” としてプログラムを実行すると, argc は 4 となり, argv[0] には “./a.out” が, argv[1] には “1” が入っている. 【課題】 ★ exercise-14-1 次の仕様をみたすプログラムを書きなさい. 【形式】 cat [file....] 【機能説明】 プログラム cat は引数に与えられたテキストファイルを順に読み込み, それらを標準出力 に出力します. 引数が無い場合には標準入力からデータを読み込みます. 【利用例】 • cat file fileの中身を標準出力に出力します. • cat file1 file2

file1, file2の中身を連結した結果を標準出力に出力します. • cat 標準入力からのテキストデータを標準出力に出力します. ★ exercise-14-2 次の仕様をみたすプログラムを書きなさい. 【形式】 od file 【機能説明】 プログラム od は file の内容を 16 進ダンプします. すなわち, file のバイト列を先頭か ら表示します. 【表示方法】

(6)

00000000: 20 21 22 23 24 25 26 27 28 29 0a 31 32 33 34 35 00000010: 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 のように1行に 16 バイト分, 4 バイトごとに空白を余分に入れます. 一番左側の 8 桁の 16 進数は, その行の最初のバイトデータがファイル先頭から何バイト目 にあるかを示しています. 上の例では 2 行目の 0x36 は, ファイルの先頭から 0x00000010 バイト目, すなわち 16 バイト目となります.

ex14-1-1.c の内容

  

/* $Id: ex14-1-1.c,v 1.2 2004-07-12 14:39:34+09 naito Exp $ */ #include <stdio.h>

#define MAX_CHAR_PAR_LINE (1024) int main(int argc, char **argv)

{

char buf[MAX_CHAR_PAR_LINE] ; while(!feof(stdin)) {

if (fgets(buf, MAX_CHAR_PAR_LINE, stdin) != NULL) printf("%s", buf) ; } return 0 ; }

ex14-1-2.c の内容

  

/* $Id: ex14-1-2.c,v 1.2 2004-07-12 14:39:43+09 naito Exp $ */ #include <stdio.h>

#define MAX_CHAR_PAR_LINE (1024) int main(int argc, char **argv)

{

char buf[MAX_CHAR_PAR_LINE] ; while(!feof(stdin)) {

fgets(buf, MAX_CHAR_PAR_LINE, stdin) ; printf("%s", buf) ;

}

return 0 ; }

(7)

ex14-1-3.c の内容



 

/* $Id: ex14-1-3.c,v 1.2 2004-07-12 14:39:57+09 naito Exp $ */ #include <stdio.h>

#define MAX_CHAR_PAR_LINE (1024) int main(int argc, char **argv)

{ char buf[MAX_CHAR_PAR_LINE] ; while(!feof(stdin)) { scanf("%s", buf) ; printf("%s\n", buf) ; } return 0 ; }

ex14-1-4.c の内容

  

/* $Id: ex14-1-4.c,v 1.1 2004-07-09 12:56:09+09 naito Exp $ */ #include <stdio.h>

int main(int argc, char **argv) {

int n, m ;

scanf("%d %d", &n, &m) ;

printf("n = %d, m = %d\n", n, m) ; return 0 ;

(8)

ex14-2.c の内容



 

/* $Id: ex14-2.c,v 1.2 2004-07-12 14:40:16+09 naito Exp $ */ #include <stdio.h>

#define MAX_CHAR_PAR_LINE (1024) int main(int argc, char **argv)

{

char buf[MAX_CHAR_PAR_LINE] ; FILE *in ;

if ((in = fopen("ex14-2.c", "r")) == NULL) return -1 ; while(!feof(in)) {

if (fgets(buf, MAX_CHAR_PAR_LINE, in) != NULL) printf("%s", buf) ; } fclose(in) ; return 0 ; }

ex14-3.c の内容

  

/* $Id: ex14-3.c,v 1.2 2004-07-12 14:40:28+09 naito Exp $ */ #include <stdio.h>

#define MAX_CHAR_PAR_LINE (1024) int main(int argc, char **argv)

{

char buf[MAX_CHAR_PAR_LINE] ; FILE *in, *out ;

if ((in = fopen("ex14-2.c", "r")) == NULL) return -1 ; if ((out = fopen("outfile", "a")) == NULL) return -1 ; while(!feof(in)) {

if (fgets(buf, MAX_CHAR_PAR_LINE, in) != NULL) fprintf(out, "%s", buf) ; }

fclose(out) ; fclose(in) ; return 0 ;

(9)

ex14-4.c の内容



 

/* $Id: ex14-4.c,v 1.2 2004-07-12 14:40:42+09 naito Exp $ */ #include <stdio.h>

#define MAX_CHAR (1024) int main(int argc, char **argv) {

char buf[MAX_CHAR] ; size_t size ;

FILE *in, *out ;

if ((in = fopen("./a.out", "r")) == NULL) return -1 ; if ((out = fopen("./b.out", "a")) == NULL) return -1 ; while(!feof(in)) {

if ((size = fread((char *)buf, sizeof(char), MAX_CHAR, in)) != 0) fwrite(buf, sizeof(char), size, out) ;

} fclose(out) ; fclose(in) ; return 0 ; }

ex14-5.c の内容

  

/* $Id: ex14-5.c,v 1.2 2004-07-12 14:40:55+09 naito Exp $ */ #include <stdio.h>

#include <strings.h>

#define MAX_CHAR_PAR_LINE (1024) int main(int argc, char **argv)

{

char buf[MAX_CHAR_PAR_LINE] ; int lines = 0, letters = 0 ; while(!feof(stdin)) {

if (fgets(buf, MAX_CHAR_PAR_LINE, stdin) != NULL) { lines += 1 ;

letters += strlen(buf) ; }

}

printf("%d %d\n", lines, letters) ; return 0 ;

(10)

ex14-6.c の内容



 

/* $Id: ex14-6.c,v 1.11 2005-07-20 19:12:47+09 naito Exp $ */ #include <stdio.h>

#include <ctype.h> #include <stdlib.h>

#define MAX_CHAR_PAR_LINE (1024)

#define MAX (10)

int read_int(char *, int *, int) ;

int main(int argc, char **argv) {

char buf[MAX_CHAR_PAR_LINE] ; int a[MAX], c, sum, i ;

while(!feof(stdin)) {

if (fgets(buf, MAX_CHAR_PAR_LINE, stdin) != NULL) { printf("buf = %s", buf);

c = read_int(buf, a, MAX) ; sum = 0 ;

for(i=0;i<c;i++) sum += a[i] ; printf("result = %d\n", sum) ; }

}

return 0 ; }

int read_int(char *buf, int *a, int max) { char *ps ; char s[MAX_CHAR_PAR_LINE] ; int i=0 ; while((*buf)&&(i<max)) { while(isspace((int)*buf)) buf++ ; /* 空白を読み飛ばす */ if (*buf) { ps = s ; while(!isspace((int)*buf)&&(*buf)) *ps++ = *buf++ ; /* 文字をコピー */ *ps = ’\0’ ; a[i++] = atoi(s) ; /* 整数値に変換 */ } } return i ; }

(11)

ex14-7.c の内容



 

/* $Id: ex14-7.c,v 1.1 2005-07-19 09:32:38+09 naito Exp $ */ #include <stdio.h>

int main(int argc, char **argv) {

int i ;

for(i=0;i<argc;i++) printf("%s\n", argv[i]) ; return 0 ;

参照

関連したドキュメント

CN 割り込みが発生した場合、ユーザーは CN ピンに対応する PORT レジスタを読み出す

IDLE 、 STOP1 、 STOP2 モードを解除可能な割り込みは、 INTIF を経由し INTIF 内の割り. 込み制御レジスター A で制御され CPU へ通知されます。

Using the special C- mount ring adapter, the lens can be directly attached to a CCD camera, enabling it to be used as a low cost image ob- servation lens and variable focus lens

ユーザ情報を 入力してくだ さい。必要に 応じて複数(2 つ目)のメー ルアドレスが 登録できます。.

(1)クレジットカード、AmazonPAYによるお支払いを申込まれたお客様に対しては、申込み時に報酬額を決

実績 目標 (見込み). R2

Checksum Code flash: 0x2A8E Checksum PASS. 備考