Practice 2: プログラムの基本構造

プログラムって,どこから書き始めればいいのでしょうか.この疑問は,ある程度まとまった量(といっても,今回は,300-400行ぐらいですが)のプログラムを書くときに,初心者の手が止まる原因の1つだと思います.

解説「プログラムをどこから作り始めるか」を読み,プログラムの作成手順を考えてみましょう.教科書の4.1節も参考にしてみてください.

作成手順に関する考察の結果として着手点を見つけます.実際に,練習2-1と練習2-2を通して,プロジェクトを前進させましょう.練習2-3が完成すれば,最終的な目標となるプログラムの大枠のようなものが見えてくることでしょう.

解答例(前半後半)は,後に公開されるかもしれませんが,その前に自分で解けるようにしておきましょう.

プロジェクトの開始(2): レポートAの準備と作成

今回から,レポート執筆のことも意識してもらいます.LaTeXの使い方も思い出してください.工学基礎実験実習の教科書(通称:緑教科書)も,適宜参照するとよいでしょう.

レポートAの詳細は演習課題説明資料PDF 3章で説明しています.

(クリックすると,詳細な説明が現れます)

レポートの作成例をダウンロードする

テンプレートと作成例は以下から探してください.講義中に教員から指示がある場合は,その指示に従ってください.

前回同様,wgetコマンドでダウンロードしましょう.使い方を忘れたという人は,前回資料を見てくださいね.

ダウンロードしたファイルは,mvコマンドを使って,学生番号を含むファイル名に変えてください.例えば,eop1_reportA_example.texであれば,

$ mv eop1_reportA_example.tex eop1_reportA_09B21999.tex

のような塩梅です.Linuxコマンドを入力する際は,TABキーによる入力補完も活用しましょう.

レポートの作成例を使ってみる

TeXファイルからの,PDF生成とPDF閲覧の流れを思い出してください.緑教科書や,以下のページも参考にしてください.

必要な個所を抜粋しておきます.以下の例ではeop1_reportA_09B21999.texというファイルを扱っています.

$ edu-uplatex eop1_reportA_09B21999.tex
**** RUN: uplatex -interaction=nonstopmode -file-line-error -shell-escape -halt-on-error eop1_reportA_09B22999.tex
This is e-upTeX, Version 3.14159265-p3.8.2-u1.25-190131-2.6 (utf8.uptex) (TeX Live 2019) (preloaded format=uplatex)
(中略)
-rw-r----- 1 09B21999 student 13427  4月  1 12:29 eop1_reportA_09B2199.log
LaTeX Warning: Reference `xxxx' on page 3 undefined on input line 253.
LaTeX Warning: Reference `xxxx' on page 4 undefined on input line 281.
LaTeX Warning: There were undefined references.
$

正しく動作していれば,PDFファイルができているはずです.確認しておきましょう.

$ ls -al eop1_reportA_09B21999.*
-rw-r----- 1 09B21999 student   1867  4月  1 12:29 eop1_reportA_09B22987.aux
-rw-r----- 1 09B21999 student  13796  4月  1 12:29 eop1_reportA_09B22987.dvi
-rw-r----- 1 09B21999 student  13427  4月  1 12:29 eop1_reportA_09B22987.log
-rw-r----- 1 09B21999 student 145236  4月  1 12:29 eop1_reportA_09B22987.pdf
-rw-r----- 1 09B21999 student  14722  4月  1 12:29 eop1_reportA_09B22987.synctex.gz
-rw-r----- 1 09B21999 student  16458  4月  1 12:25 eop1_reportA_09B22987.tex
$

少なくとも,PDFファイルの方がTeXファイルより新しい日付になっていることを確認してください.

注釈

edu-uplatexは,演習室でのみ利用可能な専用コマンドです.内部処理的にはuplatexを2回,dvipdfmxを1回実行しています.cf.4.2. LaTeXを用いた文書作成(詳細版)

さて,PDFファイルの閲覧は,以下のコマンドですね.

$ evince eop1_reportA_09B21999.pdf &
$

キー入力は,evi[TAB][SPACE]eop[TAB]p[TAB]&ぐらいで済むはずです.楽をしましょう.

また,最後に&をつけてevinceを実行している点にも注意してください.プログラムを起動したまま,次のコマンド実行ができます.このことは,後の操作で大きな意味を持ちます.

注釈

&をつけ忘れた時は,端末画面内でC-zの後で,bgコマンド,です.

レポートを書く

evinceは開いたまま,Emacs を使って,TeXファイルを編集してみましょう.

$ emacs eop1_reportA_09B21999.tex &
# あるいは,Emacs の GUI で新しいバッファとして開いても結構です.
  • タイトル部分について,自分の名前と学生番号に変えてください.

  • ファイルを保存してください.C-x C-sでしたね.(texファイルは開いたままです.閉じないように!)

  • 端末画面に戻り,edu-uplatexでPDF生成してください.

  • 開いていたevinceの画面に戻ってください.

evinceで閲覧してたPDFファイルが,自動で更新されていることを確認できましたか?レポート執筆中は,わざわざ Emacs を閉じたり,Evince を閉じる必要はありません.効率よく作業しましょう.

注釈

自習環境で作業している人は,利用しているPDF閲覧アプリの挙動に注意してください.稀に,PDFファイルを開いたままだと,PDF再生成ができないことがあります.(ファイルロック機構のため)

練習2-1 文字列操作関数 split() の作成

文字列STRを文字列中の文字SEPで区切って,配列RET[]に格納する関数split()を作成せよ.ただし,分割後の要素数は最大MAXまでとし,実際に分割された要素数を戻り値とすること.

また,split()の動作をテストするmain()関数を書け.どのような文字列を引数としてsplit()をテストすればよいか考えること.

/**
 * 文字列 STR を文字列中の文字 SEP で区切る.
 * 区切った結果の文字列は,...
 * 引数 MAX は,...
 * 戻り値: ...
 *    ※※ この1行は消す....で省略されている箇所も,仕様を踏まえて,記載すること.※※
 */
int split(char *str, char *ret[], char sep, int max)
{
    // ... ここを埋める
}

int main()
{
  // ... split をテストする
}

注釈

split()を作ったら,subst()の時と同じように,必ず動作確認のためのテストをしましょう.つまり,split()を呼び出すmain()関数が必要だ,ということです.このmain()関数は,課題プログラム完成品のそれとは,当然異なるものになるでしょうし,ここで作ったmain()は,最終的な課題プログラムには現れません.それだけ聞くと,余分な手間が増えて時間がかかるだけでは,,,と思う人もいるかもしれません.しかし,ここで惜しんだ手間は,原因不明のバグとして,のちに手痛くしっぺ返しを受けることになります.動作テストを重ねながら作ることが,まとまった量のプログラムを手早く作りあげるコツです.

» 解答例(練習2-1)

練習2-2 1行入力関数 get_line() の作成

標準入力 (stdin) から1行読んで,文字配列LINEに格納する関数get_line()を作成せよ.

  • 戻り値は,成功時 1, 失敗時(もう読む行がない) 0 とする.

  • get_line()実行後の文字配列 LINE には,改行コード('\n') は含まないものとする.

  • 簡単のため,「入力の1行の長さは,改行コード('\n')を含んで1024文字以内」という追加仕様を与えてもよい.ただし,万が一1024文字を越えた場合でも,バッファオーバーランは起こしてはならない.

また,get_line()をテストするmain()関数を書け.

/**
 * ※※ get_line()関数の説明としてふさわしいコメント文を書く【この1行は消す】 ※※
 */
int get_line(char *line)
{
    // ... ここを埋める
}

int main()
{
  // ... get_line をテストする
}

注釈

Linuxの端末画面では,Ctrl + dにより『キーボード入力は終了する』という信号を送ることができる.(キー入力の後で,Enterキーを押す必要がある場合もある.)

» 解答例(練習2-2)

練習2-3 split()get_line() の結合

get_line()関数で得たCSV入力行を,split()関数で分割するという,一連の流れをテストしたい.

そのためのmain()関数を記述せよ.入力行が尽きるまで何行でも処理できること.

注釈

プログラムを作成したら,キーボードからCSVのテストケースを入力する代わりに,練習1-1でダウンロードしたsample.csvを入力としてテストしてみるのもよいでしょう.

例えば,以下の例の2行目では,sample.csvの先頭10行をキーボードから入力した場合とほぼ等価の動作をします.

$ gcc -Wall -o get_line-and-split get_line-and-split.c
$ head -N 10 | ./get_line-and-split

» 解答例(練習2-3)