掲示板利用宣言

 次のフォームをすべてチェックしてからご利用ください。

 私は

 題名と投稿者名は具体的に書きます。
 課題の丸投げはしません。
 ソースの添付は「HTML変換ツール」で字下げします。
 返信の引用は最小限にします。
 環境(OSとコンパイラ)や症状は具体的に詳しく書きます。
 返信の付いた投稿は削除しません。
 マルチポスト(多重投稿)はしません。

掲示板2

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.24908

線形リストのポインタでの質問です
投稿者---marumo(2005/12/22 17:31:24)


線形リストで、
(1)着目しているノードの後ろにノードを追加する関数
(2)リストに格納されているすべてのデータの番号を出力する関数
(3)仮引数で、リストへのポインタ、データxを受け取り、xと番号、デー  タが両方一致するノードをリストからすべて削除する関数
を作りたいのですが、(1),(2)を作って実行してみたところ、(2)を実行しようとうとすると、実行中にエラーがでて強制的に実行が中止され、

(1)を実行しようとすると、着目していたノードの番号がずっと出力され続けてうまくいきません。

ソースを次の分に載せます。




この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:線形リストのポインタでの質問です 24910 marumo 2005/12/22 17:39:07


No.24910

Re:線形リストのポインタでの質問です
投稿者---marumo(2005/12/22 17:39:07)


ソースは、(長いので2回に分けます。すいません。)
#include  <stdio.h>
#include  <stdlib.h>
#include  <string.h>

#define  NO  1                /* 番号(入力・探索用)*/
#define  NAME   2        /* 氏名(入力・探索用)*/

/*--- メニュー ---*/
typedef enum {
    Term, InsFront, InsRear, RmvFront, RmvRear, PrintCrnt, RmvCrnt, SrchNo, 
    SrchName, PrintAll,InsNo,PriNo,Clear/*InsNo,PriNoを追加*/
} Menu;

/*--- 会員データ ---*/
typedef struct {
    int   no;                    /* 番号 */
    char  name[10];    /* 氏名 */
} Data;
    
/*--- ノード ---*/
typedef struct __node {
    Data           data;        /* データ */
    struct __node  *next;      /* 後続ノードへのポインタ */
} Node;

/*--- 線形リスト ---*/
typedef struct  {
    Node  *head;                /* 先頭ノードへのポインタ */
    Node  *crnt;                /* 着目ノードへのポインタ */
} List;






/*--- 一つのノードを動的に確保 ---*/
Node *AllocNode(void)
{
    return ((Node *)calloc(1, sizeof(Node)));
}

/*--- 線形リストを初期化 ---*/
void InitList(List *list)
{
    list->head = NULL;            /* 先頭ノード */
    list->crnt = NULL;            /* 着目ノード */
}

/*--- ノードの各メンバに値を設定 ----*/
void SetNode(Node *n, Data x, Node *next)
{
    n->data = x;                            /* 番号 */
    n->next = next;       /* 氏名 */
}

/*--- データの番号が一致するか(探索用関数) ---*/
int NoEqual(Data x, Data y)
{
    return (x.no == y.no);
}

/*--- データの氏名が一致するか(探索用関数) ---*/
int NameEqual(Data x, Data y)
{
    return (strcmp(x.name, y.name) == 0);
}

/*--- 関数equalによってxと一致するノードを探索 ---*/
Node *SearchNode(List *list, Data x, int equal(Data x, Data y))
{
    Node  *ptr = list->head;

    while (ptr != NULL) {
        if (equal(ptr->data, x)) {    /* キー値が一致 */
            list->crnt = ptr;
            return (ptr);            /* 探索成功 */
        }
        ptr = ptr->next;                /* 後続ノードに着目 */
    }
    return (NULL);            /* 探索失敗 */
}

/*--- 先頭にノードを挿入 ---*/
void InsertFront(List *list, Data x)
{
    Node  *ptr = list->head;
    list->head = list->crnt = AllocNode();
    SetNode(list->head, x, ptr);
}

/*--- 末尾にノードを挿入 ---*/
void InsertRear(List *list, Data x)
{
    if (list->head == NULL)     /* 空であれば */
        InsertFront(list, x);            /* 先頭に挿入 */
    else {
        Node  *ptr = list->head;
        while (ptr->next != NULL)
            ptr = ptr->next;
        ptr->next = list->crnt = AllocNode();
        SetNode(ptr->next, x, NULL);
    }
}

/*--- 先頭ノードを削除 ---*/
void RemoveFront(List *list)
{
    if (list->head != NULL) {
        Node  *ptr = (list->head)->next;
        free(list->head);
        list->head = list->crnt = ptr;
    }
}

/*--- 末尾ノードを削除 ---*/
void RemoveRear(List *list)
{
    if (list->head != NULL) {
        if ((list->head)->next == NULL)  /* ノードが一つだけであれば */
            RemoveFront(list);        /* 先頭ノードを削除 */
        else {
            Node  *ptr = list->head;
            Node  *pre;

            while (ptr->next != NULL) {
                pre = ptr;
                ptr = ptr->next;
            }
            pre->next = NULL;            /* preは末尾から2番目 */
            free(ptr);            /* ptrは末尾*/
            list->crnt = pre;
        }
    }
}

/*--- 着目ノードを削除 ---*/
void RemoveCrnt(List *list)
{
    if (list->head != NULL) {
        if (list->crnt == list->head)      /* 先頭ノードに着目していれば */
            RemoveFront(list);        /* 先頭ノードを削除 */
        else {
            Node  *ptr = list->head;

            while (ptr->next != list->crnt)
                ptr = ptr->next;
            ptr->next = list->crnt->next;
            free(list->crnt);
            list->crnt = ptr;
        }
    }
}




この投稿にコメントする

削除パスワード

No.24911

Re:線形リストのポインタでの質問です
投稿者---marumo(2005/12/22 17:41:31)


続きです。
/*--- 全ノードを削除 ---*/
void ClearList(List *list)
{
    while (list->head != NULL)        /* 空になるまで */
        RemoveFront(list);          /* 先頭ノードを削除 */
    list->crnt = NULL;
}

/*--- データの番号と氏名を表示 ---*/
void PrintData(Data x)
{
    printf("番号:%d 氏名:%s\n", x.no, x.name);
}

/*--- 着目ノードのデータを表示 ---*/
void PrintCrntNode(List *list)
{
    if (list->crnt == NULL)
        puts("着目要素はありません。");
    else
        PrintData(list->crnt->data);
}

/*--- 全ノードのデータをリスト順に表示 ---*/
void PrintList(List *list)
{
    if (list->head == NULL)
        puts("ノードがありません。");
    else {
        Node  *ptr = list->head;

        puts("【一覧表】");
        while (ptr != NULL) {
            PrintData(ptr->data);
            ptr = ptr->next;                /* 後続ノードに着目 */
        }
    }
}

/*--- 線形リストの後始末 ---*/
void TermList(List *list)
{
    ClearList(list);                        /* 全ノードを削除 */
}

/*--- データの入力 ---*/
Data Read(const char *message, int sw)
{
    Data  temp;

    printf("%sするデータを入力してください。\n", message);

    if (sw & NO)    { printf("番号:");      scanf("%d", &temp.no);  }
    if (sw & NAME)  { printf("名前:");    scanf("%s", temp.name); }

    return (temp);
}
void InsertNode(List *list,Node *np,Data x){/*追加部分*/
    Node *ptr;
    ptr=AllocNode();
    ptr->data=x;
    ptr->next=np->next;
    np->next=ptr;
    SetNode(ptr,x,np->next);
}

void PrintNo(List *list){/*追加部分*/
if(list->head==NULL)
puts("ノードがありません。");
else{
    Node *ptr=list->head;
    puts("【一覧表】");
    while(ptr!=NULL){
        printf("%d",ptr->data.no);
    }
}
}

/*--- メニュー選択 ---*/
Menu SelectMenu(void)
{
    int   i, ch;
    char  *mstring[] = {
        "先頭にノードを挿入",    "末尾にノードを挿入",    "先頭のノードを削除",
        "末尾のノードを削除",    "着目ノードを表示",  "着目ノードを削除",
        "番号で探索",            "氏名で探索",            "全ノードを表示",
        "着目ノードの後に追加","すべてのノードのnoを出力","全ノードを削除",       
    };

    do {
        for (i = Term; i < Clear; i++) {
            printf("(%2d) %-18.18s  ", i + 1, mstring[i]);
            if ((i % 3) == 2)
                putchar('\n');
        }
        printf("( 0) 終了 :");
        scanf("%d", &ch);
    } while (ch < Term  ||  ch > Clear);

    return ((Menu)ch);
}

/*--- メイン ---*/
int main(void)
{
    Menu  menu;
    List  list;

    InitList(&list);                            /* 線形リストの初期化 */

    do {
        Data  x;
        Node *ptr;

        switch (menu = SelectMenu()) {
         case InsFront  :   x = Read("先頭に挿入", NO | NAME);
                            InsertFront(&list, x);          break;

         case InsRear   :  x = Read("末尾に挿入", NO | NAME);
                            InsertRear(&list, x);               break;

         case RmvFront  : RemoveFront(&list);            break;

         case RmvRear   :  RemoveRear(&list);                        break;

         case PrintCrnt :    PrintCrntNode(&list);               break;

         case RmvCrnt   :  RemoveCrnt(&list);                        break;

         case SrchNo    :   x = Read("探索", NO);
                            if (SearchNode(&list, x, NoEqual) != NULL)
                                PrintCrntNode(&list);            break;

         case SrchName  : x = Read("探索", NAME);
                            if (SearchNode(&list, x, NameEqual) != NULL)
                                PrintCrntNode(&list);            break;

         case PrintAll  : PrintList(&list);                       break;
         
         case InsNo     :   InsertNode(&list,ptr->next,x);             break;/*追加部分*/
         
         case PriNo     :   PrintNo(&list);                            break;/*追加部分*/
         
         case Clear  :    ClearList(&list);                  break;
        }
    } while (menu != Term);

    TermList(&list);                            /* 線形リストの後始末 */

    return (0);
}


となったのですが、どこが悪いのでしょうか?



この投稿にコメントする

削除パスワード

No.24914

Re:線形リストのポインタでの質問です
投稿者---kolona(2005/12/22 18:37:08)


InsertNode()
のnpが不定(初回の呼び出しなので)のままポインタを使っています。

ptr->next=np->next;

printf()等を使って、エラーが起きている関数を特定して表記した方が良いと思いますよ。どの関数で落ちるのかとか。
あと、操作と症状が逆な気がします。
上記の問題は、(1)を実行しようとすると、実行中にエラーがでて強制的に実行が中止されるものです。

(2)を実行しようとうとすると、実行中にエラーがでて強制的に実行が中止され、

(1)を実行しようとすると、着目していたノードの番号がずっと出力され続けてうまくいきません


この投稿にコメントする

削除パスワード

No.24918

Re:線形リストのポインタでの質問です
投稿者---marumo(2005/12/22 19:01:24)


kolonaさん返信ありがとうございます。

>InsertNode()
>のnpが不定(初回の呼び出しなので)のままポインタを使っています。

>ptr->next=np->next;
よく分からないのですが、どのように改善すればいいのでしょうか?

>あと、操作と症状が逆な気がします。
すいません。間違えてました。


この投稿にコメントする

削除パスワード

No.24919

Re:線形リストのポインタでの質問です
投稿者---kolona(2005/12/22 19:22:03)


>>ptr->next=np->next;
>よく分からないのですが、どのように改善すればいいのでしょうか?
np->next
の値をチェックして、何も指していなければエラーとして返す。
または先頭に追加するとか、細かい仕様は作者が決めればいいです。


この投稿にコメントする

削除パスワード

No.24920

Re:線形リストのポインタでの質問です
投稿者---marumo(2005/12/22 19:41:38)


kolonaさん返信ありがとうございます。
いろいろと考えてみたのですが、どうもよく分かりません。
もし、よければ、きちんと動くものを教えていただけると助かります。

分からなかったのですが、とりあえず、(3)の関数を作ってみました。
追加したのは、

typedef enum {
    Term, InsFront, InsRear, RmvFront, RmvRear, PrintCrnt, RmvCrnt, SrchNo, 
    SrchName, PrintAll,InsNo,PriNo,RmoNo,Clear/*InsNo,PriNoを追加*/
} Menu;
void RemoveNode(List *list,Data x,Data y){
    Node *ptr;
    
    if(list->head!=NULL){
    SearchNode(&list,x,NoEqual);
        SearchNode(&list,y,NameEqual);
        while(ptr->next!=list->crnt)
        ptr=ptr->next;
        ptr->next=list->crnt->next;
        free(list->crnt);
        list->crnt=ptr;
    }
}

 case RmoNo     :   
                                x = Read("探索", NO);
                                y=  Read("探索",NAME);
                                RemoveNode(&list,x,y);                       break;/*追加部分*/



です。これでいいのでしょうか?


この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧