ページ 1 / 1
複数の構造体について
Posted: 2013年5月23日(木) 00:47
by 小岩井
深夜に失礼します。
現在、C言語を勉強している者です。
課題が出たのですが、どう作ればよいかわからず困っています。
実行結果を
B300000
2000.01.01
2000.01.05
....
B300004
2000.01.05
2000.01.07
....
....
B300189
2000.01.01
2000.01.08
のようにしたいです。
以下がそのコードになります。
コード:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student_Entry
{
char number[8];
struct Student_Entry *next;
};
struct Date_Entry
{
int year;
int month;
int day;
struct Date_Entry *next;
};
main()
{
FILE *fp;
int f, i;
char buffer[1024];
char *table[1024];
fp = fopen("text.txt", "r");
i = 0;
while(1)
{
f = fscanf(fp, "%s", buffer);
if(fp == EOF) break;
if(buffer[0] == 'B')
{
table[i] = strdup(buffer);
}
else
{
table[i] = strdup(buffer);
i++;
}
}
fclose(fp);
}
授業中にStudent_EntryにDate_Entryを入れてあげてリストを作ればいいよ、と言われたのですがその方法もいまいちピンときません…。
授業では構造体、ハッシュ、ポインタ、リスト構造を学びましたがきちんと理解できていません。
どなたかご指摘のほうをよろしくお願いいたします。
Re: 複数の構造体について
Posted: 2013年5月23日(木) 01:31
by ぽこ
生徒番号と何らかの日付データ2つを持つ学生リストが有って、
リスト内のデータを全て表示する課題のように見えますが、
具体的な課題を提示してください。
Re: 複数の構造体について
Posted: 2013年5月23日(木) 07:47
by 小岩井
出席番号とその出席した日付をすべて出力しなさい、というのが課題です。
そして以下がその実行例になります。
(実行例)
./output
attend(標準入力)
B300001
2012.11.14
2012.11.7
2012-11-2
2012.10.17
2012.10.5
2012.10.3
2012.9.28
2012.9.26
2012.9.21
2012.6.1
2012.5.23
2012.5.18
2012.5.16
2012.5.11
2012.5.9
B300002
2012.12.19
2012.12.12
2012.12.5
....
メンバ変数は拡張しても可。
またtext.txtには
20120511
B300001
B300002
B300003
....
B300121
20120512
B300001
B300002
B300004
....
と、出席データが記入されてあります。
Re: 複数の構造体について
Posted: 2013年5月23日(木) 11:06
by non
小岩井 さんが書きました:授業中にStudent_EntryにDate_Entryを入れてあげてリストを作ればいいよ、と言われたのですがその方法もいまいちピンときません…。
おそらく、
コード:
struct Student_Entry
{
char number[8];
struct Date_Entry *date_entry;
struct Student_Entry *next;
};
struct Date_Entry
{
int year;
int month;
int day;
struct Date_Entry *next;
};
このような構造体にしろという意味だと思いますが、まずは、あなたの理解度として、普通の単方向リスト構造を作れますか?
たとえば、ファイルが
B300001
B300002
B300003
....
B300121
のように学籍番号だけだとして、学籍番号だけのリスト構造を作れますか?
Re: 複数の構造体について
Posted: 2013年5月23日(木) 23:33
by 小岩井
すみません。遅くなりました。
授業で扱ったサンプルをもとに作ってみました。
コード:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student_Entry
{
char number[8];
struct Student_Entry *next;
struct Date_Entry *date_entry;
char *str;
};
struct Date_Entry
{
int year;
int month;
int day;
struct Date_Entry *next;
};
void *add(char *str, struct Student_Entry *ptr)
{
struct Student_Entry *tmp;
while(ptr != NULL)
{
if(!strcmp((ptr->str),str)))
{
free(str);
return;
}
else
{
ptr = ptr -> next;
}
}
tmp = (struct Student_Entry*)malloc(sizeof(struct Student_Entry));
if(tmp = NULL)
{
printf("Nothing.\n");
exit(1);
}
ptr -> next = tmp;
tmp -> str = str;
tmp -> next = NULL;
}
main()
{
FILE *fp;
int f, i;
char buffer[1024];
char *table[1024];
fp = fopen("text.txt", "r");
i = 0;
while(1)
{
f = fscanf(fp, "%s", buffer);
if(fp == EOF) break;
if(buffer[0] == 'B')
{
table[i] = strdup(buffer);
}
else
{
table[i] = strdup(buffer);
i++;
}
}
fclose(fp);
}
Re: 複数の構造体について
Posted: 2013年5月24日(金) 09:02
by non
どこをどう突っ込んでいいやら、わかりませんが・・・・
コード:
struct Student_Entry
{
char number[8];
struct Student_Entry *next;
struct Date_Entry *date_entry;
char *str;
};
最後のメンバーstrは、何でしょ?入力ファイルには、それらしいのがないのですが。
仮に、名前があったとして、これはポインタです。実際に格納される領域はどうするのでしょうか?
add関数の中でfreeしているみたいだけど。
コード:
void *add(char *str, struct Student_Entry *ptr)
{
struct Student_Entry *tmp;
while(ptr != NULL)
{
if(!strcmp((ptr->str),str)))
{
free(str);
return;
}
else
{
ptr = ptr -> next;
}
}
tmp = (struct Student_Entry*)malloc(sizeof(struct Student_Entry));
if(tmp = NULL)
{
printf("Nothing.\n");
exit(1);
}
ptr -> next = tmp;
tmp -> str = str;
tmp -> next = NULL;
}
何をする関数だと説明してもらわないと、困ります。読む人に間違ったプログラムから想像しろといわれても・・・
この関数は何を返したいのですか?
26行のwhileを抜けるときは、ptrがNULLのはず。44行でptr->nextは参照できません。
Re: 複数の構造体について
Posted: 2013年5月24日(金) 09:26
by 小岩井
non さんが書きました:どこをどう突っ込んでいいやら、わかりませんが・・・・
コード:
struct Student_Entry
{
char number[8];
struct Student_Entry *next;
struct Date_Entry *date_entry;
char *str;
};
最後のメンバーstrは、何でしょ?入力ファイルには、それらしいのがないのですが。
仮に、名前があったとして、これはポインタです。実際に格納される領域はどうするのでしょうか?
add関数の中でfreeしているみたいだけど。
私が何か勘違いをしていたようです、すみません。
addはリストに出席番号を格納する関数です。
コード:
void *add(struct Student_Entry *ptr)
{
struct Student_Entry *tmp;
tmp = (struct Student_Entry*)malloc(sizeof(struct Student_Entry));
if(tmp = NULL)
{
printf("Nothing.\n");
exit(1);
}
ptr -> next = tmp;
tmp -> next = NULL;
return tmp;
}
Re: 複数の構造体について
Posted: 2013年5月24日(金) 09:55
by 小岩井
小岩井 さんが書きました:
コード:
void *add(struct Student_Entry *ptr)
{
struct Student_Entry *tmp;
tmp = (struct Student_Entry*)malloc(sizeof(struct Student_Entry));
if(tmp = NULL)
{
printf("Nothing.\n");
exit(1);
}
ptr -> next = tmp;
tmp -> next = NULL;
return tmp;
}
このままだと出席番号の配列numberにアクセス(言い方が合ってるか怪しいですが)できない気がします…。
なので、さきほどstrを使ってnumberにアクセスしたつもりでしたが、でもnextがあるし…と混乱していました。
そして、当然配列numberはポインタ型ではないので
tmp->number = number;
としても型が一致していないのでエラーが返ってきます。
このあたりで悩んでいます。
Re: 複数の構造体について
Posted: 2013年5月24日(金) 10:08
by non
小岩井 さんが書きました:
addはリストに出席番号を格納する関数です。
コード:
void *add(struct Student_Entry *ptr)
それなら、追加したい出席番号を関数に渡す必要があります。
渡すときに、本当に出席番号だけなら
コード:
void *add(char *addNumber,struct Student_Entry *ptr)
みたいにすればいいですね。最初のstrと同じってことになりますが。メンバーではないってことです。
Re: 複数の構造体について
Posted: 2013年5月24日(金) 18:44
by 小岩井
以下は出席番号を追加する関数number_addと日付を追加する関数date_addです。
コード:
void *number_add(char *add_Number, struct Student_Entry *ptr)
{
struct Student_Entry *tmp;
tmp = (struct Student_Entry*)malloc(sizeof(struct Student_Entry));
if(tmp = NULL)
{
printf("Nothing.\n");
exit(1);
}
ptr -> next = tmp;
tmp -> next = NULL;
return tmp;
//error:struct student has no member named 'add_id'というエラーが返ってきます
}
void *date_add(int year, int month, int day, struct Date_Entry *ptr)
{
struct Date_Entry *tmp;
tmp = (struct Date_Entry*)malloc(sizeof(struct Date_Entry));
if(tmp = NULL)
{
printf("Nothing.\n");
exit(1);
}
ptr -> next = tmp;
tmp -> year = year;
tmp -> month = month;
tmp -> day = day;
tmp -> next = ptr;
return tmp;
}
Student_Entry内のメンバではないのでエラーは当然ですが、number_add関数内にStudent_Entry型のポインタを作成してtmpに代入しても意味は…なさそうですね;ここもどうにかしたいです!
あと、date_add関数では日付を見ていきその中にある出席番号が既出ならその日付を返し、そうでなければその番号をStudent_Entryに追加していきたいです。
Re: 複数の構造体について
Posted: 2013年5月24日(金) 19:18
by non
プログラムは全部を載せるようにしてください。
>以下は出席番号を追加する関数number_addと日付を追加する関数date_addです。
どこに追加しようとしているのですか?前のときは、最後尾に追加しようという気持ちは伝わりましたが。
今回はさっぱりわかりません。
これおかしいです。
if(tmp = NULL)
2つもaddする関数を作るよりも、まずは完全に動くリスト構造を作ってみた方が良いと前にもお伝えしたつもりです。
****以下 再掲 ******
たとえば、ファイルが
B300001
B300002
B300003
....
B300121
のように学籍番号だけだとして、学籍番号だけのリスト構造を作れますか?
Re: 複数の構造体について
Posted: 2013年5月24日(金) 22:35
by 小岩井
non さんが書きました:
たとえば、ファイルが
B300001
B300002
B300003
....
B300121
のように学籍番号だけだとして、学籍番号だけのリスト構造を作れますか?
それなのですが、友人から教わったりして表示にこぎつけたのですが、番号が後ろの人から順に出力されました。これはそれを反対にする関数で逆順に表示しようと思います。
それと、
B300121
B300120
B300119
....
B300001
....
....
B300121
B300120
B300119
....
B300001
というように、推測ですが入力ファイルにある日付の分だけ繰り返し表示されました。
以下はそのプログラムです。
コード:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student_Entry
{
char number[10];
struct Student_Entry *next;
struct Date_Entry *date_entry;
};
struct Date_Entry
{
int year;
int month;
int day;
struct Date_Entry *next;
};
main()
{
FILE *fp;
int f, i;
char buffer[1024];
char *table[1024];
i = 0;
fp = fopen("text.txt", "r");
struct Student_Entry *SElist = NULL;
while(1)
{
f = fscanf(fp, "%s", buffer);
if(f == EOF) break;
if(buffer[0] == 'B')
{
if(SElist == NULL)
{
SElist = (struct Student_Entry*)malloc(sizeof(struct Student_Entry));
strcpy(SElist->number,strdup(buffer));
SElist->next = NULL;
//1つめのリスト
}
else
{
struct Student_Entry *SE = SElist;
SElist = (struct Student_Entry*)malloc(sizeof(struct Student_Entry));
strcpy(SElist->number,strdup(buffer));
SElist -> next = SE;
//2つめ以降のリスト
}
}
}
while(1){
if(SElist == NULL) break;
printf("%s\n", SElist -> number);
SElist = SElist -> next;
}
fclose(fp);
}
繰り返し表示されるのはwhile(1)の処理のせいだと思いますが、if文で処理しようにもできるものなのでしょうか?
Re: 複数の構造体について
Posted: 2013年5月25日(土) 08:19
by non
小岩井 さんが書きました:
それなのですが、友人から教わったりして表示にこぎつけたのですが、番号が後ろの人から順に出力されました。これはそれを反対にする関数で逆順に表示しようと思います。
それと、
B300121
B300120
B300119
....
B300001
....
....
B300121
B300120
B300119
....
B300001
というように、推測ですが入力ファイルにある日付の分だけ繰り返し表示されました。
データの追加するとき、リスト構造の先頭に付け加えており、表示は先頭から行っているので、逆順になっています。
学生番号のリストは学籍番号順に作った方が良いと思いますし、ダブった番号は出ないようにする必要が出てきますが、
これは後で考えましょう。
まず、添付されたプログラムですが、データの追加部分とデータの表示部分を関数にしましょう。
また、 SElist というポインタが、リストの先頭を表すために使われたり、追加するノードのために使われたりして、
読んでいてわかりにくいです。
あなたが作ったものと同じものを、関数にして作ってみました。
コード:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student_Entry
{
char number[10];
struct Student_Entry *next;
};
struct Student_Entry* addStudent(char *addnumber,struct Student_Entry *ptr)
{
struct Student_Entry *p;
p = (struct Student_Entry*)malloc(sizeof(struct Student_Entry));
strcpy(p->number,addnumber);
if(ptr==NULL)
p->next=NULL;
else
p->next=ptr;
ptr=p;
return ptr;
}
void dispStudent(struct Student_Entry *ptr)
{
while(ptr!=NULL){
printf("%s\n", ptr -> number);
ptr=ptr->next;
}
}
int main(void)
{
FILE *fp;
char buffer[1024];
struct Student_Entry *StudentHead = NULL;
fp = fopen("text.txt", "r");
while(fscanf(fp, "%s", buffer)!=EOF)
{
StudentHead=addStudent(buffer,StudentHead);
}
fclose(fp);
dispStudent(StudentHead);
}
text.txtは次のを使用します。
コード:
B300121
B300120
B300119
B300001
B300121
B300120
B300119
B300001
同じように逆順に表示されましたか。
それでは、読み込んだ順に表示されるように、リストの最後に追加されていくように、関数addStudentを作り変えてみてください。
他のところは変更しないように。
もし、それができたら、こんどは、出席番号順に追加されるように作り変えてみてください。このとき同じ番号がすでにリストに
あるときには、追加しないようにしてみてください。
Re: 複数の構造体について
Posted: 2013年5月25日(土) 15:28
by 小岩井
コード:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student_Entry
{
char number[8];
struct Student_Entry *next;
};
struct Date_Entry
{
int year;
int month;
int day;
struct Date_Entry *next;
};
struct Student_Entry(char *addnumber, struct Student_Entry *ptr)
{
struct Student_Entry *p;
p = (struct Student_Entry *)malloc(sizeof(struct Student_Entry));
strcpy(p -> number, addnumber);
p -> next = NULL;
return p;
}
void dispStudent (struct Student_Entry *ptr)
{
while(ptr != NULL)
{
printf("%s\n", ptr -> number);
ptr = ptr -> next;
}
}
main()
{
FILE *fp;
char buffer[1024];
fp = fopen("text.txt", "r");
while(fscanf, "%s", buffer) != EOF)
{
StudentHead = addStudent(buffer, StudentHead);
}
fclose(fp);
dispStudent(StudentHead);
}
実行結果は
B300001
B300119
B300120
B300121
B300001
B300119
B300120
B300121
となりました。
が、これだと
Re: 複数の構造体について
Posted: 2013年5月25日(土) 15:33
by 小岩井
すみません。途中で送信してしまいました。
以下が書き直したプログラムです。
http://f4.aaacafe.ne.jp/~pointc/log389.html
のページを参考に書きなおしました。
コード:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student_Entry
{
char number[10];
struct Student_Entry *next;
};
struct Date_Entry
{
int year;
int month;
int day;
struct Date_Entry *next;
};
struct Student_Entry* addStudent(char *addnumber, struct Student_Entry *ptr)
{
struct Student_Entry *p;
p = (struct Student_Entry *)malloc(sizeof(struct Student_Entry));
strcpy(p -> number, addnumber);
p -> next = NULL;
if(ptr != NULL) ptr->next=p;
return p;
}
void dispStudent (struct Student_Entry *ptr)
{
while(ptr != NULL)
{
printf("%s\n", ptr -> number);
ptr = ptr -> next;
}
}
main()
{
FILE *fp;
char buffer[1024];
fp = fopen("text.txt", "r");
while(fscanf, "%s", buffer) != EOF)
{
StudentHead = addStudent(buffer, StudentHead);
}
fclose(fp);
dispStudent(StudentHead);
}
書きなおしてみたものの、実行結果が
B300001
のみでした…。
呼び出し部分は変えていません。そのせいでしょうか?
Re: 複数の構造体について
Posted: 2013年5月25日(土) 17:37
by non
添付されたプログラムは、私のところではエラーになります。実際に、動かしているプログラムを載せてもらえないですか。
リンクしたところに書いてあるプログラムは最後尾をtailで指してるでしょ。あなたのには、そんなものがありません。
Re: 複数の構造体について
Posted: 2013年5月25日(土) 17:52
by 小岩井
すみません、ポインタの宣言を忘れていました。
以下はそれも含め書きなおしました。
コード:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student_Entry
{
char number[10];
struct Student_Entry *next;
};
struct Date_Entry
{
int year;
int month;
int day;
struct Date_Entry *next;
};
struct Student_Entry* addStudent(char *addnumber, struct Student_Entry *tail)
{
struct Student_Entry *p;
p = (struct Student_Entry *)malloc(sizeof(struct Student_Entry));
if(p == NULL) printf("nothing.\n"),exit(1);
strcpy(p -> number, addnumber);
p -> next = NULL;
if(tail != NULL) tail->next=p;
return p;
}
void dispStudent (struct Student_Entry *ptr)
{
while(ptr != NULL)
{
printf("%s\n", ptr -> number);
ptr = ptr -> next;
}
}
main()
{
FILE *fp;
char buffer[1024];
struct Student_Entry *StudentHead = NULL;
struct Student_Entry *tail = NULL;
fp = fopen("text.txt", "r");
while(fscanf(fp, "%s", buffer) != EOF)
{
tail = addStudent(buffer,tail);
if(StudentHead == NULL) StudentHead = tail;
}
fclose(fp);
dispStudent(StudentHead);
}
Re: 複数の構造体について
Posted: 2013年5月25日(土) 18:36
by non
できれば、tailを使わずに、先頭からwhileを使って最後尾まで進めて挿入して欲しかったのですが、まあ、tailを使っても、理解が進んだのならいいでしょう。
では、次に最後尾に挿入するのではなく、番号順(アスキー順)に挿入するように変更してみてください。ただし、すでに同じ番号があるときには追加しないこと。
Re: 複数の構造体について
Posted: 2013年5月26日(日) 13:41
by 小岩井
non さんが書きました:できれば、tailを使わずに、先頭からwhileを使って最後尾まで進めて挿入して欲しかったのですが、まあ、tailを使っても、理解が進んだのならいいでしょう。
他にも方法はあったのですね!
この課題、去年のより難しくさらにやり方が様々あるようで教える側も困っていたことを思い出しました。
non さんが書きました:
では、次に最後尾に挿入するのではなく、番号順(アスキー順)に挿入するように変更してみてください。ただし、すでに同じ番号があるときには追加しないこと。
本当に途中までなのですが、以下の考え方で合っているでしょうか?
(addStudent内の書き換え)
コード:
//文字列の比較
strcmp(p->number,addnumber)
if((p->number) != addnumber)
p -> number = NULL;
....
....
でもこれだとちょっと違うような気もしてきます。
出席番号をリストに追加していくときにすでにあるかどうか確認し、なかったらリストへ…なのでp->number = NULL;はifの上ですかね。
アスキー順に追加、はfor文で書けばいけそうな気もするので、考え方が合っているかどうかお尋ねしたいです。
Re: 複数の構造体について
Posted: 2013年5月26日(日) 14:06
by non
まず挿入する場所を探します。
先頭から順番にstrcmpで比較していって、挿入する場所を探します。
ただし、挿入する1個先まで進んでしまうので、1個前を覚えておくか、もう一度先頭から見て行って1個手前を指す必要があります。
片方向リストは前に戻れないので不便です。
さて、挿入する場所によって次の3パターンに分かれます。
1 先頭に挿入する場合
2 最後尾に追加する場合
3 途中に挿入する場合。
まずは、挿入する場所をforかwhileを使って探す部分を作ってみてください。
添付された作りかけのプログラムは正直、訳がわからないので(strcmpは使うけど、戻り値は使ってないし)コメントできません。
このペースだと、かなり時間がかかりそうですが、提出期限はいつまで?
Re: 複数の構造体について
Posted: 2013年5月26日(日) 14:44
by 小岩井
non さんが書きました:
このペースだと、かなり時間がかかりそうですが、提出期限はいつまで?
今月末までなのですが、今現在の自分の理解力などから考えて期限を超えて提出あるいは途中までの提出になりそうです…。
とりあえず、挿入部分のプログラムを作ってみます!
Re: 複数の構造体について
Posted: 2013年5月26日(日) 19:14
by 小岩井
コード:
struct Student_Entry* addStudent(char *addnumber, struct Student_Entry *tail)
{
struct Student_Entry *p;
struct Student_Entry *q;
struct Student_Entry *r;
p = (struct Student_Entry *)malloc(sizeof(struct Student_Entry));
q = (struct Student_Entry *)malloc(sizeof(struct Student_Entry));
r = (struct Student_Entry *)malloc(sizeof(struct Student_Entry));
strcpy(p -> number, addnumber);
while(p != NULL)
{
i = strcmp(p->number,addnumber);
if(i<0) break;
tail = p;
p = p->next;
}
//最初に挿入
if(tail == NULL)
{
p->next = p;
tail = p;
return tail;
}
//最後に挿入
else if(tail != NULL)
{
tail->next = p;
return p;
}
//途中に挿入
else
{
q->next = p;
r->next = q;
}
}
コンパイルエラーは出ませんでしたが、調べながら書いたので中身がめちゃくちゃかもしれません…。
挿入するひとつ前を記憶する部分は今考えています…。
Re: 複数の構造体について
Posted: 2013年5月26日(日) 20:28
by box
ザッと見たところでは、
小岩井 さんが書きました:コード:
struct Student_Entry *q;
struct Student_Entry *r;
qとrの存在理由がよくわかりません。
小岩井 さんが書きました:コード:
//途中に挿入
else
{
q->next = p;
r->next = q;
}
}
呼び出し元に何も返さなくていいのでしょうか。
Re: 複数の構造体について
Posted: 2013年5月26日(日) 20:48
by non
まず、tailって名前は通常最後尾を指すために使う変数名です。
今回は先頭を示すポインタを必要とします。もしくは、先頭と最後尾を渡すという方法でもかまいませんが。
次に
追加するノードは一つなのに、なぜmallocが3つあるのでしょうか?
一つでいいでしょうし、まだ、挿入する場所も見つけていないのに、mallocするのは早いです。
もちろん、p以外のポインタとしてrやqを使うのはかまいませんし、たぶんp以外のポインタは必要になるでしょう。
コード:
while(p != NULL)
{
i = strcmp(p->number,addnumber);
if(i<0) break;
p = p->next;
}
ここの考え方はいいです。間の、 tail=p は意味不明ですが。(だから抜きました)
これで、挿入する場所の次をpが指しますね。挿入するのはこの前なので、pの前のノードを例えばqで指せるようにしましょう。
Re: 複数の構造体について
Posted: 2013年5月26日(日) 22:27
by 小岩井
ご指摘を受けた部分を含め修正、追加しました。
コード:
struct Student_Entry* addStudent(char *addnumber, struct Student_Entry *head, struct Student_Entry *tail)
{
struct Student_Entry *p, *q, *r;
p = (struct Student_Entry *)malloc(sizeof(struct Student_Entry));
strcpy(p -> number, addnumber);
while(p != NULL)
{
i = strcmp(p->number,addnumber);
if(i<0) break;
q = (p1)->next; //pの1個前
p = p->next;
//最初に挿入
if(tail == NULL)
{
p->next = p;
head = p;
return head;
}
//最後に挿入
else if(tail != NULL)
{
tail->next = p;
return p;
}
//途中に挿入
else
{
q = r->next;
r->next = p;
p = r;
r = q;
return r;
}
}
}
途中に挿入する部分ですが値を入れ替える感じで書きましたが、どうもわかりません…。
pのひとつ前のノードを指す=p-1のノードを指す、という理解で合っているでしょうか?
Re: 複数の構造体について
Posted: 2013年5月26日(日) 23:01
by non
p = (struct Student_Entry *)malloc(sizeof(struct Student_Entry));
したあとで
while(p != NULL)
それをこの目的につかおうという意味がわかりません。
q = (p1)->next; //pの1個前
これも???
絵を書いてみたらどうですか。
これを日本語で言えば
ポインタp1が指しているノードの次のノードをqで覚えるってことです。
Re: 複数の構造体について
Posted: 2013年5月27日(月) 00:43
by 小岩井
non さんが書きました:
p = (struct Student_Entry *)malloc(sizeof(struct Student_Entry));
したあとで
while(p != NULL)
それをこの目的につかおうという意味がわかりません。
pが領域を確保できたときwhile以下の処理を行うつもりで書いたのですが、mallocで用意しているなら必要ないですね…。
指摘された箇所を修正しました。
コード:
struct Student_Entry* addStudent(char *addnumber, struct Student_Entry *head, struct Student_Entry *tail)
{
struct Student_Entry *p, *q, *r;
p = (struct Student_Entry *)malloc(sizeof(struct Student_Entry));
strcpy(p -> number, addnumber);
while(head != NULL)
{
i = strcmp(p->number,addnumber);
if(i<0) break;
p = q;
q->next = NULL;
p->next = q;
p = p->next;
//最初に挿入
if(tail == NULL)
{
p->next = p;
head = p;
return head;
}
//最後に挿入
else if(tail != NULL)
{
tail->next = p;
return p;
}
//途中に挿入
else
{
q = r->next;
r->next = p;
p = r;
r = q;
return r;
}
}
}
Re: 複数の構造体について
Posted: 2013年5月27日(月) 06:45
by non
で、ちゃんと動いたのでしょうか?確認してみましたか。
しっかりみてはいませんが、戻り値は何を返すつもりでいますか?
最初に私が作ったプログラムでは、一番先頭のポインタを返していました。小岩井さんが作った、前の最後尾にノードを追加するプログラムではtailを返していましたね。今回は、先頭にノードが追加されるかもしれませんし、最後尾に追加されるかもしれません。戻り値は一つしか返せませんね。さて、何を返すことに決めたのでしょうか。
また、whileの繰り返しの中で、ノードの挿入を行っています。この関数では1個のノードを追加すればよいのに、なぜ、whileの中なのでしょうか?いずれにしても、小岩井さんはリスト構造への理解ができていません。前の私の課題(最後尾にノードを追加する)をtailを使わずにしてみることを提案します。また、前回、絵を書くことを提案しましたが書いてみましたか。
書いていれば
こんな条件で抜けることがおかしいときづくはずですが。
だって、headを移動していないのですから。
Re: 複数の構造体について
Posted: 2013年5月27日(月) 09:07
by non
どこかに、自分で勉強できるよい情報がないかと検索しました。
http://www.is.titech.ac.jp/compview/clang/chap11.html
ここの下の方にある、「C 言語でリスト構造を実現する」が、最後尾に追加する場合
「日付順に追加する」がアスキー順に追加する場合の参考になるのではないでしょうか。
Re: 複数の構造体について
Posted: 2013年5月27日(月) 22:59
by 小岩井
コード:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student_Entry
{
char number[10];
struct Student_Entry *next;
};
struct Date_Entry
{
int year;
int month;
int day;
struct Date_Entry *next;
};
//日付のソート
int sortDate(struct Date_Entry *a, struct Date_Entry *b)
{
if(a->year < b->year)
{
return 1;
}
else if(a->year == b->year)
{
if(a->month < b->month)
return 1;
}
else if(a->month == b->month)
{
if(a->day < b->day)
{
return 1;
}
}
return 0;
}
struct Student_Entry* tailStudent(struct Student_Entry *t)
{
if(t->next == NULL)
return t;
tailStudent(t->next);
}
struct Student_Entry* addStudent(char *addnumber, struct Student_Entry *ptr)
{
struct Student_Entry *p;
p = (struct Student_Entry *)malloc(sizeof(struct Student_Entry));
strcpy(p -> number, addnumber);
p->next = NULL;
(tailStudent(ptr))->next = p;
printf("%s\n",(tailStudent(ptr))->number);
}
void dispStudent (struct Student_Entry *ptr)
{
while(ptr != NULL)
{
printf("%s\n", ptr -> number);
ptr = ptr -> next;
}
}
main()
{
FILE *fp;
char buffer[1024];
struct Student_Entry *StudentHead = NULL;
fp = fopen("text.txt", "r");
while(fscanf(fp, "%s", buffer) != EOF)
{
StudentHead = (buffer,StudentHead);
}
dispStudent(StudentHead->next);
fclose(fp);
}
tailStudentで最後に追加すればいいよ、とアドバイスをもらったので作ってみました。
コンパイル時にエラーは出ませんでしたが、実行するとセグメンテーション違反でした…。
Re: 複数の構造体について
Posted: 2013年5月27日(月) 23:08
by box
コード全体をちゃんと追いかけたわけではありませんが、
main関数の最後の方にある
小岩井 さんが書きました:コード:
StudentHead = (buffer,StudentHead);
この部分は、おそらく意図どおりには動かないと思います。
実際には、(buffer の前に関数名が来るのではありませんか?
このコードでは、事実上
コード:
StudentHead = StudentHead;
と書いたのと同じになっています。そういう意図ではないですよね?
Re: 複数の構造体について
Posted: 2013年5月27日(月) 23:18
by 小岩井
box さんが書きました:コード全体をちゃんと追いかけたわけではありませんが、
main関数の最後の方にある
小岩井 さんが書きました:コード:
StudentHead = (buffer,StudentHead);
この部分は、おそらく意図どおりには動かないと思います。
実際には、(buffer の前に関数名が来るのではありませんか?
このコードでは、事実上
コード:
StudentHead = StudentHead;
と書いたのと同じになっています。そういう意図ではないですよね?
抜かりがありました。ご指摘ありがとうございます…。
ただしくは
コード:
StudentHead = addStudent(buffer,StudentHead);
でした。
しかしこれでもセグメンテーション違反なのです。
そういうコメントが出る理由は調べましたが、該当する箇所がピンときません…。
Re: 複数の構造体について
Posted: 2013年5月27日(月) 23:29
by box
小岩井 さんが書きました:コード:
main()
struct Student_Entry *StudentHead = NULL;
StudentHead = addStudent(buffer,StudentHead);
main関数でaddStudent関数を初めて呼び出す際、引数StudentHeadはNULLです。
ということは、
小岩井 さんが書きました:コード:
struct Student_Entry* addStudent(char *addnumber, struct Student_Entry *ptr)
(tailStudent(ptr))->next = p;
第2引数のptrがNULLですから、tailStudent関数にNULLを渡しています。
小岩井 さんが書きました:コード:
struct Student_Entry* tailStudent(struct Student_Entry *t)
{
if(t->next == NULL)
return t;
tailStudent(t->next);
}
tailStudent関数の引数tがNULLですから、そのメンバーであるnextを参照しようとすると
セグメント違反が起きるのは致し方ないと思います。
別の回答者さんからの回答にあったと思いますが、リスト構造の絵を書いてみましたか?
Re: 複数の構造体について
Posted: 2013年5月28日(火) 01:09
by 小岩井
box さんが書きました:
tailStudent関数の引数tがNULLですから、そのメンバーであるnextを参照しようとすると
セグメント違反が起きるのは致し方ないと思います。
そ、そういうことでしたか…。
値が入っていればセグメント違反は出ないのですね!
box さんが書きました:
別の回答者さんからの回答にあったと思いますが、リスト構造の絵を書いてみましたか?
どういうことをすればいいか絵を書いてわかったこともあるのですが、それをプログラムに…となるとどうすればいいのかわからなくなります。
実際に打って何がいけないか考える作業が少ないのが原因だと思います…。
Re: 複数の構造体について
Posted: 2013年5月28日(火) 07:16
by non
なんで、再帰。再帰を使っていけないわけではないけど、何のためにサンプルがあるページを示したの。わざわざ、違う方法を使う理由がわからない。サンプルが理解できてから、違う方法にチャレンジすべきじゃないかな。
Re: 複数の構造体について
Posted: 2013年5月28日(火) 10:51
by 小岩井
non さんが書きました:なんで、再帰。再帰を使っていけないわけではないけど、何のためにサンプルがあるページを示したの。わざわざ、違う方法を使う理由がわからない。サンプルが理解できてから、違う方法にチャレンジすべきじゃないかな。
すみませんでした。サンプルページのおかげで、実行結果を表示できました。
コード:
struct Student_Entry* addStudent(char *addnumber,struct Student_Entry *ptr)
{
struct Student_Entry *p;
p = (struct Student_Entry *)malloc(sizeof(struct Student_Entry));
strcpy(p -> number, addnumber);
while(p != NULL)
{
if(ptr == NULL)
{
return p;
}
else
{
struct Student_Entry *q = ptr;
while(q->next != NULL)
{
q = q->next;
}
q->next = p;
return ptr;
}
}
}
main()
{
FILE *fp;
char buffer[1024];
struct Student_Entry *StudentList = NULL;
fp = fopen("text.txt", "r");
while(fscanf(fp, "%s", buffer) != EOF)
{
StudentList = addStudent(buffer, StudentList);
}
dispStudent(StudentList->next);
fclose(fp);
}
挿入箇所を探すことはできた、と思います。
strcmpで比較する処理もやっていきます!
Re: 複数の構造体について
Posted: 2013年5月28日(火) 11:36
by non
7行目 while(p != NULL)
これってなぜwhile?
6行目あたりに、 p->next=NULL;
が必要だと思うけど。
まだたいして長くないので、プログラムは省略せずに全部載せてください。途中からスレッドを読む人がわかりにくいし、こちらも試すのに面倒です。
ついでに main() は
int main(void)
と書いてもらえますか。
Re: 複数の構造体について
Posted: 2013年5月28日(火) 11:44
by non
そろそろ、もともと課題用に用意されているTEXT.TXTを添付してもらえますか。
Re: 複数の構造体について
Posted: 2013年5月28日(火) 12:15
by 小岩井
non さんが書きました:そろそろ、もともと課題用に用意されているTEXT.TXTを添付してもらえますか。
課題用のテキストファイルですが、ざっと見るかぎり100日以上ありそこに出席番号がずらっと並んであるのと学内専用のページにあるので難しいです…。
ファイル内は日付順ならびに出席番号順で用意されています。
コード:
20120404
20120406
20120411
B3000011
B3000015
....
....
20120413
B3000011
B3000014
....
....
20130301
20130306
B3000121
20130308
一部抜粋ですが、出席していない日付などがあります。
Re: 複数の構造体について
Posted: 2013年5月28日(火) 13:00
by non
共通のデータで実行しないと、同じ結果を確認できません。
テスト用のデータを作ってファイル添付してください。
Re: 複数の構造体について
Posted: 2013年5月28日(火) 13:07
by 小岩井
コード:
20130130
B0000064
20130201
B0000005
B0000064
20130206
20130208
20130213
20130215
20130220
20130222
20130227
B0000005
B0000094
B0000117
20130301
20130306
B0000117
20130308
こんなものでよろしいでしょうか…?
Re: 複数の構造体について
Posted: 2013年5月28日(火) 16:08
by non
すると、空白行があったり、出席者がいない日付があるわけですね。了解しました。
Re: 複数の構造体について
Posted: 2013年5月28日(火) 19:28
by かずま
その入力に対する出力はこれでいいですか?
コード:
B0000005
2013.2.1
2013.2.27
B0000064
2013.1.30
2013.2.1
B0000094
2013.2.27
B0000117
2013.2.27
2013.3.6
なお、この出力は次のプログラムによるものです。
C ではなく、C++ なので、課題の解答ではありません。
コード:
#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <list>
#include <cstdlib>
int main()
{
using namespace std;
string id, date;
typedef list<string> Dates;
typedef map<string, Dates> Students;
Students students;
ifstream ifs("text.txt");
if (!ifs) return 1;
while (ifs >> id)
if (id[0] == 'B') students[id].push_back(date);
else date = id;
for (Students::iterator si = students.begin(); si != students.end(); ++si) {
cout << si->first << endl;
Dates& dates = si->second;
for (Dates::iterator di = dates.begin(); di != dates.end(); ++di)
cout << di->substr(0, 4) << '.'
<< atoi(di->substr(4, 2).c_str()) << '.'
<< atoi(di->substr(6, 2).c_str()) << endl;
cout << endl;
}
}
Re: 複数の構造体について
Posted: 2013年5月28日(火) 19:40
by かずま
"B0000064" は 8文字ですが、末尾の '\0' を含めると 9バイト
なので、struct Student_Entry の char number[8]; には
入らないことに注意してください
Re: 複数の構造体について
Posted: 2013年5月28日(火) 20:58
by 小岩井
かずま さんが書きました:"B0000064" は 8文字ですが、末尾の '\0' を含めると 9バイト
なので、struct Student_Entry の char number[8]; には
入らないことに注意してください
それはchar number[10]に変更すれば大丈夫そうですね。
出力結果はそれで合っています!
それだけでできるものなんですね…驚いています。
そう!atoiでchar型をint型に変更してねーと先生が言っていたのを思い出しました。
引き続き頑張ってみます。
Re: 複数の構造体について
Posted: 2013年5月29日(水) 08:36
by 小岩井
初めてC++のプログラムを見ましたが…、なんとなくはわかるのですが知らない文法もあり混乱しています…。
提出期限ギリギリまで完成しないのは私の責任です。
わがままではありますが、完成するまでもう少し噛み砕いてご教授いただけないでしょうか…?
Re: 複数の構造体について
Posted: 2013年5月29日(水) 08:45
by non
C++の勉強するのは課題が終わってからにしなさいよ。
Re: 複数の構造体について
Posted: 2013年5月29日(水) 09:09
by 小岩井
non さんが書きました:C++の勉強するのは課題が終わってからにしなさいよ。
もちろんそのつもりです!
C言語においてどうすれば課題がクリアできるか教えていただきたかったのです。言葉が足りませんでした…。
コード:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student_Entry
{
char number[10];
struct Student_Entry *next;
};
struct Date_Entry
{
int year;
int month;
int day;
struct Date_Entry *next;
};
struct Student_Entry* addStudent(char *addnumber, struct Student_Entry *ptr)
{
struct Student_Entry *p;
p = (struct Student_Entry *)malloc(sizeof(struct Student_Entry));
strcpy(p -> number, addnumber);
p->next = NULL;
if(ptr == NULL)
{
p->next = NULL;
return p;
}
else
{
struct Student_Entry *q = ptr;
while(q->next != NULL)
{
q = q->next;
}
q->next = p;
return p;
}
}
void dispStudent (struct Student_Entry *ptr)
{
while(ptr != NULL)
{
printf("%s\n", ptr -> number);
ptr = ptr -> next;
}
}
main()
{
FILE *fp;
char buffer[1024];
struct Student_Entry *StudentList = NULL;
fp = fopen("text.txt", "r");
while(fscanf(fp, "%s", buffer) != EOF)
{
StudentList = (buffer,StudentList);
}
dispStudent(StudentList->next);
fclose(fp);
}
実行結果は以下になります。
コード:
20130201
B0000005
B0000064
20130206
20130208
20130213
20130215
20130220
20130222
20130227
B0000005
B0000094
B0000117
20130301
20130306
B0000117
20130308
text.txtに記載されている最初の
2013130
B000064
が表示されませんでした。
もう一度ご教授願えないでしょうか…?
Re: 複数の構造体について
Posted: 2013年5月29日(水) 09:30
by non
あなたが、動かしているプログラムをそのまま、載せてください。
これに投稿するために打ち直しているのですか?
Re: 複数の構造体について
Posted: 2013年5月29日(水) 09:34
by 小岩井
コード:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student_Entry
{
char number[10];
struct Student_Entry *next;
};
struct Date_Entry
{
char year[10];
char month;
char day;
struct Date_Entry *next;
};
int before(struct Date_Entry* a, struct Date_Entry* b) {
if (a->year < b->year) {
return 1;
}
else if (a->year == b->year) {
if (a->month < b->month) {
return 1;
}
else if (a->month == b->month) {
if (a->day < b->day) {
return 1;
}
}
}
return 0;
}
struct Student_Entry *addStudent(char *addnumber, struct Student_Entry *ptr)
{
struct Student_Entry *p;
p = (struct Student_Entry *)malloc(sizeof(struct Student_Entry));
strcpy(p->number,addnumber);
p->next = NULL;
if(ptr == NULL)
{
p->next = NULL;
return p;
}
else
{
struct Student_Entry *q = ptr;
while(q->next != NULL)
{
q = q->next;
}
q->next = p;
return ptr;
}
}
struct Date_Entry* addDate(int y,int m,int d,char date[], struct Date_Entry *ptr)
{
struct Date_Entry *p;
p = (struct Date_Entry *)malloc(sizeof(struct Date_Entry));
p->month=m;
p->day=d;
strcpy(p->year,date);
if(ptr == NULL)
{
p->next = NULL;
return p;
}
else if(before(p, ptr) == 1)
{
p->next = ptr;
return p;
}
else
{
struct Date_Entry *q = ptr;
while(q->next != NULL && before(p,q->next) == 0)
{
q = q->next;
}
struct Date_Entry *n = q->next;
q->next = p;
p->next = n;
return ptr;
}
}
void dispStudent (struct Student_Entry *ptr)
{
while(ptr != NULL)
{
printf("%s\n", ptr -> number);
ptr = ptr -> next;
}
}
int main()
{
FILE *fp;
char buffer[1024];
struct Student_Entry *StudentList = NULL;
struct Date_Entry *DateList = NULL;
fp = fopen("text.txt", "r");
while(fscanf(fp, "%s", buffer) != EOF)
{
if(buffer[0]=='B')
{
StudentList = addStudent(buffer,StudentList);
}
else
{
StudentList = addStudent(buffer,StudentList);
}
}
dispStudent(StudentList->next);
fclose(fp);
}
これが私の動かしているプログラムです。
日付を加える処理を出席番号を加えるものと同様にしたものを追加してあります。
Re: 複数の構造体について
Posted: 2013年5月29日(水) 10:15
by non
130 行 dispStudent(StudentList->next);
は
dispStudent(StudentList);
でしょう。
また、これで出力されないのは先頭の1行であり、2行出ていないと思っているのは勘違いでしょう。
また、関数 beforeは日付で並べる必要はないので、(もともと日付順で入力される)不要です。
それより、addstudentを番号順に挿入できるようにしてください。
Re: 複数の構造体について
Posted: 2013年5月29日(水) 10:43
by 小岩井
non さんが書きました:それより、addstudentを番号順に挿入できるようにしてください。
そのことなんですが、課題用のテキストファイルは日付順かつ出席番号順に記述されているので、ただ挿入するだけでいいという気もするのです…。
とにかく追加できるようやってみます。
Re: 複数の構造体について
Posted: 2013年5月29日(水) 10:54
by non
小岩井 さんが書きました:non さんが書きました:それより、addstudentを番号順に挿入できるようにしてください。
そのことなんですが、課題用のテキストファイルは日付順かつ出席番号順に記述されているので、ただ挿入するだけでいいという気もするのです…。
とにかく追加できるようやってみます。
その日だけで考えれば、確かに学籍番号順なのですが、欠席した学生が後ででてくることもあるので、出席番号順に挿入できるようにしておかなくてはいけません。できあがりの絵がわかってないからイメージがつかめないのです。
Re: 複数の構造体について
Posted: 2013年5月29日(水) 12:09
by usao
うーん,
課題の内容を読む → どうやって実現するか(日本語)を決める → 実現するためのコードを書く
という流れの,真ん中の部分があやふやなままだと,最後のコードをちゃんと書けないわけで,
そんな感じの状況に陥っているように見受けます.
ばかばかしいと思われるかもしれませんが,
自身が書いたコードに存在する個々の要素(関数,構造体,変数)毎に,
・それがなんなのか(役割.何のために必要で用意したのか)
を書いてみると 頭の中の整理の助けになったりしないでしょうか?
例えば,
コード:
//学生毎のデータを格納する用の構造体.
//・特定の学生を表すための学籍番号と,
// その学生が出席した日時のリストを 変数として保持する
//・また,nextを用いて数珠つながりなデータ構造を作ることで
// 学生データのリストを表現する
struct Student_Entry
{
//この学生のデータ
char number[10]; //学籍番号(文字列)
struct Date_Entry *pDateListHead; //出席日時リストの先頭要素へのポインタ.(最初(Student_Entry型変数を作ったとき)にNULLに初期化すること!)
//学生リスト構築用
struct Student_Entry *next; //次の学生のデータへのポインタ.(次が無い時はNULLを格納すること!)
};
みたく.
自然と 何をどうすべきか,今のコードに変な(意味や役割のわからない)部分が無いか 等が見えてくると思います.
(回答者も 各所が何を意図して書いたコードなのか を理解しやすくなりますし,
もしコードも提出する課題だったら,きちっとこういったことが書かれていたら 私だったら好印象)
Re: 複数の構造体について
Posted: 2013年5月29日(水) 12:15
by 小岩井
non さんが書きました:その日だけで考えれば、確かに学籍番号順なのですが、欠席した学生が後ででてくることもあるので、出席番号順に挿入できるようにしておかなくてはいけません。できあがりの絵がわかってないからイメージがつかめないのです。
絵を描いていただきありがとうございます!
なんとなくのイメージはあるのですが、前にも言ったようにそれをどう組み立てていけばいいのかさっぱりでして…。
番号順に追加するところでつまづいています。
コード:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student_Entry
{
char number[10];
struct Student_Entry *next;
};
struct Date_Entry
{
char year[10];
char month;
char day;
struct Date_Entry *next;
struct Student_Entry *studentlist;
};
struct Student_Entry *addStudent(char *addnumber, struct Student_Entry *ptr)
{
struct Student_Entry *p, *q;
p = (struct Student_Entry *)malloc(sizeof(struct Student_Entry));
strcpy(p->number,addnumber);
if(addnumber)
{
while(p)
{
if(!strcmp(p->next,addnumber))
break;
p = p->next;
}
return p;
}
if(ptr == NULL)
{
p->next = NULL;
return p;
}
else
{
struct Student_Entry *q = ptr;
while(q->next != NULL)
{
q = q->next;
}
q->next = p;
return ptr;
}
}
struct Date_Entry* addDate(int y,int m,int d,char date[], struct Date_Entry *ptr)
{
struct Date_Entry *p;
p = (struct Date_Entry *)malloc(sizeof(struct Date_Entry));
strcpy(p->year,date);
p->next = NULL;
if(ptr == NULL)
{
p->next = NULL;
return p;
}
else
{
struct Date_Entry *q = ptr;
while(q->next != NULL)
{
q = q->next;
}
q->next = p;
return ptr;
}
}
void dispStudent (struct Student_Entry *ptr)
{
while(ptr != NULL)
{
printf("%s\n", ptr -> number);
ptr = ptr -> next;
}
}
void dispDate(struct Date_Entry *ptr)
{
while(ptr != NULL)
{
printf("www%s\n", ptr-> year);
ptr = ptr->next;
}
}
int main()
{
FILE *fp;
char buffer[1024];
struct Student_Entry *StudentList = NULL;
struct Date_Entry *DateList = NULL;
fp = fopen("text.txt", "r");
while(fscanf(fp, "%s", buffer) != EOF)
{
if(buffer[0]!='B')
{
StudentList = addStudent(buffer,StudentList);
}
else
{
StudentList = addStudent(buffer,StudentList);
}
}
dispStudent(StudentList);
fclose(fp);
}
Re: 複数の構造体について
Posted: 2013年5月29日(水) 12:31
by non
これが、私が前に示したHPの挿入部分
コード:
if (list == NULL) { /* リストが空の場合は特別扱いする */
node->next = NULL;
return node;
}
else if (before(node, list) == 1) { /* 新しい要素が日付順でもっとも早い */
node->next = list;
return node;
}
else { /* 挿入位置を決める */
struct schedule* p = list;
while (p->next != NULL && before(node, p->next) == 0) {
p = p->next;
} /* 新しい要素は変数 p がさす要素の直後に挿入 */
struct schedule* n = p->next;
p->next = node;
node->next = n;
return list;
}
下が、あなたのプログラム
コード:
if(addnumber)
{
while(p)
{
if(!strcmp(p->next,addnumber))
break;
p = p->next;
}
return p;
}
if(ptr == NULL)
{
p->next = NULL;
return p;
}
else
{
struct Student_Entry *q = ptr;
while(q->next != NULL)
{
q = q->next;
}
q->next = p;
return ptr;
}
なぜ、参考にしないのですか?
Re: 複数の構造体について
Posted: 2013年5月29日(水) 12:57
by 小岩井
non さんが書きました:これが、私が前に示したHPの挿入部分
コード:
if (list == NULL) { /* リストが空の場合は特別扱いする */
node->next = NULL;
return node;
}
else if (before(node, list) == 1) { /* 新しい要素が日付順でもっとも早い */
node->next = list;
return node;
}
else { /* 挿入位置を決める */
struct schedule* p = list;
while (p->next != NULL && before(node, p->next) == 0) {
p = p->next;
} /* 新しい要素は変数 p がさす要素の直後に挿入 */
struct schedule* n = p->next;
p->next = node;
node->next = n;
return list;
}
下が、あなたのプログラム
コード:
if(addnumber)
{
while(p)
{
if(!strcmp(p->next,addnumber))
break;
p = p->next;
}
return p;
}
if(ptr == NULL)
{
p->next = NULL;
return p;
}
else
{
struct Student_Entry *q = ptr;
while(q->next != NULL)
{
q = q->next;
}
q->next = p;
return ptr;
}
なぜ、参考にしないのですか?
す、すみませんでした…。
コード:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student_Entry
{
char number[10];
struct Student_Entry *next;
};
struct Date_Entry
{
char year[10];
char month;
char day;
struct Date_Entry *next;
struct Student_Entry *studentlist;
};
int before(struct Student_Entry *a, struct Student_Entry *b)
{
if(a->number < b->number)
{
return 1;
}
else if(a->number == b->number)
{
return 1;
}
return 0;
}
struct Student_Entry *addStudent(char *addnumber, struct Student_Entry *ptr)
{
struct Student_Entry *p;
p = (struct Student_Entry *)malloc(sizeof(struct Student_Entry));
strcpy(p->number,addnumber);
if(ptr == NULL)
{
p->next = NULL;
return p;
}
else if(before(p,ptr) == 1)
{
p->next = ptr;
return p;
}
else
{
struct Student_Entry *q = p;
while(q->next!=NULL && before(p,q->next)==0)
{
struct Student_Entry *n = q->next;
q->next = p;
p->next = n;
return ptr;
}
}
}
struct Date_Entry* addDate(int y,int m,int d,char date[], struct Date_Entry *ptr)
{
struct Date_Entry *p;
p = (struct Date_Entry *)malloc(sizeof(struct Date_Entry));
strcpy(p->year,date);
p->next = NULL;
if(ptr == NULL)
{
p->next = NULL;
return p;
}
else
{
struct Date_Entry *q = ptr;
while(q->next != NULL)
{
q = q->next;
}
q->next = p;
return ptr;
}
}
void dispStudent (struct Student_Entry *ptr)
{
while(ptr != NULL)
{
printf("%s\n", ptr -> number);
ptr = ptr -> next;
}
}
void dispDate(struct Date_Entry *ptr)
{
while(ptr != NULL)
{
printf("www%s\n", ptr-> year);
ptr = ptr->next;
}
}
int main()
{
FILE *fp;
char buffer[1024];
struct Student_Entry *StudentList = NULL;
struct Date_Entry *DateList = NULL;
fp = fopen("text.txt", "r");
while(fscanf(fp, "%s", buffer) != EOF)
{
if(buffer[0]!='B')
{
StudentList = addStudent(buffer,StudentList);
}
else
{
StudentList = addStudent(buffer,StudentList);
}
}
dispStudent(StudentList);
fclose(fp);
}
実行結果は
20130130
のみとなりました。
before関数内で同じ番号だったときの処理がまずいのでしょうか…。
Re: 複数の構造体について
Posted: 2013年5月29日(水) 15:14
by usao
ちょっとコード変えた→結果はこうなった→動きませんが?
みたいなことを繰り返すよりも,
せめて
「○○してみて,動きを追ってみたところ
ここでしくじっているせいで うまくいっていないところまでは突き止めたんだけど
なんでこの書き方でうまくいかないのか??」
くらいの状態までは自力でこぎ着けて,疑問点を明確に訊いた方が良いように思いますが…
とりあえず
・before()で文字列の辞書順の比較のようなことを行いたいのであれば
意図したとおりに働かないものと思います.
Cでは char[]文字列を単純に < とか == とかで比較できないので.
・struct Date_Entryとかを見る限りだと,
他の回答者様が示した図によるデータ構造(私も図示された構造に見合う形でコードを示したのですが)
とは異なるデータ構造 でやろうとしているように見えるが,意図的にそういう方向でいくことにしたのでしょうか?
・116行目の ifの分岐後の処理内容(118行と122行)が全く一緒の処理なのも謎です.
Re: 複数の構造体について
Posted: 2013年5月29日(水) 15:18
by non
学籍番号は文字列なのでstrcmpを使います。beforeはいらないと前もいいました。
Re: 複数の構造体について
Posted: 2013年5月29日(水) 15:19
by non
54行のwhileあたりも、サンプルと違う。
Re: 複数の構造体について
Posted: 2013年5月29日(水) 18:06
by 小岩井
コード:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student_Entry
{
char number[10];
int count;
struct Student_Entry *next;
struct Date_Entry *datelist;
};
struct Date_Entry
{
char year[10];
char month;
char day;
struct Date_Entry *next;
};
struct Student_Entry *addStudent(char *addnumber, struct Student_Entry *ptr,int a)
{
struct Student_Entry *p;
p = (struct Student_Entry *)malloc(sizeof(struct Student_Entry));
strcpy(p->number,addnumber);
p->next = NULL;
int j;
int tmp;
for(j=0;j<a;j++,a++)
{
int n;
if (n = strcmp(ptr->number,(ptr+1)->number) != 0)
{
tmp = *ptr->number;
*ptr->number = *(ptr+1)->number;
*(ptr+1)->number = tmp;
return ptr;
}
}
if(ptr == NULL)
{
return p;
}
else
{
struct Student_Entry *q = ptr;
while (q->next != NULL)
{
q = q->next;
}
q->next = p;
return ptr;
}
}
struct Date_Entry* addDate(char date[], struct Date_Entry *ptr)
{
struct Date_Entry *p;
p = (struct Date_Entry *)malloc(sizeof(struct Date_Entry));
strcpy(p->year,date);
p->next = NULL;
if(ptr == NULL)
{
p->next = NULL;
return p;
}
else
{
struct Date_Entry *q = ptr;
while(q->next != NULL)
{
q = q->next;
}
q->next = p;
return ptr;
}
}
void dispStudent (struct Student_Entry *ptr)
{
while(ptr != NULL)
{
printf("%s\n", ptr -> number);
ptr = ptr -> next;
}
}
void dispDate(struct Date_Entry *ptr)
{
while(ptr != NULL)
{
printf("%s\n", ptr-> year);
ptr = ptr->next;
}
}
int main()
{
FILE *fp;
char buffer[1024];
struct Student_Entry *StudentList = NULL;
struct Date_Entry *DateList = NULL;
DateList = (struct Date_Entry *)malloc(sizeof(struct Date_Entry));
int a;
fp = fopen("text.txt", "r");
while(fscanf(fp, "%s", buffer) != EOF)
{
if(buffer[0]=='B')
{
StudentList = addStudent(buffer,StudentList,a);
}
}
dispStudent(StudentList);
fclose(fp);
return 0;
}
とりあえず文字列の比較まで見様見真似でやってみました。
比較する出席番号が同じでない場合の場合分けです。
実行結果は
コード:
B0000064
B0000005
B0000064
B0000005
B0000094
B0000117
B0000117
になりました。
if(buffer[0] == 'B')のところを!=に変えると日付が出てきます(日付はもちろん重複しません)。
比較したときの場合分けがうまく入ったと思ったのですが、出力結果を見るかぎりそうでもないようです...。
返り値の値が不適切なためだと私は推測しています。
参考にしたページはhttp://dixq.net/forum/viewtopic.php?f=3&t=13101です。
そのページのnumbersort関数を参考に追加してみましたが、型の不一致(参考ページはint、課題はchar)もうまくいかなかった原因のひとつでしょうか?
Re: 複数の構造体について
Posted: 2013年5月29日(水) 18:46
by usao
なんかもう 悪夢の様相を呈してきていますね…
addStudent()の引数aは一体何なのか?
34行目から始まるforループは何をしたいのか?
ここに来たとき,aの値はいくつで,この先どうなってしまうのか…
どこかのコードを「参考にする」には,
・そのコードのやっていることを完全に理解し,
・自分の問題に流用できる 処理方法やコーディング方法 は何か? を判断したうえで,
・自分の問題に見合う形にきちんと修正して取り込む
ことが必要ではないでしょうか. 参考=中途半端にコピペしてくること ではないと思います.
どの助言に耳を傾けるか の取捨選択は小岩井さんの自由ですが,
私は再度 以下の事柄をお勧めしておきます.
>ばかばかしいと思われるかもしれませんが,
>自身が書いたコードに存在する個々の要素(関数,構造体,変数)毎に,
>・それがなんなのか(役割.何のために必要で用意したのか)
>を書いてみると 頭の中の整理の助けになったりしないでしょうか?
特に,各関数内の変数の役割や 処理の意味 を自分で書いてみることです.
前述した addStudent() の引数aの役割を説明できますか?
「自分で考えた処理内容をコーディングしている」のだから,自分で説明できない要素が
その中に出てくるはずはないのです.普通は.
とりあえず ごく普通に addStudent()でやるべき処理を 考えたならば,私なら
既存リストの要素の学籍番号と,追加しようとしている学籍番号とを
strcmp()で比較した結果=戻り値 の値から,
(case1)ここはまだ追加場所ではない→次の要素へ
(case2)ちょうどここに追加すればいいようだ→ここに追加
(case3)この学籍番号は既にリストにあるようだ→追加しない
という3通りに分岐することになるだろうな,
とかと思うわけです.そしたら,その流れをコード化すれば良いわけで…
Re: 複数の構造体について
Posted: 2013年5月29日(水) 20:24
by non
今日、明日は忙しいのでusaoさんにパス。しっかり絵を書いてくださいね。とても書いているとは思えないから。
Re: 複数の構造体について
Posted: 2013年5月29日(水) 21:52
by かずま
struct Student_Entry の count は何?
struct Date_Entry で、char year[10]; char month; char day; となっているのはなぜ?
ptrが配列の要素を指しているわけでもないので、ptr+1 は意味がありません。
次のサンプルを完璧に理解できますか?
コード:
#include <stdio.h>
#include <stdlib.h>
struct Node {
char name[10];
struct Node *next;
};
struct Node *addName(struct Node *head, char *name)
{
struct Node *node, *cur, *pre;
for (cur = head; cur != NULL; cur = cur->next) {
int diff = strcmp(cur->name, name);
if (diff > 0) break; // 挿入場所が見つかったのでループを抜ける
if (diff == 0) { // 既に存在するのが見つかった
// やるべきことをやる
return head;
}
pre = cur;
}
node = malloc(sizeof(struct Node)); // リストにはなかったので追加
strcpy(node->name, name);
// やるべきことをやる
node->next = cur; // node に cur をつなぐ
if (cur == head) return node; // node が新たなリストの先頭
pre->next = node; // pre に node をつなぐ
return head; // head がリストの先頭
}
void printList(struct Node *head)
{
struct Node *cur;
for (cur = head; cur != NULL; cur = cur->next)
printf("%s\n", cur->name);
}
int main(void)
{
char name[10];
struct Node *nameList = NULL;
while (scanf("%9s", name) == 1)
nameList = addName(nameList, name);
printList(nameList);
return 0;
}
実行結果
コード:
kiko (入力)
mako
kako
mako
kiko
^Z (Windows なら行頭で Ctrl+Z、Linux なら行頭で Ctrl+D で入力終わり)
kako (出力)
kiko
mako
Re: 複数の構造体について
Posted: 2013年5月29日(水) 23:43
by 小岩井
すみません、遅くなりました…。
かずまさんのサンプルをそのまま使用させていただきました。
コード:
#include <stdio.h>
#include <stdlib.h>
struct Node {
char name[10];
struct Node *next;
};
struct Node *addName(struct Node *head, char *name)
{
struct Node *node, *cur, *pre;
for (cur = head; cur != NULL; cur = cur->next) {
int diff = strcmp(cur->name, name);
if (diff > 0) break; // 挿入場所が見つかったのでループを抜ける
if (diff == 0) { // 既に存在するのが見つかった
// 日付を返す?
return head;
}
pre = cur;
}
node = malloc(sizeof(struct Node)); // リストにはなかったので追加
strcpy(node->name, name);
node->next = node; //追加部分
node->next = cur; // node に cur をつなぐ
if (cur == head) return node; // node が新たなリストの先頭
pre->next = node; // pre に node をつなぐ
return head; // head がリストの先頭
}
void printList(struct Node *head)
{
struct Node *cur;
for (cur = head; cur != NULL; cur = cur->next)
printf("%s\n", cur->name);
}
int main(void)
{
char name[10];
struct Node *nameList = NULL;
while (scanf("%9s", name) == 1)
nameList = addName(nameList, name);
printList(nameList);
return 0;
}
新しいnodeが指す先は既存のnodeの次に加えればいいので、node->next = nodeとしました。
既にあった場合はそのときの日付を返せばいいのかなあ、と思いましたが日付のリストがないし、
追加しなければいいのでループから出ればいいのでは、とも考えたのですがその時返すものがないのでいよいよわからなくなりました…。
かずまさんのサンプルは理解できました!ありがとうございます。
Re: 複数の構造体について
Posted: 2013年5月30日(木) 00:58
by かずま
小岩井 さんが書きました:
新しいnodeが指す先は既存のnodeの次に加えればいいので、node->next = nodeとしました。
全く理解されていなくて悲しい。
head は、既存のリストの先頭のノードを指すポインタ。
cur は、既存のリストの各ノードを先頭から順に指していくポインタ。
pre は、cur の指すノードの一つ前のノードを指すポインタ。
node は、新しく確保したノードを指すポインタ。
新しいノード node は、既存のノード pre と既存のノード cur の間に
挿入しなければなりません。
それが、node->next = cur; と pre->next = node; です。
ただし、node が新しいリストの先頭になるときは、
pre->next = node; は要らないから
if (cur == head) return node; が間にあるのです。
ところで、
node->next = node;
node->next = cur;
ですが、node->next という「同じ変数」に、連続して異なる値を代入しても
最初の代入に意味がないことに気づかないのが不思議でなりません。
なぜそんなことを平気で書くのですか?
他の質問にも答えてください。
- addStudent() の引数 a は何?
- struct Student_Entry の count は何?
- struct Date_Entry の char year[10] は何?
- (p+1)->number の p+1 は何?
Re: 複数の構造体について
Posted: 2013年5月30日(木) 01:20
by 小岩井
かずま さんが書きました:
node->next = node;
node->next = cur;
ですが、node->next という「同じ変数」に、連続して異なる値を代入しても
最初の代入に意味がないことに気づかないのが不思議でなりません。
なぜそんなことを平気で書くのですか?
リストを辿っていき、比較している番号がすでにあったらそのとき先頭を示しているポインタの次に追加すればいいと思いそのように書きました。
先頭を示すポインタが何であるかをきっちりわかっていませんでした。
かずま さんが書きました:
他の質問にも答えてください。
- addStudent() の引数 a は何?
- struct Student_Entry の count は何?
- struct Date_Entry の char year[10] は何?
- (p+1)->number の p+1 は何?
参考サイトのプログラムを特に理解もせずそのまま写したので皆さんにご迷惑おかけしました……。
(p+1)はポインタpのさす次のノードのつもりでした。
夜遅くにごめんなさい……。
Re: 複数の構造体について
Posted: 2013年5月30日(木) 09:16
by usao
>usaoさんにパス
どうやら私は 取捨選択の「捨」の側に分類されているように見受けられるので パス先としては無理ではないかとw
(でも他の方がそのパスを受けてくれた模様)
…というのは まぁ 半分冗談としても
「理解しよう」という意気込みというか姿勢がどうにも見られないようなので,個人的にはもう無理(無駄?)かな,とか.
(私はこの掲示板を見るようになって日は浅いですが,これまでのやりとりの雰囲気から)
この掲示板は「わかんないけど動けばOK」の達成を手伝う場ではない…んだろうな,と感じているので.
Re: 複数の構造体について
Posted: 2013年5月30日(木) 10:38
by 小岩井
usao さんが書きました:>usaoさんにパス
どうやら私は 取捨選択の「捨」の側に分類されているように見受けられるので パス先としては無理ではないかとw
(でも他の方がそのパスを受けてくれた模様)
…というのは まぁ 半分冗談としても
「理解しよう」という意気込みというか姿勢がどうにも見られないようので,個人的にはもう無理(無駄?)かな,とか.
(私はこの掲示板を見るようになって日は浅いですが,これまでのやりとりの雰囲気から)
この掲示板は「わかんないけど動けばOK」の達成を手伝う場ではない…んだろうな,と感じているので.
決してそんなつもりはありません。なぜ動かないか、リスト構造の仕組みなどをここで教わりつつ理解できたらと思っています。
usaoさんの助言のおかげで頭のなかは整理できました。ありがとうございます。
ここでの私の行いを振り返るとまわりに聞いてばかりで、自分でろくに考えていませんでした。これでは理解しようという態度もないに等しいですよね。
これ以上皆さんに迷惑はかけたくないので、途中ではありますがここで解決にしたいと思います。
残りは自力で考えます。
本当にご迷惑をおかけしました。指摘、助言などしてくださった方々、ありがとうございました。
Re: 複数の構造体について
Posted: 2013年5月30日(木) 11:36
by usao
迷惑だ,とか 何で俺の言うのことを聞かないんだ! とか言ってるわけではなく
あまつさえあなたを排除しよう とかいう意図があるわけではないので その点は誤解なきよう.
ただ,多くの方が回答してくれているのに,その内容がほとんど反映されることもなく
むしろ他所からの部分コピペと思われる記述が追加されていく, という状況が謎というか,
だったら何で訊いたの? っていうか…うまく言えないけどそんな感じです.
仮に,もらった回答の内容がよくわからないのであれば,そのことについて
「ちょっとここが何言ってるかわからないです.もっと詳しく教えてください」とかいった方向で再度質問するなりして
とにかく問題点を一個一個解決していけば進展すると思うのですが
なんかというか,不明点が不明なまま次に進んでしまっていて,全体として進展がほとんどないように見受けられます.
続けるのも打ち切るのも自由ですが,どちらにせよ
多くの方に回答して頂いた内容を再度丁寧に読み返してみるとよいかと思います.
(提出期限がある状況下では,私が書いてきたような 急がば回れ 的な話は,
不親切でかえって迷惑なものに感じられるかもしれませんが…)
Re: 複数の構造体について
Posted: 2013年5月30日(木) 16:51
by ISLe
「好き」の反対は「嫌い」ではなく「無関心」。
「分かりませんでした」は「分かりました」と同じ価値があります。
指摘された間違いを何度も繰り返せば、関心がない(から覚えない)という印象を植え付けます。
「自分なりに調べてやってみました」というのもある意味コミュニケーションの拒絶です。
自分で考えているかどうか、理解できたかどうかは、この際関係ありません。
「ご迷惑をかけるので自分で考えます」もコミュニケーションの拒絶で、しかも一方的なものです。
けっしてやる気を認められることにはなりません。
プログラミングに必要なのは、国語(日本語)の読解力とコミュニケーション力と想像力だと思います。
Re: 複数の構造体について
Posted: 2013年5月31日(金) 00:15
by たいちう
本人はそれなりに頑張ってたつもりなのに、(本人の為を思ってのことでしょうが)
やる気がないように書かれたら退散したくもなるのではないかと。
結構、努力はしていたと思いますよ。
以下は質問者宛て。もう読まないかもしれないけど。
深く考えることなく安易に理解したつもりになることが一番の問題だと思います。
> かずまさんのサンプルは理解できました!ありがとうございます。
↑とか↓とか。
> usaoさんの助言のおかげで頭のなかは整理できました。ありがとうございます。
「理解したつもりであったが実は殆ど理解していなかった」という経験は誰にでもあります。
多いか少ないかだけの違いですが、プログラミングではあまり、ごまかしが効きませんので、
しっかり理解しておかないと先に進めません。
「理解」という言葉をもっと「理解」するように努めましょう。
# この掲示板では常に質問は歓迎されていますので、いつでも書き込んで下さい。
# もし反省すべき点が見つかり、反省した後ならば尚更大歓迎です。
# (回答も含めてですよ)
## 普段ROMってるだけの私が書くのもなんですが、
## このような方針の掲示板だったと理解しています。
Re: 複数の構造体について
Posted: 2013年5月31日(金) 06:55
by non
あらま、投げ出してよいの。それは、それで回答者に失礼だな。
ちょっと、課題が難しかったね。質問者のレベルでは、難しいと思う。
もう少し、前から勉強した方がいいと思います。その方が、本当に勉強するつもりなら、かえって早いでしょう。
急がば回れ!!