本講義では 2 通のレポートで評価します。 レポートは A4 縦の様式で PDF 形式で作成して下さい。 またプログラムは C 言語で作成しなさい。
解答法は課題1と同等である。 但し、課題1で作成したプログラムを使用、結合して良く、またその際には、 課題1のプログラムの詳細の説明は省いてよい。
問題の最後に、本課題で必要なヘッダファイル kadai2.h, ekilist.h と Makefile を示す。 課題で作成する関数は「関数名.c」というファイルに入れられる前提としている。
本課題で使用するヘッダファイル kadai2.h (後述)には次の構造体が定義されてい る。
typedef struct list {
char* eki;
struct list* next;
} LIST;
これを使用した線形リストを処理するプログラムを作成する
また、プログラムテスト用にekilist.h(後述)が定義されている。
LIST を用いて作成した線形リストについて、
中に入っている駅名を eki1 --- eki2 --- eki3 のように3つのハイフンで
区切って表示し、最後、改行する関数
void printekilist(LIST* p)
を作成
をprintekilist.cというファイルに作成せよ。
なお、空のリストを受け取った場合は、改行のみすることとする。
これと、下記のテストプログラム, kadai2.h, ekilist.h を結合して実行し、出 力結果を示せ。
#include <stdlib.h>
#include "kadai2.h"
#include "ekilist.h"
int main(void){
LIST **p;
for(p=ekilists;*p!=NULL;p++){
printekilist(*p);
}
return 0;
}
kitasenju ueno --- kitasenju tokyo --- ueno --- kitasenju ikebukuro --- tokyo --- ueno --- kitasenju shinjuku --- ikebukuro --- tokyo --- ueno --- kitasenju
LIST を用いて作成した線形リストについて、
中に入っている駅間の料金を課題1で示した二次元配列 ryokin に基づいて
取得し、合算した値を返す関数int listryokin(LIST* p)
をlistryokin.cというファイルに作成せよ。
なお、空のリストを受け取った場合、1駅だけのリストの場合は 0 を返すこ
ととする。
これと、下記のテストプログラム, kadai2.h, ekilist.h, eki.c を結合して実行し、出力結果を示せ。
なお、課題1で作成した ekikan, search などを使用しても良い
#include <stdio.h>
#include <stdlib.h>
#include "kadai2.h"
#include "ekilist.h"
int main(void){
LIST **p;
for(p=ekilists;*p!=NULL;p++){
printekilist(*p);
printf("%d\n",listryokin(*p));
}
return 0;
}
0 kitasenju 0 ueno --- kitasenju 180 tokyo --- ueno --- kitasenju 350 ikebukuro --- tokyo --- ueno --- kitasenju 560 shinjuku --- ikebukuro --- tokyo --- ueno --- kitasenju 730
LIST の空のノードを作る関数LIST* newnode(void)
をnewnode.cというファイルに作成せよ。
これと、下記のテストプログラム, kadai2.h, eki.c を結合して実行し、出 力結果を示せ。
#include <stdio.h>
#include <stdlib.h>
#include "kadai2.h"
void delnode(LIST* p){
if(p==NULL)return ;
delnode(p->next);
free(p);
}
int main(void){
LIST *p;
LIST *q;
int i;
if((p=newnode())==NULL){
fprintf(stderr,"メモリが確保できませんでした\n");
return 2;
}
for(i=0;i<N;i++){
if((q=newnode())==NULL){
fprintf(stderr,"メモリが確保できませんでした\n");
return 2;
}
q->next=p;
q->eki=eki[i];
p=q;
printekilist(p);
}
delnode(p);
return 0;
}
kitasenju ueno --- kitasenju tokyo --- ueno --- kitasenju ikebukuro --- tokyo --- ueno --- kitasenju shinjuku --- ikebukuro --- tokyo --- ueno --- kitasenju
LIST で作成された線形リストの管理変数 p と文字列を指すポインター e
より、線形リストの最後にeを追加する
関数LIST* add(LIST* p, char* e)
をadd.cというファイルに作成せよ。
なお、戻り値として、新たな要素を追加した構造体のポインタを返すこと。
これと、下記のテストプログラム, kadai2.h, newnode.c, listryokin, eki.c を結合して実行し、出 力結果を示せ。
なお、課題1で作成した ekikan, search などを使用しても良い
#include <stdio.h>
#include <stdlib.h>
#include "kadai2.h"
void delnode(LIST* p){
if(p==NULL)return ;
delnode(p->next);
free(p);
}
int main(void){
LIST *p, *q;
int i;
if((p=newnode())==NULL){
fprintf(stderr,"メモリが確保できませんでした\n");
return 2;
}
for(i=0;i<N;i++){
if((q=add(p,eki[i]))==NULL){
fprintf(stderr,"メモリが確保できませんでした\n");
return 2;
}
printf("追加した駅は%s\n",q->eki);
printekilist(p);
printf("%d\n",listryokin(p));
}
delnode(p);
return 0;
}
追加した駅はkitasenju kitasenju 0 追加した駅はueno kitasenju --- ueno 180 追加した駅はtokyo kitasenju --- ueno --- tokyo 350 追加した駅はikebukuro kitasenju --- ueno --- tokyo --- ikebukuro 560 追加した駅はshinjuku kitasenju --- ueno --- tokyo --- ikebukuro --- shinjuku 730
#include "kadai1.h"
typedef struct list {
char* eki;
struct list* next;
} LIST;
void printekilist(LIST* p);
int listryokin(LIST* p);
LIST* newnode(void);
LIST* add(LIST* p, char* e);
LIST l0={NULL,NULL};
LIST l1={"kitasenju",&l0};
LIST l2={"ueno",&l1};
LIST l3={"tokyo",&l2};
LIST l4={"ikebukuro",&l3};
LIST l5={"shinjuku",&l4};
LIST* ekilists[]={&l0,&l1,&l2,&l3,&l4,&l5,NULL};
$(CC) -o $@ $^
の $(CC) の前には TAB 記号が一つ
だけ入っていることに注意する。これが空白記号に置き換わっていると動作しない。
ex24.exe: ex24.o printekilist.o eki.o newnode.o add.o listryokin.o ekikan.o search.o
$(CC) -o $@ $^
ex23.exe: ex23.o printekilist.o eki.o newnode.o
$(CC) -o $@ $^
ex22.exe: ex22.o printekilist.o listryokin.o eki.o ekikan.o search.o
$(CC) -o $@ $^
ex21.exe: ex21.o printekilist.o
$(CC) -o $@ $^
ex13.exe: ex13.o eki.o search.o ekikan.o keiyuryokin.o
$(CC) -o $@ $^
ex12.exe: ex12.o eki.o search.o ekikan.o
$(CC) -o $@ $^
ex11.exe: ex11.o eki.o search.o
$(CC) -o $@ $^
ex21.o: kadai2.h ekilist.h
ex22.o: kadai2.h ekilist.h
ex23.o: kadai2.h
ex24.o: kadai2.h
printekilist.o: kadai2.h
ryokin.o: ekikan.c
newnode.o: kadai2.h
add.o: kadai2.h
ex11.o: kadai1.h
ex12.o: kadai1.h
ex13.o: kadai1.h
ex14.o: kadai1.h
eki.o: kadai1.h
search.o: kadai1.h
ekikan.o: kadai1.h
keiyuryokin.o: kadai1.h
解答法として、分割コンパイルによる別ファイルにプログラムを書く方 法と、下記のテストプログラムに関数を追記する方法の二通りがあるが、 どちらでも良い。 プログラムの解説は、自分で作成した関数について行うこと。 こちらで提供したテストプログラムの説明は基本的には不要である。 但し、自分で作成した関数を説明するのに必要な内容には言及すること。 また前問で作成した関数については自由に使用して良い。
問題とテストプログラムの改変は不合格である。 なお、Makefile は使用してもしなくても良い。 また、プログラムを結合するためなどのやむを得ない必要な変更(include の代わりにプログラムを埋め込むなど)は許される。
問題の最後に、本課題で必要なヘッダファイル kadai1.h と Makefile を示す。 課題で作成する関数は「関数名.c」というファイルに入れられる前提としている。
なお、レポートは締め切り後も提出できます。 同じファイル名で複数のバージョンが存在できます。 締め切り内に採点可能なレポートがある場合は、最も締切に近いものだけを採 点します。 締め切り内に有効なレポートがない場合、最も新しいレポートを遅れレポー トとして減点の上採点します。
eki.c に駅名の配列と、駅間の運賃の二次元配列が記述されている。
#include "kadai1.h"
char* eki[N]={"kitasenju", "ueno", "tokyo", "ikebukuro", "shinjuku"};
int ryokin[N][N]={{0,180,230,230,320},
{180,0,170,180,210},
{230,170,0,210,210},
{230,180,210,0,170},
{320,210,210,170,0}};
文字配列の先頭番地を受け取り、配列ekiの中の該当する要素の添え字を返す
int search(char* name)
をsearch.cというファイルに作成せよ。
なお、発見できなかった場合は -1を返すものとする。
これと、下記のテストプログラム, kadai1.h, eki.c を結合して実行し、出 力結果を示せ。
#include <stdio.h>
#include <stdlib.h>
#include "kadai1.h"
int main(void){
char* testeki[]={"","ikebukuro","kitasenju", "shinjuku",
"shibuya","tokyo", "ueno",NULL};
char** p;
int e;
for(p=testeki; *p!=NULL; p++){
e = search(*p);
printf("%s駅の駅番号は%d\n",*p,e);
}
return 0;
}
駅の駅番号は-1 ikebukuro駅の駅番号は3 kitasenju駅の駅番号は0 shinjuku駅の駅番号は4 shibuya駅の駅番号は-1 tokyo駅の駅番号は2 ueno駅の駅番号は1
二つの駅名の文字配列の先頭番地を受け取り、その駅間の運賃を返す
int ekikan(char* name0, char* name1)
関数を作成せよ。
この関数のファイル名を ekikan.c とする。
これと、下記のテストプログラム, ekikan.c, eki.c, kadai1.h と必要なら ば search.c を結合して実行し、出力結果を示せ。
#include <stdio.h>
#include <stdlib.h>
#include "kadai1.h"
int main(void){
char* testekipair[][2]={{"ikebukuro","kitasenju"},
{"shinjuku","kitasenju"},
{"shinjuku","ueno"},
{"kitasenju","kitasenju"},
{"tokyo", "ueno"},
NULL};
char *(*p)[2];
int r;
for(p=testekipair; **p!=NULL; p++){
r = ekikan(**p,*(*p+1));
printf("%s駅と%s駅間の料金は%d\n",**p,*(*p+1),r);
}
return 0;
}
ikebukuro駅とkitasenju駅間の料金は230 shinjuku駅とkitasenju駅間の料金は320 shinjuku駅とueno駅間の料金は210 kitasenju駅とkitasenju駅間の料金は0 tokyo駅とueno駅間の料金は170
駅名を表す文字配列へのポインタの配列がNULLを番兵に持つものとする (NULL は stdlib.h に定義されているものとする)。
char* a[]={"kitasenju", "ueno", "tokyo", NULL};
このような文字配列ポインタの配列の番地を受け取り、
各駅を順に訪れる場合の運賃の合計を返す
int keiyuryokin(char** p)
を作成せよ。
この関数のファイル名を keiyuryokin.c とする。
これと、下記のテストプログラム, eki.c, kadai1.h の他、必要に応じて前問で作成した関数を結合して実行し、出力結果を示せ。
#include <stdio.h>
#include <stdlib.h>
#include "kadai1.h"
int main(void){
char* eki1[]={"kitasenju",NULL};
char* eki2[]={"kitasenju","ikebukuro",NULL};
char* eki3[]={"kitasenju","ueno","tokyo",NULL};
char* eki4[]={"kitasenju","shinjuku","tokyo","ueno",NULL};
char** testekiretsu[]={eki1,eki2,eki3,eki4,NULL};
char ***p;
char **q;
int r;
for(p=testekiretsu; *p!=NULL; p++){
for(q=*p; *q!=NULL; q++){
printf("%s駅",*q);
}
r = keiyuryokin(*p);
printf("間の料金は%d\n",r);
}
return 0;
}
kitasenju駅間の料金は0 kitasenju駅ikebukuro駅間の料金は230 kitasenju駅ueno駅tokyo駅間の料金は350 kitasenju駅shinjuku駅tokyo駅ueno駅間の料金は700
#define N 5
extern char* eki[N];
extern int ryokin[N][N];
int search(char* name);
int ekikan(char* name0, char* name1);
int keiyuryokin(char** p);
$(CC) -o $@ $^
の $(CC) の前には TAB 記号が一つ
だけ入っていることに注意する。これが空白記号に置き換わっていると動作しない。
ex13.exe: ex13.o eki.o search.o ekikan.o keiyuryokin.o
$(CC) -o $@ $^
ex12.exe: ex12.o eki.o search.o ekikan.o
$(CC) -o $@ $^
ex11.exe: ex11.o eki.o search.o
$(CC) -o $@ $^
ex11.o: kadai1.h
ex12.o: kadai1.h
ex13.o: kadai1.h
ex14.o: kadai1.h
eki.o: kadai1.h
search.o: kadai1.h
ekikan.o: kadai1.h
keiyuryokin.o: kadai1.h
なお、写したと思われるほど酷似したレポートが複数提出された場合、原著が どれかの調査を行わず、抽選で一通のレポートのみを評価 の対象とし、他は提出済みの不合格レポートとして再提出は課しません。 自分で意図せずに他人にコピーされてしまった場合も同様ですので、レポート の取り扱いについては十分に注意して下さい。