#author("2022-06-30T10:11:03+09:00","ldap:bbm85148","土村 展之")
* [[プログラミング実習II知能・機械:https://am.kwansei.ac.jp/prog2/]] の教科書 [#h8221d47]
『キックオフC言語 2022年度用』のサポートページです。

#contents


>アンケートを実施しているので、回答にご協力をお願いします。
&br;https://docs.google.com/forms/d/e/1FAIpQLScdTwgxEu8hoUMzLRdqJBoD4ClyuoCl7Re93B8VwAyDzVIJQg/viewform?usp=sf_link

** 配布物 [#ge8fc588]
製本した印刷物は、授業の初回で配布します。A5版以外に、少量ですが大きめの手作りのB5版も用意しています。

PDF は以下で公開します。
- [[閲覧用:https://cs.kwansei.ac.jp/~tutimura/debug/KickOffC/KickOffC-2022view.pdf]]
-- ページ番号が、ページの上と下の2ヶ所にあるので、ページ全体が表示されてなくても確認が容易です。
-- リンク部分の文字の色が「赤」です。
- [[印刷用:https://cs.kwansei.ac.jp/~tutimura/debug/KickOffC/KickOffC-2022print.pdf]]
-- ページ端に、章ごとの帯のような印(ツメ)があります。
-- リンク部分の文字の色が「黒」です。
-- B5用紙の中にA5の領域の版面があるので、裁断できるのなら「B5用紙に原寸」で印刷してA5に裁断するのがベストですが、通常は「A5用紙に原寸」「B5用紙に122%拡大」のどちらかで印刷するのがよいでしょう。
- [[ソースコード閲覧:https://cs.kwansei.ac.jp/~tutimura/debug/KickOffC/source/]]
-- [[全ファイルダウンロード:https://cs.kwansei.ac.jp/~tutimura/debug/KickOffC/KickOffC-2022source.zip]]

** 正誤表 [#o4cc021b]
*** 多数 [#jba28e2e]
// 04/14 37021623 福田 壮一朗
『自動''清''算』→『自動''精''算』

*** まえがき [#A00]
:p.iv 下から6行目|『チーティング』→『ティーチング』

*** 3章 [#A03]
:p.50 問題6.と7.|難易度順的には、6.と7.を入れ替えておくべきでした。
:p.50 問題7.タイトル部分|『関数の''再利用と''信頼性』→『関数の信頼性''・キャスト''』再利用する場面は、特にありませんでした。逆にキャスト(p.30参照)の必要になる場合があります。
:p.50 問題8.|指示を追加します。『εはマクロ名をEPSとして定義せよ。(p.31を参照のこと。)』具体的には、次のような記述を #include の直後に書きます。ギリシャ文字のイプシロンはマルチバイト文字のため、識別子には使えません。
 #define EPS 0.000001

*** 4章 [#A04]
:p.54 脚注*3|『単純に 2 つの if を並べるだけだと、 printf() が 2 回とも実行される場合があるので、 else if は必須です。』→『この例ではelseがなくても動作に変わりはありませんが、一般の条件では2つのifが同時に成り立つ可能性があるので、else ifで構造的に1回だけに絞っています。』
:p.69 問題2.|指示を追加します。%%『if文1つで判定せよ。』%%『1個の if と1個の else で判定せよ。』
:p.69 問題4.|指示を追加します。『1≦m≦6 あるいは 1≦n≦3 のどちらの範囲にも該当しなければ、何も表示しない。この動作を void print_grade(int a) の関数に独立させ、また70ページのコラムを参考に、正しく動作することのわかる main() を作れ。』
:p.69 問題6.|辺の長さをintに限定するメリットは特にないので、関数のプロトタイプを『int exist_triangle(double a, double b, double c)』にしておくべきでした。(解答には影響しません。)
:p.70 問題7.|『x は 10 以上 990 以下の 10 の倍数』これは入力側の条件と考えてください。これ以外の値が与えられたときでも、エラー処理は不要です。

*** 5章 [#A05]
:p.86 問題0.|誤植ではありませんが、問題を追加します。
&br;『次のプログラムの無駄を省いて、単純にせよ。(34ページの問題2.も参照のこと。)』
 #include <stdio.h>
 
 int main(void) {
     int a;
     for (int i=1; i<=5; i++) {
         a = i * 10;
     }
     printf("%d\n", a);
     return 0;
 }
:p.86 問題8.|余力のある人向けに、以下を追加します。提出は必須ではありません。
&br;『整数 y,m について定義される T(y,m) の値を表示してみよ。y は 2022 などの値1つを自由に選んで固定し、m は 3から14まですべてを試みよ。
 T(y,m) = (y + y/4 - y/100 + y/400 + 13*(m+1)/5) % 7
そして、現実の y年m月1日の曜日との関係で、気づいたことを述べよ。なお、13月、14月は、翌年の1月、2月と対応付けて考えよ。』

*** 6章 [#A06]
:p102 問題6.と問題7.|誤植ではありませんが、以下のように問題を差し替え/廃止します。(元の問題をオプション課題として残しておきます。提出欄の ...6orig と 7orig です。)
~6. ''[ある?ない?]''
&br;ソースコード 6.5 の is_prime3() を利用して、次の関数を作れ。
~• int is_sum_of_2primes(int n) は、 n が 2 つの素数の和で表せれば論理型の TRUE、そうでなければ FALSE を返す。''(追記)2つの素数は同じものでもよい。''
~そして main() 関数で、2 から 100 までの整数のうち、素数でもなく、2 つの素数の和でも表せないものを、すべて求めて表示せよ。
~7. ''廃止''
:p102 問題9.|[[12章>#A12]] の6章部分を参照してください。

*** 7章 [#A07]
:p.112 コラムのすぐ上の行|『''場合''には』→『''変数''には』&br;意味が通じないので、訂正します。
:p.117 問題0.|以下を追加します。『 問題0.[仮引数のスコープ(3.5節の復習)] p.44 の リスト3.3 の5行目のtriangle()関数について、仮引数を「(double a, double b, double c)」から「(double x, double y, double z)」に変更すると、そのままではコンパイルエラーになる。エラーを解消するための''最小限の修正''を行え。実行結果は修正前と同じになるようにせよ。4行目のコメント中の「a,b,c」は「x,y,z」に修正し、これ以外に不必要な(実行結果に影響しない)修正は行ってはならない。』
>3.5節での説明は不十分でした。仮引数のスコープはその関数全体であるため、仮引数がどんな名前であるかは、別の関数(呼び出し側)からは感知できないことに注意してください。
<
:p.117 問題A.|復習の問題を追加します。『問題A. [論理型の変数と関数(4.5節)] 次のプログラムの print_is_in_circle() 関数中の if の条件式を埋めよ。''ヒント'':「if (is_in_circle(x,y,r) == TRUE)」ではない。is_in_circle() 関数の return が条件式を返すことに着目して、p.62--p.65をよく読むこと。』
 #include <stdio.h>
 
 /* 点(x,y)が、原点を中心とする半径rの円の内側なら、論理型の TRUE、
    そうでなければ FALSE を返す */
 int is_in_circle(double x, double y, double r) {
     return (x * x + y * y <= r * r);
 }
 
 void print_is_in_circle(double x, double y, double r) {
     printf("(%g,%g)は、原点を中心とする半径 %g の円の", x, y, r);
     if ( /*   ここを埋めよ   */ ) {
         printf("内側\n");
     } else {
         printf("外側\n");
     }
 }
 
 int main(void) {
     print_is_in_circle(1.0, 1.0, 1.4142); // 外
     print_is_in_circle(1.0, 1.0, 1.4143); // 内
     print_is_in_circle(11, 4, 12);        // 内
     print_is_in_circle(11, 5, 12);        // 外
     return 0;
 }
:p.117 下から1行目|ユークリッドの互除法を説明していませんでした。[[WikiPedia.ja:ユークリッドの互除法#手続き的記述]] などを参照してください。
:p.118 問題4.|''指示''を追加します。『4つの関数のプロトタイプ宣言を、プログラムの先頭部分(#include よりは後)に追加せよ。』また、main()関数のサンプルを例示しておきます。
 #include <stdio.h>
 
 int main(void) {
     set_year(0);  // 無効
     set_month(0); // 無効
     printf("year = %d, month = %d\n", get_year(), get_month());
     set_year(2022);
     set_month(6);
     printf("year = %d, month = %d\n", get_year(), get_month());
     return 0;
 }

*** 8章 [#A08]
:p.129 ソースコード8.5の18--19行目|配列要素数を num という変数にしています(可変長配列という機能です)が、Visual C++ではサポートされていないので、マクロ定数を使うべきでした。
:p.138 問題3.|main()関数を例示しておきます。
 int main(void) {
     int d = 31;
     for (int i=0; i<=13; i++) {
         if (! is_valid_date(i, d)) {
             printf("%d月%d日は存在しません\n", i, d);
         }
     }
     return 0;
 }
:p.138 問題7.|訂正ではありません。オプションの問題を追加しておきます。『問題7. [配列要素の全ペア] 東海道新幹線のぞみ号の停車する6つの駅の、東京駅からの距離(km)は、それぞれ
  東京  品川  新横浜 名古屋 京都   大阪
  0.0    6.8   28.8  366.0  513.6  552.6 
である。この距離を1次元配列に格納し、以下の表のように、各駅の間の距離を''計算で''求めて表示するプログラムを作れ。
&br;・実行結果の、()内の駅名はヒントであるので、''数値部分だけ''を表示すればよい。
&br;・数値は "%8.1f" で表示すると、桁が揃いやすい。
 実行結果
 ( 東京)( 品川)(新横浜)(名古屋)( 京都)( 大阪)
      0.0     6.8    28.8   366.0   513.6   552.6 ( 東京)
      6.8     0.0    22.0   359.2   506.8   545.8 ( 品川)
     28.8    22.0     0.0   337.2   484.8   523.8 (新横浜)
    366.0   359.2   337.2     0.0   147.6   186.6 (名古屋)
    513.6   506.8   484.8   147.6     0.0    39.0 ( 京都)
    552.6   545.8   523.8   186.6    39.0     0.0 ( 大阪)
』

*** 9章 [#A09]
:p.154 問題3.|『2.5.''1''項』→『2.5.''2''項』&br;toupper()の参照先が間違っていました。p.25です。また toupper() 関数は、変換の必要のない文字はそのまま返すので、事前に小文字であるかどうかの検査は不要です。
:p.154 問題4.|関数のプロトタイプと、main()関数を例示しておきます。また、参考にしたURLがコメント中に記載されていれば、採点の際に考慮します。
 void print_cancel_or_not(char weather[]) {
     /* ここを作る */
 }
 int main(void) {
     print_cancel_or_not("暴風雪警報");
     print_cancel_or_not("大雪警報");
     print_cancel_or_not("特別警報(大雪)");
 }
:p.154 問題5.|ヒントを追加します。charからintへの変換の式は「c - '0'」です。関数に独立させると、次の通りです。
 int char2int(char c) { return c - '0'; }
これを使うと、次のように、「1文字」から「整数」に変換されます。
 char2int('0') → 0
 char2int('1') → 1
 ...
 char2int('9') → 9
:p.154 問題6.|[[12章>#A12]] の9章部分を参照してください。

*** 10章 [#A10]
:p.168 問題2.|補足です。frac_mul()もfrac_div()も、返す分数は''約分''済みのものにしてください。
:p.168 問題4.|『(1)10.2.1項のpoint_t型を用いる。』→『(1)10.2.1項の''ように、 struct pointの代わりに''point_t型を用いる。』&br;構造体のメンバーは、10.2.1項と同一ではなく、ソースコード10.2では label が増えています。
:p.168 問題4.|『(2)z座標を追加して』→『(2)''point_tに''z座標を追加して』&br;指示が不明瞭でした。
:p.168 問題6.|[[12章>#A12]] の10章部分を参照してください。

*** 11章 [#A11]
:p.188 問題0.|以下を追加します。『 問題0.([複数の手段の使い分け])&br;(a) fputc(c, fp) は fprintf(fp, "%c", c) で代用できる。標準ライブラリに、なぜこの単機能の関数が用意されているのか、考察せよ。&br;(b)数学関数の sqrt(x) は pow(x, 0.5) で代用できる。標準ライブラリに、なぜこの単機能の関数が用意されているのか、考察せよ。』
:p.188 問題1.|提出物に、''入力ファイル''と''出力結果''を追加します。入力ファイル名は"input.txt"としてください。出力結果は「./11_6_1.exe > 11_6_1.txt」として保存した"11_6_1.txt"か、あるいは画面に出力された文字をコピー&ペーストしてテキストファイルを作成してください。
:p.188 問題2.|''オプション課題''に変更します。また、''入力ファイル''は問題1.と共通とします。''出力結果''は、同様に"11_6_2.txt"を作成して提出してください。
:p.188 問題3.|''入力ファイル''は問題1.と共通とします。''出力結果''は、同様に"11_6_3.txt"を作成して提出してください。&br;''ヒント1'':char s[]="abc" の文字列は、各配列要素に以下のように格納されるので、s[strlen(s)]は常にヌル文字です。s[strlen(s)-1]が末尾の文字です。&br;''ヒント2'':fgets()で受け取った文字列には、末尾に"\n"の付いていることがありますが、s[strlen(s)-1] を '\n' と比較すれば、付いているか判断できます。&br;''ヒント3'':本来はOSによる改行文字"\r\n", "\n", "\r" の違いを標準ライブラリ関数が吸収することになっていますが、Cygwin は吸収しきれずに "\r\n" になる場合があります。末尾の '\r' も除去するとよいでしょう。
|~変数定義|>|>|>|~配列要素|~文字列の長さ|~末尾の文字|h
|~|[0]|[1]|[2]|[3]|~|~|
|char s[ ]="abc";|'a'|'b'|'c'|'\0'|strlen(s)=3|s[strlen(s)-1]|
:p.188 問題4.|新たに追加します。→[[プログラミング実習II知機11_6_4]]

*** 12章 [#A12]
:p.191 6章|変更と補足があります。変更は、『1000, 500, 100のいずれか』→『''5000,'' 1000, 500, 100のいずれか』と、受取可能な金額に5000も含めます。補足は、最後に次の文を追加します。『受け取れない金額に「受け取れません」と表示することは、最初の段階では考えなくても構いません。(6.4.3項のように、例外的な処理が必要になります。)』
:p.192 9章|お釣りに1000円札を含めてください。そして表示するメッセージを『a円''硬貨''b枚』→『a円b枚』に変更してください。
:p.193 10章|『現在時刻を取得し、''経過時間から駐車料金を決定して返します''。』→『現在時刻を取得し、''現在時刻を表示します''。』&br;駐車料金の決定には、いくつもの関数を呼び出す必要があります。各関数を連結するのは、最終的な目標であるので、今の段階では、現在時刻の取得方法を練習するにとどめてもらって構いません。最終的には、この指示の通りに駐車料金を返すようにして完成させてください。そして、参照すべきソースコード12.1は、プログラム全体ではなく、以下の部分だけで十分です。
 #include <time.h>   // time(), struct tm
 
 /* 10章 構造体 */
 struct tm get_current_time(void) {
     time_t t = time(NULL);
     return *localtime(&t);
 }
 
 /* 10章 構造体 */
 int decide_fee(void) {
     //printf("駐車開始時刻を入力してください\n");
     //printf("時 => ");  int h = input_int();
     //printf("分 => ");  int m = input_int();
     //printf("秒 => ");  int s = input_int();
 
     struct tm now = get_current_time();
     printf("現在時刻は %02d:%02d:%02d です\n",
            now.tm_hour, now.tm_min, now.tm_sec);
 
     int sec = 0;
     /* ここを作る */
     printf("経過時間は %d 秒です。\n", sec);
 
     int fee = 0;
     /* ここを作る */
     printf("駐車料金は %d 円です。\n\n", fee);
     return fee;
 }

:p.194 ソースコード中の7行目|以下のプロトタイプ宣言を挿入しておくべきでした。
 /* プロトタイプ宣言 */
 int input_int(void);
 int sec2fee(int sec);
 int is_coin_note(int value);
 int get_coin_note(void);
 int hms2sec(int h, int m, int s);
 int sec_diff(int h1, int m1, int s1, int h2, int m2, int s2);
 void put_change(int x);
 struct tm get_current_time(void);
 int decide_fee(void);
 int receive_fee(int fee);
:p.195 ソースコード中の60行目|『%d:%d:%d』→『%d:%''02''d:%''02''d』分と秒は、1桁の数字でも0を補って、2桁で表示する必要がありました。

*** 13章 [#A13]
:p.203 ソースコード 13.2の7行目|コメント中の引数名が不一致です。『''a''と''b''がほぼ等しければ0, ''a''>''b''なら正, ''a''<''b''なら負を返す』→『''x''と''y''がほぼ等しければ0, ''x''>''y''なら正, ''x''<''y''なら負を返す』
:p.208 コラムの1行目|『終端を示こと』→『終端を示''す''こと』

トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS