本講義では 2 通のレポートで評価します。 レポートは A4 縦の様式で PDF 形式で作成して下さい。 またプログラムは C 言語で作成しなさい。
課題1で作成した FIVEWS をメンバとして持つ線形リストを作成するため、 下記の構造体 ITEM を定義する(kadai2.h)
typedef struct item {
FIVEWS sentence;
struct item * next;
} ITEM;
線形リストは先頭のITEMから順に next メンバで次のITEM型の頂点 を指していく。 最終頂点は、next に NULL を入れるとし、その頂点の sentence は無視をするとする。 これを扱うため、先頭のITEMを指すポインタを関数に渡して処理をする。
以下の問題で作成したプログラムに対して、各問題で示されたテストプログ ラムの他、本課題の最後に示す kadai2.h, dataset2.c を結合して、実行結 果を出力すること。 なお、課題1で作成した関数を結合する際は、その関数の説明は不要である。
ITEM の線形リストのポインタを与えると内容を表示する
void printlist(ITEM *p)
を作成せよ。
但し、ファイル名を printlist.c とする。
また、課題1で作成した printfivewsなどの関数を使用しても良い。
作成した下記のテストプログラムと他のプログラムを結合して実行し、出 力結果を示せ。
#include <stdio.h>
#include <stdlib.h>
#include "kadai2.h"
int main(void){
ITEM i0,i1,i2,i3;
i3.sentence=data[2];
i3.next =&i2;
i2.sentence=data[1];
i2.next =&i1;
i1.sentence=data[0];
i1.next =&i0;
i0.next= NULL;
printlist(&i0);
printf("-----\n");
printlist(&i1);
printf("-----\n");
printlist(&i2);
printf("-----\n");
printlist(&i3);
printf("-----\n");
return 0;
}
----- 2023年05月25日18時30分58秒に先生が授業で課題を説明した ----- 2023年06月14日00時00分00秒に私は家でプログラムを作った 2023年05月25日18時30分58秒に先生が授業で課題を説明した ----- 2023年06月14日23時59分58秒に友達はオンラインでレポートを提出した 2023年06月14日00時00分00秒に私は家でプログラムを作った 2023年05月25日18時30分58秒に先生が授業で課題を説明した -----
malloc 関数を使用して、
nextメンバーがNULLになっているITEM 型の領域のポインターを一つ得る
ITEM* newitem(void)
を作成せよ。
但し、メモリが確保できなかった時は NULL を返すこと。
この関数のファイル名を newitem.c とする。
また、課題1で作成した関数を使用しても良い。
これと、下記のテストプログラムなどを結合して実行し、出 力結果を示せ。
#include <stdio.h>
#include <stdlib.h>
#include "kadai2.h"
int main(void){
ITEM *p[SIZE];
ITEM nil;
int i;
nil.next=NULL;
for(i=0; i<SIZE; i++){
p[i]=newitem();
if(p[i]==NULL){
fprintf(stderr,"メモリーを確保できませんでした\n");
return 1;
}
p[i]->sentence=data[i];
p[i]->next=&nil;
}
for(i=0; i<SIZE; i++){
printlist(p[i]);
printf("-----\n");
free(p[i]);
}
return 0;
}
2023年05月25日18時30分58秒に先生が授業で課題を説明した ----- 2023年06月14日00時00分00秒に私は家でプログラムを作った ----- 2023年06月14日23時59分58秒に友達はオンラインでレポートを提出した -----
ITEM の線形リストのポインタを与えると、ポインタの指す線形リスト
の領域を全て free で開放する
void dellist(ITEM* p)
を作成せよ。
但し、ITEM 中の文字列のメモリは開放しなくて良い。
この関数のファイル名を dellist.c とする。
また、課題1で作成した関数を使用しても良い。
これと、下記のテストプログラムなどを結合して実行し、出 力結果を示せ。
なお、正常に free できたかをテストすることは困難なので、作成した関数 が正答でなくても、このテストプログラムが正常に動作する場合がある。 テストプログラムが動作しても、関数が正しく作成されていない場合は減点 の対象になりうる。
#include <stdio.h>
#include <stdlib.h>
#include "kadai2.h"
int main(void){
ITEM* p[SIZE+1];
int i,j;
for(i=0;i<SIZE+1;i++){
for(j=0;j<i+1;j++){
if((p[j]=newitem())==NULL){
fprintf(stderr,"メモリーを確保できませんでした\n");
return 1;
}
p[j]->sentence=data[j-1];
if(j>0){
p[j]->next = p[j-1];
}
}
printlist(p[i]);
dellist(p[i]);
printf("------\n");
}
return 0;
}
------ 2023年05月25日18時30分58秒に先生が授業で課題を説明した ------ 2023年06月14日00時00分00秒に私は家でプログラムを作った 2023年05月25日18時30分58秒に先生が授業で課題を説明した ------ 2023年06月14日23時59分58秒に友達はオンラインでレポートを提出した 2023年06月14日00時00分00秒に私は家でプログラムを作った 2023年05月25日18時30分58秒に先生が授業で課題を説明した ------
ITEM の線形リストのポインタと FIVEWS の値
を与えると、指しているITEMの直前にその要素を追加する
ITEM* add(ITEM *p, FIVEWS s)
を作成せよ。
但し、この関数は追加した要素のポインタを返すこととし(pと同じ)、
領域が確保できなかった時は NULL を返すとする。
この関数のファイル名を add.c とする。
また、課題1で作成した関数を使用しても良い。
これと、下記のテストプログラムと
課題1の dataset.c と課題1で作成した
FIVEWS randomfivews(void)
などを結合して実行し、出
力結果を示せ。
#include <stdio.h>
#include <stdlib.h>
#include "kadai2.h"
int main(void){
ITEM *list;
ITEM *p;
int i;
srand(time(NULL));
if((list = newitem())==NULL){
fprintf(stderr,"メモリーを確保できませんでした\n");
return 1;
}
for(i=0;i<5;i++){
if((p=add(list,randomfivews()))==NULL){
fprintf(stderr,"メモリーを確保できませんでした\n");
return 1;
}
printfivews(p->sentence);
printlist(list);
printf("-----\n");
}
dellist(list);
return 0;
}
この出力はランダムに生成されるので、実行するたびに変化する。 但し、問題の条件通りにプログラムが作られている場合は、特定の秩序が ある。
2023年05月25日18時30分58秒に友達は家で課題を説明した 2023年05月25日18時30分58秒に友達は家で課題を説明した ----- 2023年06月14日00時00分00秒に先生がオンラインでプログラムを説明した 2023年06月14日00時00分00秒に先生がオンラインでプログラムを説明した 2023年05月25日18時30分58秒に友達は家で課題を説明した ----- 2023年06月14日23時59分58秒に私は家で課題を説明した 2023年06月14日23時59分58秒に私は家で課題を説明した 2023年06月14日00時00分00秒に先生がオンラインでプログラムを説明した 2023年05月25日18時30分58秒に友達は家で課題を説明した ----- 2023年05月25日18時30分58秒に先生が授業でプログラムを作った 2023年05月25日18時30分58秒に先生が授業でプログラムを作った 2023年06月14日23時59分58秒に私は家で課題を説明した 2023年06月14日00時00分00秒に先生がオンラインでプログラムを説明した 2023年05月25日18時30分58秒に友達は家で課題を説明した ----- 2023年06月14日00時00分00秒に友達は家でプログラムを作った 2023年06月14日00時00分00秒に友達は家でプログラムを作った 2023年05月25日18時30分58秒に先生が授業でプログラムを作った 2023年06月14日23時59分58秒に私は家で課題を説明した 2023年06月14日00時00分00秒に先生がオンラインでプログラムを説明した 2023年05月25日18時30分58秒に友達は家で課題を説明した -----
ITEM の線形リストのポインタと FIVEWS の要素
を与えると、ポインタで指した線形リストから順に日付を比較し、
FIVEWSの要素の日付と等しいか遅い要素の手前に追加する
ITEM* addchronologically(ITEM *p, FIVEWS s)
を作成せよ。
但し、この関数は追加した要素のポインタを返すこととし(pと同じ)、
領域が確保できなかった時は NULL を返すとする。
この関数のファイル名を addchronologically.c とする。
また、課題1で作成した関数を使用しても良い。
これと、下記のテストプログラムと
課題1の dataset.c と課題1で作成した
FIVEWS randomfivews(void)
などを結合して実行し、出
力結果を示せ。
また、課題1で作成した関数を使用しても良い。 特に、日付は time_t の値の大小で比較できる。
これと、下記のテストプログラムなどを結合して実行し、出 力結果を示せ。
#include <stdio.h>
#include <stdlib.h>
#include "kadai2.h"
int main(void){
ITEM *list;
ITEM *p;
int i;
srand(time(NULL));
if((list=newitem())==NULL){
fprintf(stderr,"メモリーを確保できませんでした\n");
return 1;
}
for(i=0;i<5;i++){
if((p=addchronologically(list,randomfivews()))==NULL){
fprintf(stderr,"メモリーを確保できませんでした\n");
return 1;
}
printfivews(p->sentence);
printlist(list);
printf("-----\n");
}
dellist(list);
return 0;
}
この出力はランダムに生成されるので、実行するたびに変化する。 但し、問題の条件通りにプログラムが作られている場合は、特定の秩序が ある。
2023年05月25日18時30分58秒に私は家でプログラムを説明した 2023年05月25日18時30分58秒に私は家でプログラムを説明した ----- 2023年06月14日00時00分00秒に私はオンラインで課題を作った 2023年05月25日18時30分58秒に私は家でプログラムを説明した 2023年06月14日00時00分00秒に私はオンラインで課題を作った ----- 2023年06月14日23時59分58秒に友達は家で課題を作った 2023年05月25日18時30分58秒に私は家でプログラムを説明した 2023年06月14日00時00分00秒に私はオンラインで課題を作った 2023年06月14日23時59分58秒に友達は家で課題を作った ----- 2023年06月14日23時59分58秒に友達はオンラインでレポートを作った 2023年05月25日18時30分58秒に私は家でプログラムを説明した 2023年06月14日00時00分00秒に私はオンラインで課題を作った 2023年06月14日23時59分58秒に友達はオンラインでレポートを作った 2023年06月14日23時59分58秒に友達は家で課題を作った ----- 2023年06月14日23時59分58秒に先生が授業でレポートを説明した 2023年05月25日18時30分58秒に私は家でプログラムを説明した 2023年06月14日00時00分00秒に私はオンラインで課題を作った 2023年06月14日23時59分58秒に先生が授業でレポートを説明した 2023年06月14日23時59分58秒に友達はオンラインでレポートを作った 2023年06月14日23時59分58秒に友達は家で課題を作った -----
kadai2.hはkadai1.hを読み込む
#include "kadai1.h"
typedef struct item {
FIVEWS sentence;
struct item * next;
} ITEM;
#define SIZE 3
void printlist(ITEM* p);
extern FIVEWS data[];
ITEM* newitem(void);
void dellist(ITEM* p);
ITEM* add(ITEM *p, FIVEWS s);
ITEM* addchronologically(ITEM *p, FIVEWS s);
#include "kadai2.h"
FIVEWS data[SIZE]={
{{2023,5,25,18,30,58},"先生が","授業で","課題を","説明した"}
,{{2023,6,14,0,0,0},"私は","家で","プログラムを","作った"}
,{{2023,6,14,23,59,58},"友達は","オンラインで","レポートを","提出した"}
};
ex25.exe: ex25.o addchronologically.o add.o randomfivews.o randoms.o dataset.o newitem.o dellist.o printlist.o printfivews.o time2str.o h2timet.o
$(CC) -o $@ $^
ex24.exe: ex24.o add.o randomfivews.o randoms.o dataset.o newitem.o dellist.o printlist.o printfivews.o time2str.o h2timet.o
$(CC) -o $@ $^
ex23.exe: ex23.o newitem.o dellist.o printlist.o dataset2.o printfivews.o time2str.o h2timet.o
$(CC) -o $@ $^
ex22.exe: ex22.o newitem.o printlist.o dataset2.o printfivews.o time2str.o h2timet.o
$(CC) -o $@ $^
ex21.exe: ex21.o printlist.o dataset2.o printfivews.o time2str.o h2timet.o
$(CC) -o $@ $^
ex14.exe: ex14.o printfivews.o time2str.o h2timet.o randomfivews.o randoms.o dataset.o
$(CC) -o $@ $^
ex13.exe: ex13.o printfivews.o time2str.o h2timet.o
$(CC) -o $@ $^
ex12.exe: ex12.o time2str.o h2timet.o
$(CC) -o $@ $^
ex11.exe: ex11.o time2str.o
$(CC) -o $@ $^
ex11.o: kadai1.h
ex12.o: kadai1.h
ex13.o: kadai1.h
ex14.o: kadai1.h
time2str.o: kadai1.h
h2timet.o: kadai1.h
printfivews.o: kadai1.h
randomfivews.o: kadai1.h
randoms.o: kadai1.h
dataset.o: kadai1.h
printlist.o: kadai2.h
ex21.o: kadai2.h
ex22.o: kadai2.h
ex23.o: kadai2.h
ex24.o: kadai2.h
newitem.o: kadai2.h
dellist.o: kadai2.h
add.o: kadai2.h
システムライブラリに関しては、授業で取り扱っていない内容を問う場合が ある。 システムライブラリに関して必要な情報は、適宜調査して補うこと。 また、C言語の動作環境により、必ずしも統一されていない場合があるが、 その場合は自分の環境で動作する情報を優先すること。
解答法として、分割コンパイルによる別ファイルにプログラムを書く方 法と、下記のテストプログラムに関数を追記する方法の二通りがあるが、 どちらでも良い。 プログラムの解説は、自分で作成した関数について行うこと。 こちらで提供したテストプログラムの説明は基本的には不要である。 但し、自分で作成した関数を説明するのに必要な内容には言及すること。
Makefile は使用してもしなくても良い。 また、問題そのものの改変は不合格であるが、プログラムを結合するためな どのやむを得ない必要な変更は許される。
問題の最後に、本課題で必要なヘッダファイル kadai1.h と Makefile を示す。 課題で作成する関数は「関数名.c」というファイルに入れられる前提としている。
なお、レポートは締め切り後も提出できます。 同じファイル名で複数のバージョンが存在できます。 締め切り内に採点可能なレポートがある場合は、最も締切に近いものだけを採 点します。 締め切り内に有効なレポートがない場合、最も新しいレポートを遅れレポー トとして減点の上採点します。
C言語の標準ライブラリに time.h という、時刻や日付を取り扱うものがある。 time_tはシステム時刻を表すデータ型であり、struct tm はtime_tと年月 日時分秒をやり取りするための構造体である。 また、補助的にサイズを表す size_t という型も定義される。
time 関数は現在のシステム時刻を time_t 型で返す関数である。
これを日本の標準的な表現である「2023年5月25日18時10分30秒」という文字
列に変換する
size_t time2str(char * st,size_t l, time_t t)
をtime2str.cというファイルに作成せよ。
ここで、作成する文字列を受け取るため、十分な長さの文字配列 st を予め
用意し、格納できる最大サイズを l で指定する。
また、関数の戻り値は、格納された文字数を表すとする(プログラムミスな
どで変換が失敗する場合は
-1
0
を返す)。
なお、作成において、システムライブラリで既に定義されている localtime
関数や strftime 関数を使用して良い(使用法は各自調査すること)。
なお、 struct tm で変数を宣言するときは、={0}で初期化すると良い。
これと、下記のテストプログラム, kadai1.h, time2str.c を結合して実行し、出 力結果を示せ。
#include <stdio.h>
#include <time.h>
#include "kadai1.h"
#define BUFSIZE 256
int main(void){
time_t t;
size_t ret;
char buff[BUFSIZE];
t=time(NULL);
ret=time2str(buff, BUFSIZE, t);
if(ret>0){
printf("%s\n",buff);
}else{
fprintf(stderr,"strftime エラー\n");
return -1;
}
return 0;
}
2023年05月25日18時10分30秒
構造体 HIDUKE を次のように定義する。
typedef struct {
int year,month,day,hour,min,sec;
} HIDUKE;
HIDUKE の構造体を受け取り、time_t の値を返す
time_t h2timet(HIDUKE h)
関数を作成せよ。
この関数のファイル名を h2timet.c とする。
なお、作成において、システムライブラリで既に定義されている mktime
関数を使用して良い(使用法は各自調査すること)。
これと、下記のテストプログラム, h2timet.c, time2str, kadai1.h を結合 して実行し、出力結果を示せ。
#include <stdio.h>
#include <time.h>
#include "kadai1.h"
#define BUFSIZE 256
int main(void){
time_t t;
size_t ret;
char buff[BUFSIZE];
HIDUKE h[]={{2023,5,25,18,10,30},{2022,1,1,0,0,0},{1999,12,31,23,59,59}
,{0}};
int i;
for(i=0;h[i].year!=0;i++){
t=h2timet(h[i]);
ret=time2str(buff, BUFSIZE, t);
if(ret>0){
printf("%s\n",buff);
}else{
fprintf(stderr,"strftime エラー\n");
return -1;
}
}
return 0;
}
2023年05月25日18時10分30秒 2022年01月01日00時00分00秒 1999年12月31日23時59分59秒
構造体 FIVEWS を次のように定義する。
typedef struct {
HIDUKE when;
char* w[4];
} FIVEWS;
この時、HIDUKEを年月日時分秒で表示した後に「に」を表示し、その後、w
で示される 4 つの文字列を順に表示し、改行する
void printfivews(FIVEWS f)
を作成せよ。
この関数のファイル名を printfivews.c とする。
これと、下記のテストプログラム, h2timet.c, time2str, kadai1.h を結合 して実行し、出力結果を示せ。
#include "kadai1.h"
int main(void){
FIVEWS fs[]={{{2023,5,25,18,30,58},"先生が","授業で","課題を","説明した"},
{{2023,6,14,0,0,0},"私は","家で","プログラムを","作った"},
{{2023,6,14,23,59,58},"友達は","オンラインで","レポートを","提出した"},
{{0}}};
FIVEWS *p;
for(p=fs; p->when.year!=0;p++){
printfivews(*p);
}
return 0;
}
2023年05月25日18時30分58秒に先生が授業で課題を説明した 2023年06月14日00時00分00秒に私は家でプログラムを作った 2023年06月14日23時59分58秒に友達はオンラインでレポートを提出した
下記のdataset.cに含まれているデータをランダムに組み合わせた FIVEWS型の
構造体を作成することを考える。
year属性が 0 の番兵を持つHIDUKE型の配列から、ランダムに要素を取り出す
HIDUKE randomhiduke(HIDUKE *p)
関数と
NULL の番兵を持つ char* 型の配列から、ランダムに要素を取り出す
char* randomstring(char **p)
関数は、下記に与えてある。
この時、ランダムな FIVEWS を返す関数
FIVEWS randomfivews(void)
を作成せよ。この関数のファイル名を randomfivews.c とする。
なお、提供してある関数や、extern 宣言しているグローバル変数
HIDUKE hidukes[],char** fourws[];
を使用して良い。
これと、下記のテストプログラム, printfivews.c time2str.c h2timet.c randoms.c dataset.c, kadai1.h を結合して実行し、出 力結果を示せ。
なお、dataset.c 中に文字列を追加しても良い。
#include <stdlib.h>
#include "kadai1.h"
HIDUKE hidukes[]={{2023,5,25,18,30,58},{2023,6,14,0,0,0},{2023,6,14,23,59,58},{0}};
char* who[]={"先生が","私は","友達は",NULL};
char* where[]={"授業で","家で","オンラインで",NULL};
char* what[]={"課題を","プログラムを","レポートを",NULL};
char* how[]={"説明した","作った","提出した",NULL};
char** fourws[]={who,where,what,how};
#include <stdlib.h>
#include "kadai1.h"
HIDUKE randomhiduke(HIDUKE* p){
int n=0;
HIDUKE *q=p;
while(q++->year!=0){n++;};
return p[(int)((double)rand()/RAND_MAX*n)];
}
char* randomstring(char** p){
int n=0;
char **q=p;
while(*q++!=NULL){n++;};
return p[(int)((double)rand()/RAND_MAX*n)];
}
#include <time.h>
#include <stdlib.h>
#include "kadai1.h"
#define N 10
int main(void){
FIVEWS f[N];
int i;
srand(time(NULL));
for(i=0; i<N; i++){
f[i]=randomfivews();
}
for(i=0; i<N; i++){
printfivews(f[i]);
}
return 0;
}
2023年05月25日18時30分58秒に友達は授業でレポートを作った 2023年06月14日00時00分00秒に友達はオンラインで課題を説明した 2023年06月14日00時00分00秒に先生が家でプログラムを作った 2023年06月14日00時00分00秒に友達は授業で課題を提出した 2023年06月14日23時59分58秒に友達は授業でプログラムを作った 2023年06月14日00時00分00秒に友達は授業でレポートを作った 2023年05月25日18時30分58秒に友達は家でプログラムを提出した 2023年05月25日18時30分58秒に先生がオンラインで課題を作った 2023年06月14日23時59分58秒に私は家でプログラムを説明した 2023年05月25日18時30分58秒に友達はオンラインで課題を提出した
#include <time.h>
typedef struct {
int year,month,day,hour,min,sec;
} HIDUKE;
size_t time2str(char * s,size_t l, time_t t);
time_t h2timet(HIDUKE h);
typedef struct {
HIDUKE when;
char* w[4];
} FIVEWS;
void printfivews(FIVEWS f);
FIVEWS randomfivews(void);
extern HIDUKE hidukes[];
extern char** fourws[];
HIDUKE randomhiduke(HIDUKE* p);
char* randomstring(char** p);
$(CC) -o $@ $^
の $(CC) の前には TAB 記号が一つ
だけ入っていることに注意する。これが空白記号に置き換わっていると動作しない。
ex14.exe: ex14.o printfivews.o time2str.o h2timet.o randomfivews.o randoms.o dataset.o
$(CC) -o $@ $^
ex13.exe: ex13.o printfivews.o time2str.o h2timet.o
$(CC) -o $@ $^
ex12.exe: ex12.o time2str.o h2timet.o
$(CC) -o $@ $^
ex11.exe: ex11.o time2str.o
$(CC) -o $@ $^
ex11.o: kadai1.h
ex12.o: kadai1.h
ex13.o: kadai1.h
ex14.o: kadai1.h
time2str.o: kadai1.h
h2timet.o: kadai1.h
printfivews.o: kadai1.h
randomfivews.o: kadai1.h
randoms.o: kadai1.h
dataset.o: kadai1.h
なお、写したと思われるほど酷似したレポートが複数提出された場合、原著が どれかの調査を行わず、抽選で一通のレポートのみを評価 の対象とし、他は提出済みの不合格レポートとして再提出は課しません。 自分で意図せずに他人にコピーされてしまった場合も同様ですので、レポート の取り扱いについては十分に注意して下さい。