レポート課題

以下の課題を C, C++, Java のどれかの言語を使って作りなさい。

注意: Windows の API は使用しないで作って下さい。

課題1

レポート締切日: 2006年11月29日20:00

提出先: レポートボックス

ファイルを読み込み、各行が逆順に出るようなプログラムを書きなさい。 作成したプログラムに対して、空の入力と、作成したプログラム本体のソース コードを入力し、出力結果を報告しなさい。 なお、ファイルの読み込み、出力は標準入出力が望ましい。 また、絶対に、一行の文字数や、行数の制限を行わない事。 同じファイルを二回以上オープンしない事。 但し、メモリに異常が発生した場合は、検知し、確実に異常終了させる事。

注意

一文字の処理に、文字列の文字数に比例した時間かかったり、一行の処理に 全体の行数分の時間がかかるようなプログラムは大幅に減点します。

C++ の注意点

行の入力には getline を使うのが簡単です。 坂本は 18 行で作りました。

Java の注意点

行の入力には java.io.BufferedReader クラスを使うと便利です。 System.in を使って InputStreamReader オブジェクトを作ります。 また、入力メソッドは java.lang.IOException 例外を投げますが、この処理は行 わず、 main メソッドの定義時に throws IOException を指定すると簡単です。 Exception を catch するだけしておいて、利用者にはなにも起きてないよう な振舞いをするプログラムを作るのは止めましょう。 坂本は 17 行で作りました。

C の注意点

行の入力を得るため、制限のない文字列を表現する線形リストを作る必要があ ります。 これはキューのように振舞いますが、読み出しは常に先頭からで、文字の追 加は常に最後尾になります。 このような入力をスタックに貯めていきます。 したがって、講義資料にあるように行自体をグローバル変数で作るのはまずい です。 そのため、行の先頭を指すポインタと、最後を指すポインタの組からなる構造 体を作り、この構造体を行と同一します。 そして、追加、表示などの関数はこの構造体へのポインタに対して作る事にし ます。 なお、行だけでもそれなりに複雑になりますので、別ファイルに分け、単独で テストした方が良いと思われます。

坂本は 3 ファイル、 144 行で作りました。但し、さらに 21 行のテスト用ファ イルも作っています。

実行例

入力

#include <stdio.h>
int main(void){
  printf("Hello World\n");
  return 0;
}

出力

}
  return 0;
  printf("Hello World\n");
int main(void){
#include <stdio.h>

レポート作成上の注意点

  1. どのプログラミング言語で書くのかあらかじめはっきりしておくこと
  2. プログラミングのレポートでは必ずプログラムの説明をすること。 その時に、一行一行を日本語に直訳するのではなく、データの読み込みとか、 出力とかの部分に分割し、機能毎に使用した手法を説明すること。 プログラム中にコメントを入れてもプログラムの説明とはみなさないので注意 する事。
  3. 「問題を解きなさい」という問に対して「解きました。合ってました」で は正解ではないことはわかるはず。 「テストしなさい」という問に対しては、テストの方法の説明、実際のテスト の実施方法、テスト結果、検証などを説明して下さい。
  4. 考察は必ず書いて下さい。 ネタがない人は以下を参考にして下さい。
  5. 不必要なことはなるべく書かない事。C++, Java をプログラミング言語に 選んだ場合、本文は 10 ページ程度(プログラム、実行結果は付録)が標準とな るはずです。 長過ぎるレポートは減点します。またなるべく両面印刷にしてください。 但し、文字は必要以上に小さくしない事。レポート本文の文字は 10 ポイント 以上のものを使う事。

課題2

(2006/12/20) 設問の条件を緩くするよう、注意を追記しました。

(2006/12/18) 実行例を訂正しました。

(2006/12/8) Java 1.4 に関して追記しました。

レポート締切日: 2007年1月10日20:00 但し 4 年生以上は冬休み中にやりとりできる e-mail アドレスを表紙に記入して 2006年12月20日 20:00

提出先: レポートボックス

ファイルを読み込み、英字のみか、先頭が英字で二文字目以降が英字または数 字である文字列を抽出し、文字列の長さが長い順に並べ、その文字列の頻度と 共に表示するプログラムを作成したい。 但し、文字列の長さが同じものに関しての順序は任意で良い。 以下の設問にしたがって回答しなさい。

実行例

入力


#include <stdio.h>
#include <ctype.h>
int main(void){
  int c0;
  char c1;
  c1='\0';
  b='\0';
  while((c0=getchar())!=EOF){
    if((!isalnum(c1))&&isalnum(c0)){
      printf("\n");
    }
    if(isalnum(c0)){
      printf("%c",c0);
    }
    c1=c0;
  }
  return 0;
}

出力

getchar:1
include:2
isalnum:3
printf:2
return:1 
stdio:1 
while:1
ctype:1
char:1
main:1 
void:1
EOF:1
int:2 
if:2
c1:4
c0:6
h:2
n:1
c:1

設問

  1. ファイルを読み込み、英字のみか、先頭が英字で二文字目以降が英字または数 字である文字列を出力するプログラムを作りなさい。

    出力例

    include
    stdio
    h
    include
    ctype
    h
    int
    main
    void
    int
    c0
    char
    c1
    c1
    while
    c0
    getchar
    EOF
    if
    isalnum
    c1
    isalnum
    c0
    printf
    n
    if
    isalnum
    c0
    printf
    c
    c0
    c1
    c0
    return
    
  2. 文字列 s1,s2 の二つを比較する関数またはクラスを作りなさい。
    C 言語
    関数名を cmp とするとき、プロトタイプ宣言は次のようにします。
    
    int cmp(char *s1, char *s2);
    
    これを strcmp と同じ仕様となるようにします。 但し、文字列が長い順に並ぶようにするため、次のようにします。 s1 が s2 に較べて 1)短い、2)等しい、3)長い場合に、ゼロよりも 1)大きい、 2)等 しい、3)小さい整数を返すようにします。 但し、同じ長さの文字列だった場合、任意の順序を考え、真に等しい場合以外 は 0 以外の値を返すようにします。
    Java5 言語
    Java では java.util.Comparator を実装したクラスを作り、 compare を実装 してください。クラス名を Cmp とすると、次のような定義になります。
    
    class Cmp implements java.util.Comparator<String> {
        public int compare(String s1, String s2){
        // ここは自分で書く
        }
    }
    
    この compare メソッドは C 言語の場合と同様の値を出力するようにします。
    Java1.4 言語
    Java では java.util.Comparator を実装したクラスを作り、 compare を実装 してください。クラス名を Cmp とすると、次のような定義になります。
    
    class Cmp implements java.util.Comparator {
        public int compare(Object s1, Object s2){
        // ここは自分で書く
        }
    }
    
    この compare メソッドは C 言語の場合と同様の値を出力するようにします。
    C++ 言語
    C++ では s1 より s2 が長い時 true を返す関数を考えます。 但し、 s1 と s2 の長さが同じ時は、任意の順序を考え、s1 より s2 が「大 きい」と判断したときだけ、 true を返し、残りは false を返すようにしま す。 この関数を以下のようにクラスの operator() のオーバロードとして作成しま す。
    
    class Cmp : public std::binary_function<std::string,std::string,bool> {
    public:
      bool operator()(const std::string& s1, const std::string& s2){
      // ここは自分で書く
      }
    };
    

    なお、詳しい解説とテスト方法はこちら

  3. 題意を満たすプログラムを作りなさい。 プログラムを説明する時、1,2 で作成したプログラムをどのように活用したか も説明しなさい。
  4. 作成したプログラムに実行例の入力を与え、出力例と等しくなることを確 かめなさい。 また完全に等しくならない時は、 2 で作成したプログラムの説明をしながら 題意を満たしていることを説明しなさい。
  5. 作成したプログラムのソースコードを作成したプログラムに与え、出力を 求めなさい。

注意

ファイルの終端が改行の直後にあることを仮定しても構いません (販売するようなレベルのソフトウェアでは問題ですが)。

ファイルを二回以上 open しないこと。 0 回または 1 回で済ませて下さい。 また最適さを追求しすぎる必要はないですが、余りにも効率が悪すぎる手法を 使用した場合(バブルソートを使うなど)、講義の内容を理解していないと見な しますので、ご注意下さい。

ヒント

C++ を使う人は次がヒントになるかも知れません。

ヒント1

#include <iostream>
#include <locale>
using std::isalpha;
using std::isalnum;
int main(void){
    std::locale loc;
    std::cout << isalpha('2',loc)
	      << isalpha('a',loc)
	      << isalpha('#',loc)
	      <<std::endl;
    std::cout << isalnum('2',loc)
	      << isalnum('a',loc)
	      << isalnum('#',loc)
	      <<std::endl;
    return 0;
}

古い gcc を使っていると locale が入ってないため、上は動きません。 新しい mingw32 にバージョンアップを勧めますが、古い gcc のまま動かした い場合は下記のようにして下さい。 但し、結果は上とは異なります。


#include <iostream>
#include <cctype>
using std::isalpha;
using std::isalnum;
int main(void){
    std::cout << isalpha('2')
	      << isalpha('a')
	      << isalpha('#')
	      <<std::endl;
    std::cout << isalnum('2')
	      << isalnum('a')
	      << isalnum('#')
	      <<std::endl;
    return 0;
}

参考

坂本が解答を作成した時の行数を示します。

言語行数
C146
C++95
Java 556
Java 1.475

注意

なお、写したと思われるほど酷似したレポートが複数提出された場合、原著が どれかの調査を行わず、抽選で一通のレポートのみを評価 の対象とし、他は提出済みの不合格レポートとして再提出は課しません。 自分で意図せずに他人にコピーされてしまった場合も同様ですので、レポート の取り扱いについては十分に注意して下さい。


坂本直志 <sakamoto@c.dendai.ac.jp>
東京電機大学工学部情報通信工学科