「C言語 体当たり学習徹底入門」正誤表
このページは、拙書「C言語 体当たり学習徹底入門」技術評論社 ISBN4-7741-1200-3 の正誤表です。
あまり増えないことを祈ります。
たとえば15ページの一番上の、 「0-1-3 なぜCUIなのか」などのタイトル部分の背景などで、
誤
Happy - go - luky
C Language
「luky」は、「lucky」のスペルミスです。
正
Happy - go - lucky
C Language
ページによって、直っているところといないところがあります。
表紙と扉のページだけ、「行き当たり」でなく「行き当り」になってます。
p.38 注
「ほげを考えるページ」は、現在オリジナルが公開されていませんので、 作者の吉田さんの許可を得まして、私のページに転載させていただきました。
URLは、
http://member.nifty.ne.jp/maebashi/programmer/hoge.html(移転済み)
http://kmaebashi.com/programmer/hoge.html(移転後)
です。
Fig.1-2の中。
誤
meter_height = height / 10
正
meter_height = height / 100
「条件式」という言葉を使っていますが、規格では「条件式」とは、 ?:による式のことを指します。
if文の中に書くものも一般に条件式と呼びますが、一応補足しておきます。
誤
if (bmi < 17.6) ...
基準とする値が前のページのものと異なっています。
実は、BMIの基準値にもいくつかありまして、最初、 どこかのWebページで拾ってきたものをベースにとりあえず書いていたのですが、 最終的には「権威のあるものの方がよいだろう」ということで アメリカCDCのものに置き換えたわけです。 ...が、その時に修正漏れが発生してしまいました。申し訳ありません。
誤
符合
正
符号
「間違えるのはしょうがない。 大切なのは、同じ間違いを繰り返さないことだ」 というのが小学校時代の恩師の口癖でした(嘘)。
ポインタ完全制覇のときと同じミスを繰り返してしまいました。 すみません。
誤:
(double)weight ←weightに格納されている値をdouble型に変換
いちおうこの文字は赤くあるべきなのではないかと。
誤:
whlie (条件式) {
正:
while (条件式) {
誤:
Cでは0でない値は真を意味するので、whlieの条件式が...
正:
Cでは0でない値は真を意味するので、whileの条件式が...
誤:
...ただ、例えばList2-3の24〜25行目は、 以下のように書き替えることができます。
printf("score[%d]\n", index, score[index++]);これは、
printf("score[%d]\n", index, score[index]); index++;と同値です。
申し訳ありません。二重に間違っています。
というわけで、p.88の2行目までを以下のように差し替えてください。
正:
...ただ、例えばList2-3の17〜18行目は、 以下のように書き替えることができます。
score[score_count++] = temp_score;これは、
score[score_count] = temp_score; score_count++;と同値です。
ここで、前置の++を使うと、
score[++score_count] = temp_score;これは、
score_count++; score[score_count] = temp_score;と同値になります。
かなり問題のあるミスをしてしまいました。お詫びいたします。
誤:
これは、カレントディレクトリからヘッダファイルを探してもらえるように するおまじないです。
正:
これは、そのソースファイルの存在するディレクトリからヘッダファイルを 探してもらえるようにするおまじないです。
macro.cはcpp.cの誤りです。
誤
単純に「100 」に起き換えられていることがわかります。
正
単純に「100 」に置き換えられていることがわかります。
Fig2-5の一番下の配列の図について、
誤
正
1手順ごとに「ソートずみの範囲」はひとつづつ増えていきます。
左上のところ
誤
sorted_num
正
sorted_count
誤:
悪いことは言いません。3の状態になったら...
ここの「3」ですが、その前の箇条書きの(3)に対応します。 黒丸に白抜き文字の(3)だと思ってください。
誤
プログラムが異常終了した時に最後の方のデバッグライトが出力されないことがあ る,ということもありす
正
プログラムが異常終了した時に最後の方のデバッグライトが出力されないことがあ る,ということもあります
誤:
「標準入出力のバッファリング」
正:
「標準ライブラリのバッファリング」
「標準入出力」というとstdin, stdoutとまぎらわしいので変更します。
p.131 3-2-5の前誤
「未来の自分は他人である」ということは肝に命じて おくべきでしょう。
正
「未来の自分は他人である」ということは肝に銘じて おくべきでしょう。
演算子の優先順位表の?:の結合規則
誤
左から右
正
右から左
誤
FORTRANやBASICでは、等値比較にも代入にも同じ = を使います。
正
BASICでは、等値比較にも代入にも同じ = を使います。
FORTRAN(FORTRAN77-ISO/IEC1539 JIS X3001)では、等値比較は.EQ.でした。 等値比較に=が使えるFORTRANはおそらく存在しません。
誤:
nを8で割った時、割り切れない分は切り捨てられるので...ここの所に、以下のように注を入れます。
nが正の数の場合の話です。
誤:
Cの中で、タブを表現する場合、
正:
Cでは、タブ文字を表現する場合、
ちょっと前のままでは意味がわかりにくいので。
誤
25: fputc(ch, out_fp);
正
25: putc(ch, out_fp);
Cにはfputc()という関数もあり、putc()と同じように動きますが、 p.148の説明の方でputc()と書いていますので。
誤
は「'n'」という1文字で表現できなければなりません。
正
は「'\n'」という1文字で表現できなければなりません。
誤:
PCでWebページを作成し、FTPでサーバに送ったが
正:
PCでWebページを作成し、FTPでUNIXのサーバに送ったが
一応補足します。
誤:
fp = fopen(argc[1], "r");
正:
fp = fopen(argv[1], "r");
誤:
汎整数拡張が行なわれます
正:
汎整数拡張が行なわれます。
最後のマルが抜けているようです。
誤:
そういえばWindows3.1はフロッピー12枚組みでした。
正:
そういえばWindows3.1はフロッピー12枚組でした。
どっちでもいいような気はしますが...
誤:
しかし、記述の順序に関わらず、Cではプログラムの実行はmain() 関数から開始されます...
ここのところに、以下のように注を入れてください。
「4-1-3 main()を先に書くか後に書くか」を参照
誤:
9行目のreturn文で
正:
7行目のreturn文で
誤:
呼び出す側では話が別で、voidを入れる必要はありません。
正:
呼び出す側では話が別で、voidを入れてはいけません。
誤:
Cでは、歴史的な事情により、()の中にはvoidを入れることになっています...
以下のように注を入れてください。
正しく言うと、関数定義の()の中は、voidを入れても入れなくても意味は同じです。 voidを入れる必要があるのはプロトタイプ宣言です。p.179も参照してください。
誤
void func()
正
void func(void)
間違いと言うわけではないですが、統一性のために入れておきます。
誤:
そこで、ANSI Cから、引数も併せて宣言するように改められたわけです...
ここに注をいれてください。
引数がない場合、プロトタイプ宣言にvoidを入れるのは、 昔のスタイルの宣言と区別するためだったわけです。
挿入ソートが初出なので、注で
挿入ソートについては「4-5-1 挿入ソート」を参照のこと
と入れます。
誤:
というわけで、2変数の内容を交換する関数(swap())関数を...
swap()をタイプライタ体にしてください。
10行目で*hoge_pに10を代入していますが、
21行目で*hoge_pに10を代入していますが、
本文がゴシック体になってしまっています。地の文なので、明朝だと思ってください。
正
その理由は、「0-1-2 なぜCUIなのか」でも書きましたが
誤
その理由は、「0-1-3 なぜCUIなのか」でも書きましたが
ふたつめの注「arrayに文字列を設定する部分ですが...」は、リスト 5-9に対する注なので、リストの横に移動します(大差ない気もしますが...)。
誤
y_or_n = tolower(buf[0]);
buf[0]はcharですから、ユーザが漢字を入力した場合などには 負の数になる可能性があります。
tolower()は、引数としてunsigned charの値とEOFしか許しておらず、 それ以外の場合の挙動は未定義なので、これは問題があります。
誤
/* 価格を表示 */ printf("書名..%s\n", book_data.book_name);
正
/* 書名を表示 */ printf("書名..%s\n", book_data.book_name);
132: /* 133: * 文字列を再入力させる。改行だけ押された場合は、 134: * strには手をつけない。 135: */ 136: void reinput_string(char *str, int size, FILE *fp) 137: { 138: char buf[1024]; 139: 140: input_string(buf, size, fp); 141: 142: if (buf[0] != '\0') { 143: /* 144: * 改行のみ叩かれたわけではないようなので、 145: * データを変更する 146: */ 147: strcpy(str, buf); 148: } 149: } (中略) 178: /* 179: * data_pの指す先のデータについて、再入力させる。 180: * 変更しない場合は returnだけ押せばよい。 181: */ 182: void reinput_data(BookData *data_p) 183: { 184: printf("書名:%s>", data_p->book_name); 185: reinput_string(data_p->book_name, BOOK_NAME_LEN, stdin); 186: 187: printf("著者:%s>", data_p->author); 188: reinput_string(data_p->author, AUTHOR_LEN, stdin); 189: 190: printf("出版社:%s>", data_p->publisher); 191: reinput_string(data_p->publisher, PUBLISHER_LEN, stdin); 192: 193: printf("価格:%d>", data_p->price); 194: data_p->price = reinput_number(data_p->price); 195: 196: printf("ISBN:ISBN%s>ISBN", data_p->isbn); 197: reinput_string(data_p->isbn, ISBN_LEN, stdin); 198: 199: printf("備考:%s>", data_p->note); 200: reinput_string(data_p->note, NOTE_LEN, stdin); 201: }
オリジナルのソースだと、reinput_string()の方にはBOOK_NAME_LEN等が渡せないため、 1024文字で受けてしまい、それをBookData構造体のbook_nameにコピーするため 領域破壊が発生します。
誤
enum { … } BookType;
正
enum BookType { … };
誤:
/* 詠みかけ状態 */
正:
/* 読みかけ状態 */
List5-17で、 '\0'の分の領域確保を忘れるというかなり情けないミスを犯していました。 input_string関数を全面的に差し替えます。
char *input_string(FILE *fp) { char *p = NULL; int ch; int size = 0; /* 改行までの文字を読み込む */ do { /* 1文字分領域を拡張する */ p = realloc(p, sizeof(char) * (size+1)); ch = getc(fp); p[size] = ch; size++; } while(ch != '\n'); p[size-1] = '\0'; return p; }
誤
int select_y_or_n()
正
int select_y_or_n(void)
間違いと言うわけではないですが、統一性のために入れておきます。
誤
* 登録と一覧表示以外はとりあえずダミー
このリストでは既にダミーではありません。
このように、コメントはいとも簡単に嘘になってしまうから やたらに書くべきではない、ということを証明するためにわざと間違えた、 わけではありません。ごめんさい。
誤
しかし、"" で囲む方の書き方をすると、たいていの処理系ではまず カレントディレクトリを探しに行きます。
正
しかし、"" で囲む方の書き方をすると、たいていの処理系ではまず そのソースファイルの存在するディレクトリを探しに行きます。
同様に、下から4行目の「カレントディレクトリ」も、 「そのソースファイルの存在するディレクトリ」に置き換えます。
誤
戻り値はfromと同一、まず使わないので忘れてしまってよい。
正
戻り値はtoと同一、まず使わないので忘れてしまってよい。
next以外は(連結リストとは無関係の)構造体の本来のメンバの意味なので、 以下のように説明を入れます。
typedef struct Hoge_tag { int a; ┐ char b[32]; ┘これが構造体の内容 struct Hoge_tag *next; } Hoge;
誤
規格では、配列の要素を指していないポインタについて加減算を行った 場合の動作は未定義になっています。
正
規格では、配列の要素数をふたつ以上超えるようなポインタ演算を 行なった場合の動作は未定義になっています。
一応規格では、
配列でないオブジェクトへのポインタは、 要素型としてそのオブジェクトの型をもつ長さ 1の配列の最初の要素へのポインタと同じ動きをする
と書いてありますので、元のままの記述だと問題がありそうです。
誤:
scanf()は変換に成功した数を返します。
正:
scanf()は変換代入に成功した数を返します。 ファイルの終わりに達した場合、EOFを返します。
2010/8/25追記:
こちらに
あるとおり、代入抑止文字*を使用した場合、変換の数と代入の数は食い違います。
誤
標準出力から1文字読みこみ、戻り値として返します。
正
標準入力から1文字読みこみ、戻り値として返します。
誤
入力行の長さが予測できないのなら、fgetc()でも使って
正
入力行の長さが予測できないのなら、getc()でも使って
fgetc()でもいいですが、この本ではgetc()を使ってきていますので。
誤
ご質問の歳には
正
ご質問の際には