本講義では 2 通のレポートで評価します。 レポートは A4 縦の様式で PDF 形式で作成して下さい。 またプログラムは C 言語で作成しなさい。
解答法として、分割コンパイルによる別ファイルにプログラムを書く方 法と、下記のテストプログラムに関数を追記する方法の二通りがあるが、 どちらでも良い。 プログラムの解説は、自分で作成した関数について行うこと。 こちらで提供したテストプログラムの説明は基本的には不要である。 但し、自分で作成した関数を説明するのに必要な内容には言及すること。
また、課題1で作成した関数については説明無しで使用して構わない。
なお、締め切り前は何度でも提出可能だが、締切後の提出は受け付けない。 複数の提出があった場合は、締切直前のファイルを有効とする。
文字列でラベルの付いた数値を、線形リストで管理し、ラベル毎に集計し、出力する。
始めに課題1で扱った ITEM 型を持つ線形リストを定義するため、 ITEMLIST 型を下記のように定める。
typedef struct itemlist {
ITEM item;
struct itemlist* next;
} ITEMLIST;
また、本課題において、next が NULL のノードを線形リストの番兵とする。 そのノードの item には何も入れないこととする。
本問題を解くにあたり、ヘッダファイル itemlist.h の他、テストデータを定義 したファイル data21.h と、 Makefile を後に与える。 また、課題1で提供、作成したファイルは説明無く使用する。
ITEMLIST の線形リストのポインタを与えると内容を表示する
void printList(ITEMLIST *p)
を作成せよ。
但し、ファイル名を printlist.c とする。
また、課題1で作成した関数を使用しても良い。
これと、下記のテストプログラムなどを結合して実行し、出 力結果を示せ。
#include "itemlist.h"
#include "data21.h"
int main(void){
printList(&d7);
return 0;
}
tokushima: 0 tokyo: 1 chiba: 3 tokyo: 2 chiba: 4 kanagawa: 3 tokyo: 5
malloc 関数を使用して、
ITEMLIST 型の初期化した領域のポインターを一つ得る
ITEMLIST* newList(void)
を作成せよ。
但し、メモリが確保できなかった時は NULL を返すこと。
この関数のファイル名を newlist.c とする。
また、課題1で作成した関数を使用しても良い。
これと、下記のテストプログラムなどを結合して実行し、出 力結果を示せ。
#include <stdio.h>
#include "itemlist.h"
#include "data21.h"
#define SIZE sizeof(data)/sizeof(data[0])
int main(void){
ITEMLIST *d[SIZE];
ITEMLIST *prev;
int i,j;
prev=NULL;
for(i=0;i<SIZE;i++){
if((d[i]=newList())==NULL){
fprintf(stderr,"メモリーエラー\n");
for(j=i-1;j>=0;j--){
free(d[j]);
}
return 1;
}
d[i]->item=data[i];
d[i]->next=prev;
prev=d[i];
}
printList(d[SIZE-1]);
for(i=SIZE-1;i>=0;i--){
free(d[i]);
}
return 0;
}
(null): 0 tokushima: 0 tokyo: 1 chiba: 3 tokyo: 2 chiba: 4 kanagawa: 3
ITEMLIST の線形リストのポインタを与えると、ポインタの先の線形リスト
の領域を free で開放する
void delList(ITEMLIST* p)
を作成せよ。
但し、ITEM 中の文字列のメモリは開放しなくて良い。
この関数のファイル名を dellist.c とする。
また、課題1で作成した関数を使用しても良い。
これと、下記のテストプログラムなどを結合して実行し、出 力結果を示せ。
#include <stdio.h>
#include "itemlist.h"
#include "data21.h"
#define SIZE sizeof(data)/sizeof(data[0])-1
int main(void){
ITEMLIST *d[SIZE];
ITEMLIST *prev;
int i,j;
prev=NULL;
for(i=0;i<SIZE;i++){
if((d[i]=newList())==NULL){
fprintf(stderr,"メモリーエラー\n");
if(i>0){
delList(d[i-1]);
}
return 1;
}
d[i]->item=data[i];
d[i]->next=prev;
prev=d[i];
}
printList(d[SIZE-1]);
delList(d[SIZE-1]);
return 0;
}
tokushima: 0 tokyo: 1 chiba: 3 tokyo: 2 chiba: 4 kanagawa: 3
ITEMLIST の線形リストのポインタと ITEM の要素
を与えると、線形リストの先頭にその要素を追加する
ITEMLIST* add(ITEMLIST* p, ITEM it)
を作成せよ。
但し、この関数は追加した要素のポインタを返すこととし(pと同じ)、
領域が確保できなかった時は NULL を返すとする。
この関数のファイル名を add.c とする。
また、課題1で作成した関数を使用しても良い。
これと、下記のテストプログラムなどを結合して実行し、出 力結果を示せ。
#include <stdio.h>
#include "itemlist.h"
#include "data21.h"
#define SIZE sizeof(data)/sizeof(data[0])-1
int main(void){
ITEMLIST *p;
int i,j;
if((p=newList())==NULL){
fprintf(stderr,"メモリーエラー\n");
return 1;
}
for(i=0;data[i].name!=NULL;i++){
if(add(p,data[i])==NULL){
fprintf(stderr,"メモリーエラー\n");
return 1;
}
}
printList(p);
delList(p);
return 0;
}
tokushima: 0 tokyo: 1 chiba: 3 tokyo: 2 chiba: 4 kanagawa: 3 tokyo: 5
ITEMLIST の線形リストのポインタと ITEM の要素
を与えると、線形リストの中を検索し、ITEM の nameが同じ要素のポインター
を返す
ITEMLIST* findList(ITEMLIST* p, ITEM it)
を作成せよ。
但し、発見できなかった場合は NULL を返すものとする。
この関数のファイル名を findlist.c とする。
また、課題1で作成した関数を使用しても良い。
これと、下記のテストプログラムなどを結合して実行し、出 力結果を示せ。
#include <stdio.h>
#include "itemlist.h"
#include "data21.h"
int main(void){
ITEMLIST *p;
ITEMLIST *q;
int i,j;
if((p=newList())==NULL){
fprintf(stderr,"メモリーエラー\n");
return 1;
}
for(i=0;data[i].name!=NULL;i++){
if(add(p,data[i])==NULL){
fprintf(stderr,"メモリーエラー\n");
delList(p);
return 1;
}
printf("list ");
printList(p);
printf("-----------\n");
for(j=0;data[j].name!=NULL;j++){
printf("item ");
printItem(&data[j]);
q=findList(p,data[j]);
printf("target ");
if(q==NULL){
printf("NULL\n");
}else{
printItem(&(q->item));
}
printf(".\n");
}
printf("==============\n");
}
delList(p);
return 0;
}
list tokyo: 5 ----------- item tokyo: 5 target tokyo: 5 . item kanagawa: 3 target NULL . item chiba: 4 target NULL . item tokyo: 2 target tokyo: 5 . item chiba: 3 target NULL . item tokyo: 1 target tokyo: 5 . item tokushima: 0 target NULL . ============== list kanagawa: 3 tokyo: 5 ----------- item tokyo: 5 target tokyo: 5 . item kanagawa: 3 target kanagawa: 3 . item chiba: 4 target NULL . item tokyo: 2 target tokyo: 5 . item chiba: 3 target NULL . item tokyo: 1 target tokyo: 5 . item tokushima: 0 target NULL . ============== list chiba: 4 kanagawa: 3 tokyo: 5 ----------- item tokyo: 5 target tokyo: 5 . item kanagawa: 3 target kanagawa: 3 . item chiba: 4 target chiba: 4 . item tokyo: 2 target tokyo: 5 . item chiba: 3 target chiba: 4 . item tokyo: 1 target tokyo: 5 . item tokushima: 0 target NULL . ============== list tokyo: 2 chiba: 4 kanagawa: 3 tokyo: 5 ----------- item tokyo: 5 target tokyo: 2 . item kanagawa: 3 target kanagawa: 3 . item chiba: 4 target chiba: 4 . item tokyo: 2 target tokyo: 2 . item chiba: 3 target chiba: 4 . item tokyo: 1 target tokyo: 2 . item tokushima: 0 target NULL . ============== list chiba: 3 tokyo: 2 chiba: 4 kanagawa: 3 tokyo: 5 ----------- item tokyo: 5 target tokyo: 2 . item kanagawa: 3 target kanagawa: 3 . item chiba: 4 target chiba: 3 . item tokyo: 2 target tokyo: 2 . item chiba: 3 target chiba: 3 . item tokyo: 1 target tokyo: 2 . item tokushima: 0 target NULL . ============== list tokyo: 1 chiba: 3 tokyo: 2 chiba: 4 kanagawa: 3 tokyo: 5 ----------- item tokyo: 5 target tokyo: 1 . item kanagawa: 3 target kanagawa: 3 . item chiba: 4 target chiba: 3 . item tokyo: 2 target tokyo: 1 . item chiba: 3 target chiba: 3 . item tokyo: 1 target tokyo: 1 . item tokushima: 0 target NULL . ============== list tokushima: 0 tokyo: 1 chiba: 3 tokyo: 2 chiba: 4 kanagawa: 3 tokyo: 5 ----------- item tokyo: 5 target tokyo: 1 . item kanagawa: 3 target kanagawa: 3 . item chiba: 4 target chiba: 3 . item tokyo: 2 target tokyo: 1 . item chiba: 3 target chiba: 3 . item tokyo: 1 target tokyo: 1 . item tokushima: 0 target tokushima: 0 . ==============
ITEMLIST の線形リストのポインタと ITEM の要素
を与えると、ITEM の name 毎に数を集計する
ITEMLIST* totalList(ITEMLIST* p, ITEM it)
を作成せよ。
但し、この関数は集計先の要素のポインタを返すこととし(pと同じ)、
領域が確保できなかった時は NULL を返すとする。
この関数のファイル名を totallist.c とする。
また、課題1で作成した関数を使用しても良い。
これと、下記のテストプログラムなどを結合して実行し、出 力結果を示せ。
#include <stdio.h>
#include "itemlist.h"
#include "data21.h"
int main(void){
ITEMLIST *p;
int i;
if((p=newList())==NULL){
fprintf(stderr,"メモリーエラー\n");
return 1;
}
for(i=0;data[i].name!=NULL;i++){
printf("item ");
printItem(&data[i]);
if(totalList(p,data[i])==NULL){
fprintf(stderr,"メモリーエラー\n");
delList(p);
return 1;
}
printList(p);
printf("-----------\n");
}
delList(p);
return 0;
}
tem tokyo: 5 tokyo: 5 ----------- item kanagawa: 3 kanagawa: 3 tokyo: 5 ----------- item chiba: 4 chiba: 4 kanagawa: 3 tokyo: 5 ----------- item tokyo: 2 chiba: 4 kanagawa: 3 tokyo: 7 ----------- item chiba: 3 chiba: 7 kanagawa: 3 tokyo: 7 ----------- item tokyo: 1 chiba: 7 kanagawa: 3 tokyo: 8 ----------- item tokushima: 0 tokushima: 0 chiba: 7 kanagawa: 3 tokyo: 8 -----------
#include "item.h"
typedef struct itemlist {
ITEM item;
struct itemlist* next;
} ITEMLIST;
void printList(ITEMLIST* p);
ITEMLIST* newList(void);
void delList(ITEMLIST* p);
ITEMLIST* add(ITEMLIST* p, ITEM item);
ITEMLIST* findList(ITEMLIST* p, ITEM item);
ITEMLIST* totalList(ITEMLIST* p, ITEM it);
#include <stdlib.h>
#include "data2.h"
ITEMLIST d0={{0},NULL};
ITEMLIST d1={{t1,5},&d0};
ITEMLIST d2={{"kanagawa",3},&d1};
ITEMLIST d3={{"chiba",4},&d2};
ITEMLIST d4={{t2,2},&d3};
ITEMLIST d5={{"chiba",3},&d4};
ITEMLIST d6={{"tokyo",1},&d5};
ITEMLIST d7={{t3,0},&d6};
CC=gcc
mondai26.exe: mondai26.o
mondai26.exe: printitem.o eq.o
mondai26.exe: printlist.o newlist.o dellist.o add.o findlist.o totallist.o
$(CC) -o $@ $^
mondai25.exe: mondai25.o
mondai25.exe: printitem.o eq.o
mondai25.exe: printlist.o newlist.o dellist.o add.o findlist.o
$(CC) -o $@ $^
mondai24.exe: mondai24.o
mondai24.exe: printitem.o
mondai24.exe: printlist.o newlist.o dellist.o add.o
$(CC) -o $@ $^
mondai23.exe: mondai23.o
mondai23.exe: printitem.o
mondai23.exe: printlist.o newlist.o dellist.o
$(CC) -o $@ $^
mondai22.exe: mondai22.o
mondai22.exe: printitem.o
mondai22.exe: printlist.o newlist.o
$(CC) -o $@ $^
mondai21.exe: mondai21.o
mondai21.exe: printitem.o
mondai21.exe: printlist.o
$(CC) -o $@ $^
clean:
rm *.o *.exe
解答法として、分割コンパイルによる別ファイルにプログラムを書く方 法と、下記のテストプログラムに関数を追記する方法の二通りがあるが、 どちらでも良い。 プログラムの解説は、自分で作成した関数について行うこと。 こちらで提供したテストプログラムの説明は基本的には不要である。 但し、自分で作成した関数を説明するのに必要な内容には言及すること。
なお、レポートは締め切り後も提出できます。 同じファイル名で複数のバージョンが存在できます。 締め切り内に採点可能なレポートがある場合は、最も締切に近いものだけを採 点します。 締め切り内に有効なレポートがない場合、最も新しいレポートを遅れレポー トとして減点して採点します。
文字列でラベルの付いた数値を、ラベル毎に集計し、出力する。
始めにラベル付きの数値のデータ型 ITEM を下記のように定める。
typedef struct{
char* name;
int num;
} ITEM;
name メンバはラベルを表す文字列、num メンバは数値を意味する。
本問題を解くにあたり、ヘッダファイル item.h の他、テストデータを定義 したファイル data.h と、 Makefile を後に与える。
ITEM の変数のポインタを与えると内容を表示する
void printItem(ITEM *p)
を作成せよ。
但し、ファイル名を printitem.c とする。
これと、下記のテストプログラム, item.h, data.h を結合して実行し、出 力結果を示せ。
#include "item.h"
#ifndef DATAFILE
#include "data.h"
#endif
#if DATAFILE == 2
#include "data2.h"
#endif
int main(void){
printItem(&data[0]);
printItem(&data[1]);
printItem(&data[2]);
printItem(&data[3]);
return 0;
}
tokyo: 5 kanagawa: 3 chiba: 4 tokyo: 2
ITEM の配列を与えると全て内容を表示する関数
void printItems(ITEM *p)
を作成せよ。
但し、ITEM 配列の最後には番兵として、 name メンバが NULL である要素が
含まれているとする。
#include "item.h"
#ifndef DATAFILE
#include "data.h"
#endif
#if DATAFILE == 2
#include "data2.h"
#endif
int main(void){
printItems(data);
return 0;
}
tokyo: 5 kanagawa: 3 chiba: 4 tokyo: 2 chiba: 3 tokyo: 1
ITEM の入っている2つの変数のポインタが与えられた時、
どちらかが一方が NULL なら 0とし、
それぞれの name メンバが一致していたら 1, 一致してなかったら 0 を返
す関数
int eq(ITEM* a, ITEM* b)
を作成せよ。
なお、作成にあたって、講義で取り上げてない strcmp 関数を説明なしに
使用しても良い。
#include <stdio.h>
#include <stdlib.h>
#include "item.h"
#ifndef DATAFILE
#include "data.h"
#endif
#if DATAFILE == 2
#include "data2.h"
#endif
int main(void){
ITEM *p;
ITEM *q;
for(p=data; p->name != NULL; p++){
for(q=data; q->name != NULL; q++){
printf("%d ",eq(p,q));
}
printf("\n");
}
return 0;
}
1 0 0 1 0 1 0 1 0 0 0 0 0 0 1 0 1 0 1 0 0 1 0 1 0 0 1 0 1 0 1 0 0 1 0 1
ITEM の配列 dic に対して、 ITEM の変数 key の name メンバと一致してい
る要素を検索し、存在すればそのdic 内のポインタを、検索中に name が
NULL である番兵まで到達すればその番兵のポインタを返す関数
ITEM* find(ITEM* dic, ITEM* key)
を作成せよ。
なお、作成にあたって、 1-3 で作成した eq 関数を使用して良い。
#include <stdlib.h>
#include "item.h"
#ifndef DATAFILE
#include "data.h"
#endif
#if DATAFILE == 2
#include "data2.h"
#endif
int main(void){
ITEM data2={"ibaragi",1};
ITEM* p;
for(p=data; p->name != NULL; p++){
printItem(find(data,p));
}
printItem(find(data,&data2));
return 0;
}
tokyo: 5 kanagawa: 3 chiba: 4 tokyo: 5 chiba: 4 tokyo: 5 (null): 0
ITEM の集計甩配列 dic と、ITEM の配列である入力データ data を与えると、
data の各要素に対して、 name メンバ毎に num を集計する関数
void total(ITEM* dic, ITEM* data)
を作成せよ。
なお、 1-4 の find などの、各問題で既に作成した関数は自由に説明なしに
利用して良い。
#include "item.h"
#ifndef DATAFILE
#include "data.h"
#endif
#if DATAFILE == 2
#include "data2.h"
#endif
int main(void){
ITEM result[48]={0};
total(result,data);
printItems(result);
return 0;
}
tokyo: 8 kanagawa: 3 chiba: 7
typedef struct {
char *name;
int num;
} ITEM;
void printItem(ITEM* p);
void printItems(ITEM* p);
int eq(ITEM* a, ITEM* b);
ITEM* find(ITEM* dic, ITEM* key);
void total(ITEM* dic, ITEM* data);
#include <stdlib.h>
ITEM data[]={{"tokyo",5},{"kanagawa",3},{"chiba",4},{"tokyo",2},{"chiba",3},{"tokyo",1},{NULL,0}};
CC=gcc
mondai15.exe: mondai15.o total.o find.o eq.o printitems.o printitem.o
$(CC) -o $@ $^
mondai14.exe: mondai14.o find.o eq.o printitems.o printitem.o
$(CC) -o $@ $^
mondai13.exe: mondai13.o eq.o
$(CC) -o $@ $^
mondai12.exe: mondai12.o printitems.o printitem.o
$(CC) -o $@ $^
mondai11.exe: mondai11.o printitem.o
$(CC) -o $@ $^
clean:
rm *.o *.exe
mondai15.o: item.h data.h
mondai14.o: item.h data.h
mondai13.o: item.h data.h
mondai12.o: item.h data.h
mondai11.o: item.h data.h
printitem.o: item.h
printitems.o: item.h printitem.c
eq.o: item.h
find.o: item.h eq.c
total.o: item.h find.c
学生からの質問を受けた結果、mondai11.cからmondai15.cに関して、問題通 りに作らな くても同じ結果例になるものが容易に作れることがわかった。 そのため、mondai11.cからmondai15.cまでに変更を加えた。 但し、変更前、変更後とも、コンパイルオプションを加えない限りは同じプ ログラムが生成される。
課題の目標は設問のとおりにプログラムを作ることであり、実行結果が等し いプログラムであれば全てが合格するわけではない。 その意味で、この追加テストは必須ではなく、レポートに反映しなくても良 い。 一方、理論的に、完璧なプログラムテストは存在しないので、プログラムテ ストは常に目安に過ぎない。 その意味で、よりよいプログラムテストを使うことには意味がある。 ブラックボックステストでは、通らないのはダメであるが、ダメなプログラム でも通ってしまうものがある。
#include <stdlib.h>
char t1[]="tokyo";
char t2[]="tokyo";
char t3[]="tokushima";
ITEM data[]={{t1,5},{"kanagawa",3},{"chiba",4},{t2,2},{"chiba",3},{"tokyo",1},{t3,0},{NULL,0}};
tokyo: 5 kanagawa: 3 chiba: 4 tokyo: 2
tokyo: 5 kanagawa: 3 chiba: 4 tokyo: 2 chiba: 3 tokyo: 1 tokushima: 0
1 0 0 1 0 1 0 0 1 0 0 0 0 0 0 0 1 0 1 0 0 1 0 0 1 0 1 0 0 0 1 0 1 0 0 1 0 0 1 0 1 0 0 0 0 0 0 0 1
tokyo: 5 kanagawa: 3 chiba: 4 tokyo: 5 chiba: 4 tokyo: 5 tokushima: 0 (null): 0
tokyo: 8 kanagawa: 3 chiba: 7 tokushima: 0