複数の構造体について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
小岩井

複数の構造体について

#1

投稿記事 by 小岩井 » 6年前

深夜に失礼します。
現在、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: 複数の構造体について

#2

投稿記事 by ぽこ » 6年前

生徒番号と何らかの日付データ2つを持つ学生リストが有って、
リスト内のデータを全て表示する課題のように見えますが、
具体的な課題を提示してください。

小岩井

Re: 複数の構造体について

#3

投稿記事 by 小岩井 » 6年前

出席番号とその出席した日付をすべて出力しなさい、というのが課題です。
そして以下がその実行例になります。

(実行例)
./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
....
と、出席データが記入されてあります。

non
記事: 1097
登録日時: 8年前

Re: 複数の構造体について

#4

投稿記事 by non » 6年前

小岩井 さんが書きました:授業中に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
のように学籍番号だけだとして、学籍番号だけのリスト構造を作れますか?
non

小岩井

Re: 複数の構造体について

#5

投稿記事 by 小岩井 » 6年前

すみません。遅くなりました。
授業で扱ったサンプルをもとに作ってみました。

コード:

#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);
}

non
記事: 1097
登録日時: 8年前

Re: 複数の構造体について

#6

投稿記事 by non » 6年前

どこをどう突っ込んでいいやら、わかりませんが・・・・

コード:

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は参照できません。
non

小岩井

Re: 複数の構造体について

#7

投稿記事 by 小岩井 » 6年前

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: 複数の構造体について

#8

投稿記事 by 小岩井 » 6年前

小岩井 さんが書きました:

コード:

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;
としても型が一致していないのでエラーが返ってきます。
このあたりで悩んでいます。

non
記事: 1097
登録日時: 8年前

Re: 複数の構造体について

#9

投稿記事 by non » 6年前

小岩井 さんが書きました: addはリストに出席番号を格納する関数です。

コード:

void *add(struct Student_Entry *ptr)
それなら、追加したい出席番号を関数に渡す必要があります。
渡すときに、本当に出席番号だけなら

コード:

void *add(char *addNumber,struct Student_Entry *ptr)
みたいにすればいいですね。最初のstrと同じってことになりますが。メンバーではないってことです。
non

小岩井

Re: 複数の構造体について

#10

投稿記事 by 小岩井 » 6年前

以下は出席番号を追加する関数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に追加していきたいです。

non
記事: 1097
登録日時: 8年前

Re: 複数の構造体について

#11

投稿記事 by non » 6年前

プログラムは全部を載せるようにしてください。
>以下は出席番号を追加する関数number_addと日付を追加する関数date_addです。
どこに追加しようとしているのですか?前のときは、最後尾に追加しようという気持ちは伝わりましたが。
今回はさっぱりわかりません。

これおかしいです。
if(tmp = NULL)


2つもaddする関数を作るよりも、まずは完全に動くリスト構造を作ってみた方が良いと前にもお伝えしたつもりです。

****以下 再掲 ******
たとえば、ファイルが
B300001
B300002
B300003
....
B300121
のように学籍番号だけだとして、学籍番号だけのリスト構造を作れますか?
non

小岩井

Re: 複数の構造体について

#12

投稿記事 by 小岩井 » 6年前

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文で処理しようにもできるものなのでしょうか?

non
記事: 1097
登録日時: 8年前

Re: 複数の構造体について

#13

投稿記事 by non » 6年前

小岩井 さんが書きました: それなのですが、友人から教わったりして表示にこぎつけたのですが、番号が後ろの人から順に出力されました。これはそれを反対にする関数で逆順に表示しようと思います。
それと、
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を作り変えてみてください。
他のところは変更しないように。

もし、それができたら、こんどは、出席番号順に追加されるように作り変えてみてください。このとき同じ番号がすでにリストに
あるときには、追加しないようにしてみてください。
non

小岩井

Re: 複数の構造体について

#14

投稿記事 by 小岩井 » 6年前

コード:

#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: 複数の構造体について

#15

投稿記事 by 小岩井 » 6年前

すみません。途中で送信してしまいました。
以下が書き直したプログラムです。
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
のみでした…。
呼び出し部分は変えていません。そのせいでしょうか?

non
記事: 1097
登録日時: 8年前

Re: 複数の構造体について

#16

投稿記事 by non » 6年前

添付されたプログラムは、私のところではエラーになります。実際に、動かしているプログラムを載せてもらえないですか。

リンクしたところに書いてあるプログラムは最後尾をtailで指してるでしょ。あなたのには、そんなものがありません。
non

小岩井

Re: 複数の構造体について

#17

投稿記事 by 小岩井 » 6年前

すみません、ポインタの宣言を忘れていました。
以下はそれも含め書きなおしました。

コード:

#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);
}

non
記事: 1097
登録日時: 8年前

Re: 複数の構造体について

#18

投稿記事 by non » 6年前

できれば、tailを使わずに、先頭からwhileを使って最後尾まで進めて挿入して欲しかったのですが、まあ、tailを使っても、理解が進んだのならいいでしょう。

では、次に最後尾に挿入するのではなく、番号順(アスキー順)に挿入するように変更してみてください。ただし、すでに同じ番号があるときには追加しないこと。
non

小岩井

Re: 複数の構造体について

#19

投稿記事 by 小岩井 » 6年前

non さんが書きました:できれば、tailを使わずに、先頭からwhileを使って最後尾まで進めて挿入して欲しかったのですが、まあ、tailを使っても、理解が進んだのならいいでしょう。
他にも方法はあったのですね!
この課題、去年のより難しくさらにやり方が様々あるようで教える側も困っていたことを思い出しました。
non さんが書きました: では、次に最後尾に挿入するのではなく、番号順(アスキー順)に挿入するように変更してみてください。ただし、すでに同じ番号があるときには追加しないこと。
本当に途中までなのですが、以下の考え方で合っているでしょうか?
(addStudent内の書き換え)

コード:

//文字列の比較
strcmp(p->number,addnumber)
if((p->number) != addnumber)
    p -> number = NULL;
    ....
    ....
でもこれだとちょっと違うような気もしてきます。
出席番号をリストに追加していくときにすでにあるかどうか確認し、なかったらリストへ…なのでp->number = NULL;はifの上ですかね。
アスキー順に追加、はfor文で書けばいけそうな気もするので、考え方が合っているかどうかお尋ねしたいです。

non
記事: 1097
登録日時: 8年前

Re: 複数の構造体について

#20

投稿記事 by non » 6年前

まず挿入する場所を探します。
先頭から順番にstrcmpで比較していって、挿入する場所を探します。
ただし、挿入する1個先まで進んでしまうので、1個前を覚えておくか、もう一度先頭から見て行って1個手前を指す必要があります。
片方向リストは前に戻れないので不便です。

さて、挿入する場所によって次の3パターンに分かれます。
1 先頭に挿入する場合
2 最後尾に追加する場合
3 途中に挿入する場合。

まずは、挿入する場所をforかwhileを使って探す部分を作ってみてください。
添付された作りかけのプログラムは正直、訳がわからないので(strcmpは使うけど、戻り値は使ってないし)コメントできません。
このペースだと、かなり時間がかかりそうですが、提出期限はいつまで?
non

小岩井

Re: 複数の構造体について

#21

投稿記事 by 小岩井 » 6年前

non さんが書きました: このペースだと、かなり時間がかかりそうですが、提出期限はいつまで?
今月末までなのですが、今現在の自分の理解力などから考えて期限を超えて提出あるいは途中までの提出になりそうです…。

とりあえず、挿入部分のプログラムを作ってみます!

小岩井

Re: 複数の構造体について

#22

投稿記事 by 小岩井 » 6年前

コード:

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;
    }
}
コンパイルエラーは出ませんでしたが、調べながら書いたので中身がめちゃくちゃかもしれません…。
挿入するひとつ前を記憶する部分は今考えています…。

box
記事: 1737
登録日時: 8年前

Re: 複数の構造体について

#23

投稿記事 by box » 6年前

ザッと見たところでは、
小岩井 さんが書きました:

コード:

    struct Student_Entry *q;
    struct Student_Entry *r;
qとrの存在理由がよくわかりません。
小岩井 さんが書きました:

コード:

    //途中に挿入
    else
    {
        q->next = p;
        r->next = q;
    }
}
呼び出し元に何も返さなくていいのでしょうか。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

non
記事: 1097
登録日時: 8年前

Re: 複数の構造体について

#24

投稿記事 by non » 6年前

まず、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で指せるようにしましょう。
non

小岩井

Re: 複数の構造体について

#25

投稿記事 by 小岩井 » 6年前

ご指摘を受けた部分を含め修正、追加しました。

コード:

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のノードを指す、という理解で合っているでしょうか?

non
記事: 1097
登録日時: 8年前

Re: 複数の構造体について

#26

投稿記事 by non » 6年前

p = (struct Student_Entry *)malloc(sizeof(struct Student_Entry));
したあとで
while(p != NULL)
それをこの目的につかおうという意味がわかりません。

q = (p1)->next; //pの1個前

これも???

絵を書いてみたらどうですか。
これを日本語で言えば
ポインタp1が指しているノードの次のノードをqで覚えるってことです。
non

小岩井

Re: 複数の構造体について

#27

投稿記事 by 小岩井 » 6年前

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;
        }
    }
}

non
記事: 1097
登録日時: 8年前

Re: 複数の構造体について

#28

投稿記事 by non » 6年前

で、ちゃんと動いたのでしょうか?確認してみましたか。

しっかりみてはいませんが、戻り値は何を返すつもりでいますか?
最初に私が作ったプログラムでは、一番先頭のポインタを返していました。小岩井さんが作った、前の最後尾にノードを追加するプログラムではtailを返していましたね。今回は、先頭にノードが追加されるかもしれませんし、最後尾に追加されるかもしれません。戻り値は一つしか返せませんね。さて、何を返すことに決めたのでしょうか。

また、whileの繰り返しの中で、ノードの挿入を行っています。この関数では1個のノードを追加すればよいのに、なぜ、whileの中なのでしょうか?いずれにしても、小岩井さんはリスト構造への理解ができていません。前の私の課題(最後尾にノードを追加する)をtailを使わずにしてみることを提案します。また、前回、絵を書くことを提案しましたが書いてみましたか。
書いていれば

コード:

 while(head != NULL)
こんな条件で抜けることがおかしいときづくはずですが。
だって、headを移動していないのですから。
non

non
記事: 1097
登録日時: 8年前

Re: 複数の構造体について

#29

投稿記事 by non » 6年前

どこかに、自分で勉強できるよい情報がないかと検索しました。
http://www.is.titech.ac.jp/compview/clang/chap11.html
ここの下の方にある、「C 言語でリスト構造を実現する」が、最後尾に追加する場合
「日付順に追加する」がアスキー順に追加する場合の参考になるのではないでしょうか。
non

小岩井

Re: 複数の構造体について

#30

投稿記事 by 小岩井 » 6年前

コード:

#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で最後に追加すればいいよ、とアドバイスをもらったので作ってみました。
コンパイル時にエラーは出ませんでしたが、実行するとセグメンテーション違反でした…。

閉鎖

“C言語何でも質問掲示板” へ戻る