←検索窓の楽しみ方
  ショッピングモール  掲示板ランキング


【掲示板ご利用上の注意】

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

 詳しくはこちら


 本当はこんなに大きく書きたくはないのですが、なかなか守っていただけなくて…。
 守ってくださいね。お願いします。(by管理人)

C言語ソース⇒HTML形式ツール   掲示板1こちら


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

No.4117

DOUBLE RIST
投稿者---Seijko(2005/06/29 19:57:52)


環境:WINXP
  :CYGWIN

リストについての質問です。
下記のようなプログラムを作成しましたが、ダミーの使い方がわかりません。ダミーを使うと場合わけなどが減り平易だとお聞きしましたのでどうしても使いたいわけです。
リストの図を見て考え方はわかるのですが、繋ぎ換えなどを使う所がとくにわかりません。


typedef struct list{
  int num;      /* 社員番号 */
  char name[NAME_MAX_LENGTH];   /* 名前 */  
  int department;     /* 部 */ 
  int section;      /* 課 */ 
  int subsec;     /* 係 */ 
  
  struct person prev *;     /* 前の要素へのポインタ */
  struct person next *;     /* 次の要素へのポインタ */
  } list_t,

int main(void){
  list_t *main_head;
  
  int num;
    
    printf("<メニュー>\n");
    while (num != EXIT) {
        printf("INPUT EVENT\n");
        printf("1.登録\n
              2.削除\n 
              3.保存\n 
              4.一覧表示\n 
              9.終了\n >");q
        
      printf("\nPlease Input num:");
        scanf("%d",&num);
  




return OK;
}


この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:DOUBLE RIST続き 4118 Seijko 2005/06/29 20:09:31


No.4118

Re:DOUBLE RIST続き
投稿者---Seijko(2005/06/29 20:09:31)


000: void regist_data(*main_head)
001: {
002:     list_t *wkdata;/* 作業用ポインタ */
003:   list_t *lp;    /******************/
004:   list_t keep[GET_DATA_MAX];
005:   
006:   FILE *fin;
007:   int exit;
008:   
009:   int data_cnt;
010:   int regist_cnt;
011:   char file_name[];
012:   char buf[BUFFER_LINE_SIZE];
013:   char *str = ZERO;           /* 切り出し項目の一時保存用     */
014:   
015:   
016:   /*文字配列の初期化*/
017:   memset(buf, ZERO, sizeof(buf));
018:   
019:   /* CTRL+D 操作 */
020:   if( scanf( "%s", file_name ) == EOF ) {
021:     return;
022:   }
023:   
024:   /* 読み込み用にファイルをオープン */
025:   fin = fopen("file_name","r");
026:   if(fin == NULL){
027:     printf("登録ファイルを開けません");
028:       return ;
029:   }
030:   
031:   /*ループ1*/
032:   /*データ異常チェックと重複エラー検出をする*/
033:   for(regist_num = ZERO;regist_num<GET_DATA_MAX;regist_num++){
034:     
035:     /* ファイルから1行読み込む */
036:     if(fgets(buf, BUFFER_LINE_SIZE, fin)== NULL){
037:       printf("登録ファイルの読込みに失敗しました。");
038:       return ;
039:     }
040:     
041:     /* 社員番号の切り出し */
042:     str = strtok(buf, ",");
043:     main_head->num = atoi(str);
044:     strcpy(keep[regist_num].num, main_head->num);
045:     /* 社員番号範囲チェック */
046:     if(main_head->num <  NUM_MIN  || main_head->num > NUM_MIN){
047:       printf("入力された社員番号は、範囲外です。");
048:       fclose(fin);
049:       return;
050:     }
051: 
052:     /* 名前の切り出し */
053:     str = strtok(NULL, ",");
054:     strcpy(main_head->name, str);
055:     strcpy(keep[regist_num].name, main_head->name);
056:     /* 名前範囲チェック */
057:     if(isalpha(main_head->name) || ismain_headace(main_head->name)){
058:       ;
059:     }
060:     else{
061:         printf("入力された名前は、範囲外です。");
062:       fclose(fin);
063:       return;
064:     }
065:     
066:     /* 部の切り出し */
067:     str = strtok(NULL, ",");
068:     main_head->department = atoi(str);
069:     strcpy(keep[regist_num].department, main_head->department);
070:     /* 部範囲チェック */
071:     if(main_head->department < 1 || main_head->department >9){
072:       printf("入力された部は、範囲外です。");
073:       fclose(fin);
074:       return;
075:     }
076:     
077:     
078:     line_cnt++;ファイル内の行番号カウンタ
079:     
080:     /* ループ2 */
081:     /* 重複データを省き、登録データをを残す */
082:     for(regist_num = ZERO;regist_num<GET_DATA_MAX;regist_num++){
083:     
084:       for(lp=head;lp!=NULL;lp=lp->next){
085:       if (strcmp(main_head->num, lp->num) == 0){
086:             printf("データが重複しています。\n[line%d]\n\n", line_cnt);
087:             printf("Please Hit Return Key\n");
088:             gets(enter);
089:             fclose(fin);
090:             return;
091:       }
092:       }
093:     regist_cnt++;           /* 新規登録件数をカウント */
094:     
095:     /* ループ3 */
096:     /* リストのメモリを獲得し、登録する */
097:     for(regist_num = ZERO;regist_num<GET_DATA_MAX;regist_num++){
098:       
099:       /* 構造体1個分のメモリ領域を獲得する */
100:       if ((wkdata = (list_t*)malloc(sizeof(list_t))) == NULL){
101:         printf("メモリ獲得できません。\n");
102:         exit(1);
103:       }
104:       /************/
105:       /* 登録処理 */
106:       /************/
107:       strcpy(wkdata->num, keep[regist_num]);
108:       strcpy(wk_data->name, keep[regist_num]);
109:       strcpy(wk_department->department, keep[regist_num]);
110:       strcpy(wk->section->section, keep[regist_num]);
111:       strcpy(wk->subsec->subsec, keep[regist_num]);
112:       
113:       for(lp=main_head;lp!=NULL;lp=lp->next){
114:       }
115:       lp->next = main_head->next;
116:       main_head->before = lp;
117:       
118:     }
119:     data_cnt+=regist_cnt;       /* 登録後の登録件数 */
120:     return;




この投稿にコメントする

削除パスワード

No.4119

Re:DOUBLE RIST続き2
投稿者---Seijko(2005/06/29 20:15:01)


000: /*** double list ***/
001: void delete_data(list_t *main_head ) {
002:   //if( main_head ) return ;

003:     list_t *lp;             /* 作業用のポインタ */
004:   list_t keep[GET_DATA_MAX];          /* 社員番号情報保持配列 */
005:   
006:   FILE *fin;                  /* ファイルポインタ */
007:   int exit = ZERO;                /* CTRL+D用         */
008:   char file_name[BUFFER_LINE_SIZE]; /* 削除ファイル名 */
009:   char enter;             /* ENTER用          */
010:   char *token_p;            /* 一時保持トークン */
011:   char num;             /* 社員番号 */
012:   
013:   int data_cnt;
014:   int delete_cnter = ZERO;      /* 削除ループカウンター   */
015:   int line_cnt = ZERO;        /* 削除データなしエラー時カウント */
016:   int delete_cnt = ZERO;          /* 削除件数カウント */
017:   
018:   printf("<削除>\n\n");
019:   printf("読み込むファイルを指定してください。\n");
020:   printf("file : ");
021:   
022:   /* CTRL+D 操作 */
023:     if( scanf( "%s", file_name) == EOF ) {
024:     return;
025:     }
026:   
027:   /* 読み込み用にファイルをオープン */
028:   fin = fopen("file_name.txt","r");
029:   if(fin == NULL){
030:     printf("削除ファイルを開けません");
031:       return ;
032:   }
033:   /* ループ1:削除対象者判定し、リストに保持する */
034:   for(delete_cnter = ZERO;delete_cnter<GET_DATA_MAX;delete_cnter++){
035:     
036:     /* ファイルから1行読み込む */
037:     if(fgets(buf, BUFFER_LINE_SIZE, fin)== NULL){
038:       printf("削除ファイルの読込みに失敗しました。");
039:       return ;
040:     }
041:     /* 社員番号のみの切り出し */
042:     token_p = strtok(str,",");  
043:     strcpy(num,token_p);
044:     
045:     line_cnt++;           /* 削除データなしエラー時行番号 */
046:     
047:     /* ループ2:既存の社員番号と同じ社員情報をリストに保持する */
048:     
049:      for(lp=main_head;lp!=NULL;lp=lp->next){
050:       if(strcmp(num,lp->num) == ZERO){  /* 既存の社員番号と同じ時(削除対象) */
051:         flag = OK;
052:         keep[delete_cnter] = lp;  /* 情報の保持 */
053:         break;  
054:         }
055:      }
056:     }
057:     /* 削除データが存在しない時 */
058:     if(flag !=OK ){
059:       printf("削除するデータが存在しません。\n[line%d]\n", line_cnt);
060:         printf("Please Hit Return Key\n");
061:             gets(enter);
062:             fclose(fin);
063:             return;
064:     delete_cnt++;           /* 削除件数のカウント */ 
065:     }
066:   }
067:   
068:   /* ループ3:リストの繋ぎ換えとメモリ開放 */
069:   for(delete_cnter = ZERO;delete_cnter<GET_DATA_MAX;delete_cnter++){
070:     for(lp=main_head;lp!=NULL;lp=lp->next){
071:       if(strcmp(keep[delete_cnter],lp->num) == ZERO){   /* 既存の社員番号と同じ時(削除対象) */
072:         if(keep[delete_cnter]->next == NULL){
073:           keep[delete_cnter]->before->next = NULL;
074:         }
075:         else{
076:           keep[delete_cnter]->before->next = keep[delete_cnter]->next;
077:           keep[delete_cnter]->next->before = keep[delete_cnter]->before;
078:         }
079:         free(main_head);                  /* 領域の開放 */
080:       }
081:     }
082:   }
083:   data_cnt -=delete_cnt;                    /* 削除後のデータ数 */
084:   
085:   printf("削除完了\n");
086:   printf("削除されたデータ数 : %d件\n",delete_cnt);
087:   printf("削除後のデータ数   : %d件\n\n",data_cnt);
088:   printf("Please Hit Return Key");
089:   gets(enter);
090:   
091:   fclose(fin);
092:   
093:     return;
094: }




この投稿にコメントする

削除パスワード

No.4120

Re:DOUBLE RIST続き2
投稿者---RAPT(2005/06/29 20:42:02)


Cygwinってことはgcc?

「ダミー」とは? あなたの定義を書いてください。

# > RIST
# LIST のtypoですね。

どうせPGを掲載するならコンパイル可能な最小のコードの方が望ましいです。

struct person の定義は?
struct list との関係も書いてください。

ZERO, EXITなどの定義も無い。

main()内で未初期化の変数 num が参照されている。
文字リテラルの連結も修正の余地あり。


■1の方
000: void regist_data(*main_head)
main_head の型は?

042:     str = strtok(buf, ",");
043:     main_head->num = atoi(str);
044:     strcpy(keep[regist_num].num, main_head->num);
atoi() は int型を返すが、strcpy() の第二引数は const char* を要求する。

046:     if(main_head->num <  NUM_MIN  || main_head->num > NUM_MIN){
main_head->num == NUM_MIN 以外は真になるが良いのか?


■2の方
009:   char enter;             /* ENTER用
061:             gets(enter);
gets() のプロトタイプは char* gets( char* );




この投稿にコメントする

削除パスワード

No.4121

Re:DOUBLE RIST続き2
投稿者---Seiko(2005/06/29 21:14:40)


言葉足りなくてすいません。
特にダミーについて知りたかったので、ソースを修正しないで投稿してしまいました。

><pre>Cygwinってことはgcc?
そうです。
「ダミー」とは? あなたの定義を書いてください。
リストの先頭(head)のデータのことで、利用しないものです。ただし次のデータを指すポインタを所持しています。

# > RIST
# LIST のtypoですね。
ご指摘ありがとうございます。
どうせPGを掲載するならコンパイル可能な最小のコードの方が望ましいです。
*以後気をつけます。

>struct person の定義は?
struct list との関係も書いてください。
*すいません。struct listの間違えでした。(自己参照構造体なので)


ZERO, EXITなどの定義も無い。
こんな感じでしょうか。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

#define REGIST 1
#define DELETE 2
#define SAVE 3
#define PRINT 4
#define EXIT 9

#define NUM_MIN 100000 /* 社員番号の最小値 */
#define NUM_MAX 999999 /* 社員番号の最大値 */
#define NUM_NUM 7 /* 社員番号の配列文字数 */
#define NAME_MIN 1 /* 名前の最小文字数 */
#define NAME_MAX 30 /* 名前の最大文字数 */
#define NAME_NUM 31 /* 名前の配列文字数 */
#define DEPARTMENT_MIN 1 /* 部の数の最小値 */
#define DEPARTMENT_MAX 2 /* 部の数の最大値 */
#define DEPARTMENT_NUM 2 /* 部の配列文字数 */

#define STR_CHECK_MAX 9

#define BUFFER_LINE_SIZE 256 /* 読み出し用バッファの文字数 */
#define GET_DATA_MAX 10 /* データ読み込み最大件数 */
#define ZERO 0 /* 初期化定数 '0' */
#define OK 0
#define NG -1


main()内で未初期化の変数 num が参照されている。
*int num = 0;ですかね。

文字リテラルの連結も修正の余地あり。


■1の方
000: void regist_data(*main_head)
main_head の型は?
*list_t *main_head です。

042: str = strtok(buf, <font color="#3333ff">","</font>);
043: main_head->num = atoi(str);
044: strcpy(keep[regist_num].num, main_head->num);
atoi() は int型を返すが、strcpy() の第二引数は const char* を要求する。
*ここはstrcpyを使わず代入でしょうか?

046: if(main_head->num < NUM_MIN || main_head->num > NUM_MIN){
main_head->num == NUM_MIN 以外は真になるが良いのか?
*後ろのNUM_MINがNUM_MAXの間違いでした。

■2の方
009: char enter; /* ENTER用
061: gets(enter);
gets() のプロトタイプは char* gets( char* );
</pre>

*例えば、char enter[256];ですね。



この投稿にコメントする

削除パスワード

No.4123

Re:DOUBLE RIST続き2
投稿者---RAPT(2005/06/30 00:02:47)


なんか、無駄な処理が多いです。
で、肝心のコードが無い。
# > list_t *main_head;
# 未初期化ですが、正しく作成されていますか?


int型の値を代入するのにstrcpy()を使ったり、int型同士の比較にstrcmp()を
使ったりしています。

main_head は番兵ではないし、なぜか一時変数の代わりに再利用されていたりする。

> struct list prev *;
なんて、本当にコンパイルしましたか?

{}の数も一致していません。

# 修正&コンパイルを試みましたが途中で挫折しました。

「双方向リスト」で終端を記録しているにも関わらず、終端を線形検索してるのはなぜ?

まずは、既存のコードが「まともに」動作することを目指しましょう。
参考:
  C言語入門(双方向リスト/ソート)
  http://www.stackasterisk.jp/tech/program/c01_09.jsp



>> 「ダミー」とは? あなたの定義を書いてください。
> リストの先頭(head)のデータのことで、利用しないものです。
> ただし次のデータを指すポインタを所持しています。



この投稿にコメントする

削除パスワード

No.4159

Re:DOUBLE LIST 登録
投稿者---聖子(2005/07/02 00:11:00)



登録関数のみてもらいたいのですが、最後のprintf()で無限ループに陥ってしますのですが・・
gccのGDBでデバッグしたところ循環型の双方向リストみたい?になってしまっているらしくそれが理由かと思われますが、どう修正したらいいかわからない状況です。
細かいご指摘も歓迎ですが、特にリストの箇所でのアドバイスをよろしくお願いします。
000: void regist_data(list_t *main_head){    /* 引数は録済みリストの先頭要素のポインタ  */
001:     list_t *wkdata = NULL;          /* 新しくファイルから読み込んだデータ */
002:   list_t *roop_p = NULL;            /*リストの先頭から辿るポインタ */
003:   list_t keep[GET_DATA_MAX];
004:   list_t *add_first = NULL;             /* 新規登録リストの先頭要素のポインタ */
005:   list_t *add_last = NULL;              /* 新規登録リストの末尾要素のポインタ */
006:   list_t *last = NULL;                  /* 登録済みリストの末尾要素のポインタ */
007:   int regist_num = 0;         /* 登録人数ループカウンタ */ 
008:     ・
009:     ・
010:     ・
011:   /* リストのメモリを獲得し、登録する */
012:   for(regist_num= 0;regist_num<10;regist_num++)
013:   {
014:       if(flag[regist_num] == OK)
015:     {
016:         
017:           /* 構造体1個分のメモリ領域を獲得する */
018:         if ((wkdata = (list_t*)malloc(sizeof(list_t))) == NULL)
019:         {
020:           printf("メモリ獲得できません。\n");
021:           //exit(1);

022:           continue;
023:         }
024:       
025:         wkdata->next = NULL;
026:         wkdata->prev = NULL;
027:           /**************************/
028:           /* 配列を獲得したメモリへ */
029:           /**************************/
030:           wkdata = &keep[regist_num];  /* ここであらかじめkeep配列に格納した一人分の社員情報をwkdataに入れています。 */
031:         
032:           /************/
033:         /* 登録処理 */
034:         /************/
035:       
036:       
037:         /* 新規登録リストに追加する */
038:         if (add_first == NULL){
039:         add_first = wkdata;
040:         }
041:         else{
042:           add_last->next = wkdata;
043:           wkdata->prev = add_last;
044:         }
045:         
046:         add_last = wkdata;
047:        
048:         /* 新規登録リストを登録済みリストに連結する */
049:         if (main_head == NULL)
050:           main_head = add_first;
051:         else if (add_first != NULL)
052:         {
053:         /* 登録済みリストの末尾データを探す */
054:         for (last=main_head;last->next!= NULL; last = last->next);
055:     
056:           /* 登録済みリストの末尾と新規登録データの先頭をつなげる */
057:           last->next = add_first;
058:           
059:           add_first->prev = last;
060:         }
061:         
062:      }
063:   }
064:   for(roop_p=main_head;roop_p!=NULL;roop_p=roop_p->next){
065:       printf("|%-10d|%-30s|%-4d|%-4d|%-4d|\n", 
066:           roop_p->num,
067:           roop_p->name,
068:           roop_p->department,
069:           roop_p->section,
070:           roop_p->subsec
       }
     ・
     ・
     return;
     }
     




この投稿にコメントする

削除パスワード

No.4160

Re:DOUBLE LIST 登録
投稿者---shu(2005/07/02 00:31:25)


> 登録関数のみてもらいたいのですが、最後のprintf()で無限ループに陥ってしますのですが・・

登録関数に、いちいち表示はいらないと思います。
無限ループになるのは、無限ループになる条件だから。


この投稿にコメントする

削除パスワード

No.4162

Re:DOUBLE LIST 登録
投稿者---聖子(2005/07/02 00:42:26)


ありがとうございます。

>登録関数に、いちいち表示はいらないと思います。
いいえ、私にとって登録関数の動作確認のため、また単独で動きをみるため必要なんです。

>無限ループになるのは、無限ループになる条件だから。

064: for(roop_p=main_head;roop_p!=NULL;roop_p=roop_p->next){
のroop_p!=NULLが無限ループになる条件なのですよね?
私的にはメモリリストの最後までにすればいいことはわかっているのですが、コードが浮かばなくて・・・



この投稿にコメントする

削除パスワード

No.4161

Re:DOUBLE LIST 登録
投稿者---まきじ(2005/07/02 00:39:48)


>* 新規登録リストに追加する */
>038:         if (add_first == NULL){
>039:         add_first = wkdata;
>040:         }
>041:         else{
>042:           add_last->next = wkdata;
>043:           wkdata->prev = add_last;
>044:         }
>045:         
>046:         add_last = wkdata;
>047:        
>048:         /* 新規登録リストを登録済みリストに連結する */
>049:         if (main_head == NULL)
>050:           main_head = add_first;
>051:         else if (add_first != NULL)
>052:         {
>053:         /* 登録済みリストの末尾データを探す */
>054:         for (last=main_head;last->next!= NULL; last = >last->next);
>055:     
>056:           /* 登録済みリストの末尾と新規登録データの先頭をつ>なげる */
>057:           last->next = add_first;
>058:           
>059:           add_first->prev = last;
>060:         }

登録済みリストが無い場合に、新規リストと登録済みリストが
同じリストを参照してるのが原因だと思います。
登録済みリストが無い場合に(main_head == add_first == NULL)、
新規登録をした場合の処理をトレースしてみてください。


この投稿にコメントする

削除パスワード

No.4168

Re:DOUBLE LIST 登録
投稿者---聖子(2005/07/02 13:53:09)


><pre>>* 新規登録リストに追加する */
>038: if (add_first == NULL){
>039: add_first = wkdata;
>040: }
>041: else{
>042: add_last->next = wkdata;
>043: wkdata->prev = add_last;
>044: }
>045:
>046: add_last = wkdata;
>047:
>048: /* 新規登録リストを登録済みリストに連結する */
>049: if (main_head == NULL)
>050: main_head = add_first;
>051: else if (add_first != NULL)
>052: {
>053: /* 登録済みリストの末尾データを探す */
>054: for (last=main_head;last->next!= NULL; last = >last->next);
>055:
>056: /* 登録済みリストの末尾と新規登録データの先頭をつ>なげる */
>057: last->next = add_first;
>058:
>059: add_first->prev = last;
>060: }</pre>
>登録済みリストが無い場合に、新規リストと登録済みリストが
>同じリストを参照してるのが原因だと思います。

すいませんここで言っている同じリストとは何でしょうか?わからなかったので。




この投稿にコメントする

削除パスワード

No.4169

Re:DOUBLE LIST 登録
投稿者---まきじ(2005/07/02 14:15:03)


>すいませんここで言っている同じリストとは何でしょうか?

「main_head と add_first が同じ所を参照してる」という事です。


この投稿にコメントする

削除パスワード

No.4170

Re:DOUBLE LIST 登録
投稿者---聖子(2005/07/02 15:37:40)


>「main_head と add_first が同じ所を参照してる」という事です。

作業用リストwkdataですよね。
なぜ登録済みリストがない時、同じところを参照していることで、問題となるのでしょうか?

いまいちわからなくて。


この投稿にコメントする

削除パスワード

No.4171

Re:DOUBLE LIST 登録
投稿者---まきじ(2005/07/02 16:08:47)


>作業用リストwkdataですよね。

wkdata は、登録する 1 つのノード。

>なぜ登録済みリストがない時、同じところを参照していることで、問題となるのでしょうか?

if (main_head == NULL) main_head = add_first;

の部分は、main_head が NULL の時、つまり、登録済みが無い場合、
main_head = add_first にする。
main_head は、登録済みリストの先頭で、
add_first は、新規登録リストの先頭だから、
main_head = add_first とすると
新規登録 と 登録済み のリストの先頭は同じノードを
参照する事になる。
(先頭が同じという事は、末尾も同じ。)
その状態で、

for (last=main_head;last->next!= NULL; last = >last->next);

を実行すると、last は、main_head(= add_first) が参照してるノード
から、next が NULL になるまで繰り返し、リストの末尾を参照する。



last->next = add_first;
add_first->prev = last;

を実行すると、

last->next = add_first は、登録済みリストの末尾の次を、新規登録リストの先頭にすると意味だが、add_first と main_head が同じノードを
参照してるから、「登録済みリストの末尾と先頭を繋ぐ」とも
「新規登録リストの末尾と先頭を繋ぐ」とも取れる。


この投稿にコメントする

削除パスワード

No.4176

Re:DOUBLE LIST 登録
投稿者---聖子(2005/07/02 17:15:08)


>main_head が NULL の時、つまり、登録済みが無い場合、
>main_head = add_first にする。
>main_head は、登録済みリストの先頭で、
>add_first は、新規登録リストの先頭だから、
>main_head = add_first とすると
>新規登録 と 登録済み のリストの先頭は同じノードを
>参照する事になる。
/
/
/
>last->next = add_first は、登録済みリストの末尾の次を、新規登録リストの先頭にすると意味だが、add_first と main_head が同じノードを
>参照してるから、「登録済みリストの末尾と先頭を繋ぐ」とも
>「新規登録リストの末尾と先頭を繋ぐ」とも取れる。

では、
/* 新規登録リストを登録済みリストに連結する */
if (main_head == NULL){
temp_first = add_first;
main_head = temp_first;

のように一時退避用のlist_t *temp_first;を定義すれば大丈夫ですかね?

それにしても無限ループになってしまう理由は「roop_p!=NULL」だと思いますが、そうするとメモリリストを辿っていく作業用ポインタlist_t *roop_pが最後までいってもNULLにならないという意味ですよね。
テキストや友人のソースではそのように書いてあるのですが???



この投稿にコメントする

削除パスワード

No.4177

Re:DOUBLE LIST 登録
投稿者---まきじ(2005/07/02 17:39:45)


>if (main_head == NULL){
>temp_first = add_first;
>main_head = temp_first;
>のように一時退避用のlist_t *temp_first;を定義すれば大丈夫ですかね?

意味ないと思います。
これだと、temp_first == add_first == main_head になる。


>それにしても無限ループになってしまう理由は「roop_p!=NULL」だと思いますが

循環型双方向リストで無限ループになるなら、ループの条件が問題と
思いますが、今回は、双方向リストなどで、条件としては、!= NULL で
良いと思います。
しかし、next が NULL のノードないから、無限ループになる。

for (last=main_head;last->next!= NULL; last = >last->next);
を実行後

main_head→node1 - node2 - node3 - node4 - node5←last

add_first→node1 - node2 - node3 - node4 - node5←add_last

じゃなく
    main_head
      ↓
add_first→node1 - node2 - node3 - node4 - node5←add_last
                      ↑
                      last
となってる。


この投稿にコメントする

削除パスワード

No.4180

Re:DOUBLE LIST 登録
投稿者---聖子(2005/07/02 19:11:41)


*わかりやすいアドバイスありがとうございます。読ませていただきました。
 以下その後の経過です。

000: 
001:         /* 新規登録リストに追加する */
002:         if (add_first == NULL){
003:          add_first = wkdata;
004:         }
005:         else{
006:           add_last->next = wkdata;
007:           wkdata->prev = add_last;
008:         }
009:         
010:         add_last = wkdata;
011:        
012:         /* 新規登録リストを登録済みリストに連結する */
013:         if (main_head == NULL){
014:           //temp_first = add_first;

015:           main_head = wkdata;
016:         }
017:         else if(add_first != NULL){
018:           /* 登録済みリストの末尾データを探す */
019:           for (last=main_head;last->next!= NULL; last = last->next);
020:     
021:           /* 登録済みリストの末尾と新規登録データの先頭をつなげる */
022:           last->next = add_first;
023:           add_first->prev = last;
024:           
025:         }
026:         
027:         
028:   }
029:   last->next =NULL;
030:   for(roop_p=main_head;roop_p!=NULL;roop_p=roop_p->next){


上記のように無理やりメモリのラストにNULLをいれてみました。この関数内ではうまくいきましたが、print_result関数(コンソールに出力する)ではうまくいきませんでした。

また、登録済みがない時のfirst_headとadd_firstの処理ですが、どうしてもわからないので、もしよろしかったらやり方あるいは更なるヒントをいただけないでしょうか?



この投稿にコメントする

削除パスワード

No.4181

Re:DOUBLE LIST 登録
投稿者---まきじ(2005/07/02 20:30:32)


>また、登録済みがない時のfirst_headとadd_firstの処理ですが、どうしてもわからないので、もしよろしかったらやり方あるいは更なるヒントをいただけないでしょうか?

新規登録しながら、登録済みリストに繋げるのでしたら、最初から
登録済みリストに、登録していけば良いと思います。
登録済みリストに、繋げるのは、新規登録のリストが作成された後
(for(regist_num= 0;regist_num<10;regist_num++) を抜けた後)
に、登録済みリストと繋げるのが良いと思います。

#これのについての質問に対しては応えません。


この投稿にコメントする

削除パスワード

No.4184

Re:DOUBLE LIST 登録
投稿者---聖子(2005/07/03 23:35:09)


その後以下のように改良しました。
ただregist_data関数内ではメモリの先頭アドレスmain_headを最後まで保持できているのに、mainに戻った後、(list_t*)0x00になってしまいます。それでprint_result関数で表示できません。
もう二日ぐらい考えていじっていますが、わかりません。どなたかズバッとご指摘おねがいします。

注)list_t*ってアドレス渡しですよね?
  HTML昆布がうまく働かないですね。
int main(void){
list_t *main_head = NULL;
list_t *list_p;
char num_str[KEYBOARD_LEN_MAX];
int input_number;

while (atoi(num_str) != 9) {
         ・
         ・
      ・
switch(input_number){
    case 1:
    if (gtotal_data_cnt >= REGISTER_MAX) {
printf("登録数は最大30件までです。");
} else {
regist_data(main_head);
}
    break;
        case 4:
    print_result(main_head);
        break;
    case 9:
    printf("\n");
printf("システムを終了します。\n");
if (main_head != NULL) {
for (list_p = main_head; list_p != NULL; list_p = list_p->next) {
free(list_p);
}
}
    return OK;
}

以下は前回までのregist_data関数の要所です。
    /* ループ3 */
/* リストのメモリを獲得し、登録する */
for(regist_num= 0;regist_num<GET_DATA_MAX;regist_num++)
{
   if(flag[regist_num] == OK)
{

   /* 構造体1個分のメモリ領域を獲得する */
if ((wkdata = (list_t*)malloc(sizeof(list_t))) == NULL)
{
printf("メモリ獲得できません。\n");
//exit(1);

continue;
}

//wkdata->next = NULL;

//wkdata->prev = NULL;

   /**************************/
   /* 配列を獲得したメモリへ */
   /**************************/
   wkdata = &keep[regist_num];

   /************/
/* 登録処理 */
/************/


/* 新規登録リストに追加する */

if (add_first == NULL){/* 空の場合は先頭に */
add_first = wkdata;
}
else{/* 上記以外はリストの最後に追加 */
add_last->next = wkdata;
//wkdata->prev = add_last;

}

add_last = wkdata;
}
}
/* 新規登録リストを登録済みリストに連結する */
if (main_head == NULL){
//temp_first = add_first;

main_head = add_first;
}
else if(add_first != NULL){
/* 登録済みリストの末尾データを探す */
for (last=main_head;last->next!= NULL; last = last->next);

/* 登録済みリストの末尾と新規登録データの先頭をつなげる */
last->next = add_first;
//add_first->prev = last;

 
}
gtotal_data_cnt+=regist_cnt;/* 登録後の登録件数 */ printf("\n"); printf("登録完了\n"); printf("登録されたデータ数 : %d件\n",regist_cnt); printf("登録後のデータ数 : %d件\n\n",gtotal_data_cnt); printf("Please Hit Return Key\n"); gets(enter); fclose(fin); return ; } *以下問題の表示関数です。 void print_result(list_t *main_head){ list_t *lp;/* 作業用のポインタ */ char enter[KEYBOARD_LEN_MAX];/* ENTER用 */ if(gtotal_data_cnt!=0){ /* 一覧表示 */ printf("\n<一覧表\示>\n\n"); printf("+----------+-------------------------------+----+----+----+\n"); printf("|社員番号 |名前 |部 |課 |係 |\n"); printf("+----------+-------------------------------+----+----+----+\n"); /* ループ1:メモリ登録人数分整形して表示する */ for(lp=main_head;lp!=NULL;lp=lp->next){ printf("|%-10d|%-30s|%-4d|%-4d|%-4d|\n", lp->num, lp->name, lp->department, lp->section, lp->subsec ); } printf("+----------+-------------------------------+----+----+----+\n\n"); } else{ printf("登録データがありません。\n"); return; } printf("Please Hit Return Key"); gets(enter); return; }




この投稿にコメントする

削除パスワード

No.4185

Re:DOUBLE LIST 登録
投稿者---聖子(2005/07/03 23:59:02)


注)regist_data関数のHTML昆布修正版を貼り直しました。
  ちなみに係の切り出しを見るとわかるようにlist_t の配列keepにデータを格納した後、mallocで確保したメモリwkdataに入れています。

    /* 係の切り出し */
    token_p = strtok(NULL, ",\n");
    keep[regist_num].subsec = atoi(token_p);
    
    /* 係範囲チェック */
    if(keep[regist_num].subsec< 1 || keep[regist_num].subsec > 9){
      printf("入力された係は、範囲外です。");
      fclose(fin);
      return;
    }
  
    line_cnt++;/* ファイル内の行番号カウンタ */
    
    /* ループ2 */
    /* メモリと新規登録データの重複を判定し、フラグをNGにする */
    //for(regist_roop= 0;regist_roop<GET_DATA_MAX;regist_roop++){

        for(roop_p=main_head;roop_p!=NULL;roop_p=roop_p->next){
        /* 新規読込用とメインリスト(既存)用の社員番号の重複があるか? */
          if (keep[regist_num].num == roop_p->num){
            flag[regist_num] = NG;
            printf("データが重複しています。\n[line%d]\n\n", line_cnt);
            printf("Please Hit Return Key\n");
            gets(enter);
            
            fclose(fin);
            return;
        }
        }
    //}

    regist_cnt++;/* 新規登録件数をカウント */
    regist_num++;
  }
    
   
    /* ループ3 */
  /* リストのメモリを獲得し、登録する */
  for(regist_num= 0;regist_num<GET_DATA_MAX;regist_num++)
  {
      if(flag[regist_num] == OK)
    {
        
          /* 構造体1個分のメモリ領域を獲得する */
        if ((wkdata = (list_t*)malloc(sizeof(list_t))) == NULL)
        {
          printf("メモリ獲得できません。\n");
          //exit(1);

          continue;
        }
      
        //wkdata->next = NULL;

        //wkdata->prev = NULL;

          /**************************/
          /* 配列を獲得したメモリへ */
          /**************************/
          wkdata = &keep[regist_num];
        
          /************/
        /* 登録処理 */
        /************/
      
      
        /* 新規登録リストに追加する */
        
        if (add_first == NULL){   /* 空の場合は先頭に */
        add_first = wkdata;
        }
        else{           /* 上記以外はリストの最後に追加 */
          add_last->next = wkdata;
          //wkdata->prev = add_last;

        }
        
        add_last = wkdata;
    }
  }
  /* 新規登録リストを登録済みリストに連結する */
        if (main_head == NULL){
          //temp_first = add_first;

          main_head = add_first;
        }
        else if(add_first != NULL){
          /* 登録済みリストの末尾データを探す */
          for (last=main_head;last->next!= NULL; last = last->next);
          
          /* 登録済みリストの末尾と新規登録データの先頭をつなげる */
          last->next = add_first;
          //add_first->prev = last;

       
        }
・
・
 




この投稿にコメントする

削除パスワード

No.4186

Re:DOUBLE LIST 登録
投稿者---まきじ(2005/07/04 01:15:21)


>ただregist_data関数内ではメモリの先頭アドレスmain_headを最後まで保持できているのに、mainに戻った後、(list_t*)0x00になってしまいます。それでprint_result関数で表示できません。

main_head は、regist_data() で確保した領域のポインタの値に
する必要があるので、regist_data() は、list_p** 型で、
main_head を受け取る必要がある。(参考スレ)
あるいは、list_p* を return する。(こちらの方法が解り易いと思う。)

#main_head をグローバル変数にする方法もある。


この投稿にコメントする

削除パスワード

No.4192

Re:DOUBLE LIST 登録
投稿者---聖子(2005/07/04 20:12:02)


※HTML昆布が工事中なので字下げなどができず見た目が悪いですが上記スレッドとほぼ内容が同じですので、ご了承ください。

グローバル変数版を使って簡単に書き換えてみました。
メモリの先頭アドレスを取り出せるもののやっぱり出力結果がめちゃくちゃでした。(10人分のデータなのに1人分でしかもわけのわからないデータ!)
友達にも相談して改造版を教えていただきましたが、そちらも駄目でしたので。
どなたかご指摘お願いします。


/* ループ3 */
/* リストのメモリを獲得し、登録する */
for(regist_num= 0;regist_num<GET_DATA_MAX;regist_num++)
{
if(flag[regist_num] == OK)
{

/* 構造体1個分のメモリ領域を獲得する */
if ((wkdata = (list_t*)malloc(sizeof(list_t))) == NULL)
{
printf("メモリ獲得できません。\n");
//exit(1);
continue;
}

//wkdata->next = NULL;
//wkdata->prev = NULL;
/**************************/
/* 配列を獲得したメモリへ */
/**************************/
wkdata = &keep[regist_num];

/************/
/* 登録処理 */
/************/


/* 新規登録リストに追加する */
if (add_first == NULL){
add_first = wkdata;
}
else{
add_last->next = wkdata;
wkdata->prev = add_last;
}

add_last = wkdata;
}
}
/* 新規登録リストを登録済みリストに連結する */
if (GLORBALHEAD == NULL){
//temp_first = add_first;
GLORBALHEAD = add_first;
}
else if(add_first != NULL){
/* 登録済みリストの末尾データを探す */
for (last=GLORBALHEAD;last->next!= NULL; last = last->next);

/* 登録済みリストの末尾と新規登録データの先頭をつなげる */
last->next = add_first;
add_first->prev = last;

}


この投稿にコメントする

削除パスワード

No.4193

Re:DOUBLE LIST 登録
投稿者---聖子(2005/07/04 20:21:13)


>※HTML昆布が工事中なので字下げなどができず見た目が悪いですが
ご了承ください。

※先程友人に教えてもらったバージョンです。

int main(void){
list_t main_head;
char num_str[KEYBOARD_LEN_MAX];
int input_number;

main_head.next = NULL;
memset(&main_head,0,sizeof(main_head));



switch(input_number){
case REGIST:
if (gtotal_data_cnt >= REGISTER_MAX) {
printf("登録数は最大30件までです。");
} else {
regist_data(&main_head);
}
break;


case PRINT:
print_result(&main_head);
break;


return OK
}


宣言に以下のものを追加(regist_data関数内)

list_t add_list; /* 新規登録リスト */
memset(&add_list,0,sizeof(add_list));
add_list.next = NULL;




add_first = add_list.next;

/* ループ3 */
/* リストのメモリを獲得し、登録する */
for(regist_num= 0;regist_num<GET_DATA_MAX;regist_num++)
{
if(flag[regist_num] == OK)
{

/* 構造体1個分のメモリ領域を獲得する */
if ((wkdata = (list_t*)malloc(sizeof(list_t))) == NULL)
{
printf("メモリ獲得できません。\n");
//exit(1);
continue;
}
/**************************/
/* 配列を獲得したメモリへ */
/**************************/
wkdata = &keep[regist_num];

/************/
/* 登録処理 */
/************/


/* 新規登録リストに追加する */

if (add_first->num == 0){ /* 空の場合は先頭に */
add_first = wkdata;
}
else{ /* 上記以外はリストの最後に追加 */
wkdata->prev = add_last;
add_last->next = wkdata;
}

add_last = wkdata;
}
}
/* 新規登録リストを登録済みリストに連結する */
if (main_head->num == 0){
main_head->next = add_first;
//main_head->num = add_first->num;
//main_head->next = add_first;

}
else if(add_first != NULL){
/* 登録済みリストの末尾データを探す */
for (last=main_head;last->next!= NULL; last = last->next);

/* 登録済みリストの末尾と新規登録データの先頭をつなげる */
add_first->prev = last;
last->next = add_first;

}


この投稿にコメントする

削除パスワード

No.4195

Re:DOUBLE LIST 登録
投稿者---聖子(2005/07/04 21:04:28)


変換できるサイトを見つけたので訂正します。

 int main(void){
  list_t main_head;
  char num_str[KEYBOARD_LEN_MAX];
  int input_number;
  
  main_head.next = NULL;
  memset(&amp;main_head,0,sizeof(main_head));
・
・
・


switch(input_number){
        case REGIST:
          if (gtotal_data_cnt &gt;= REGISTER_MAX) {
          printf(<font color="#0000ff">&quot;登録数は最大30件までです。&quot;</font>);
        } else {
          regist_data(&amp;main_head);
        }
          break;
        
            
        case PRINT:
          print_result(&amp;main_head);
            break;
</pre>
・
・
・ return;
}

regist_data関数
<pre>void regist_data(list_t *main_head){    <font color="#009900">/* 引数は録済みリストの先頭要素のポインタ  */</font>
list_t add_list;              <font color="#009900">/* 新規登録リスト */</font>
    memset(&amp;add_list,0,sizeof(add_list));
  add_list.next = NULL;

・
・
・
add_first = add_list.next;
  
  /* ループ3 */
  /* リストのメモリを獲得し、登録する */
  for(regist_num= 0;regist_num<GET_DATA_MAX;regist_num++)
  {
    if(flag[regist_num] == OK)
    {
        
        /* 構造体1個分のメモリ領域を獲得する */
        if ((wkdata = (list_t*)malloc(sizeof(list_t))) == NULL)
        {
          printf("メモリ獲得できません。\n");
          //exit(1);

          continue;
        }
      
        //wkdata->next = NULL;

        //wkdata->prev = NULL;

        /**************************/
        /* 配列を獲得したメモリへ */
        /**************************/
        wkdata = &keep[regist_num];
        
        /************/
        /* 登録処理 */
        /************/
        
        
        /* 新規登録リストに追加する */
        
        if (add_first->num == 0){  /* 空の場合は先頭に */
          add_first = wkdata;
        }
        else{      /* 上記以外はリストの最後に追加 */
          wkdata->prev = add_last;
          add_last->next = wkdata;
        }
        
        add_last = wkdata;
    }
  }
  /* 新規登録リストを登録済みリストに連結する */
        if (main_head->num == 0){
          main_head->next = add_first;
          //main_head->num = add_first->num;

          //main_head->next = add_first;

          
        }
        else if(add_first != NULL){
          /* 登録済みリストの末尾データを探す */
          for (last=main_head;last->next!= NULL; last = last->next);
          
          /* 登録済みリストの末尾と新規登録データの先頭をつなげる */
          add_first->prev = last;
          last->next = add_first;
       
        }




この投稿にコメントする

削除パスワード

No.4194

Re:DOUBLE LIST 登録
投稿者---まきじ(2005/07/04 20:54:10)


>メモリの先頭アドレスを取り出せるもののやっぱり出力結果がめちゃくちゃでした。(10人分のデータなのに1人分でしかもわけのわからないデータ!)

同じ所ばっか見てても解決しないと思いますが?
原因は他にあるかも知れません。

>wkdata = &keep[regist_num];
wkdata -> num とか wkdata -> name などは表示できますか?

複雑すぎて、「こうすれば動く」という解答は無理です。
もう 1 度、全体を整理して、見直してみてください。
printf などで、小まめに値をチェックするなどしてください。

#もう付き合いきれないので、私は、これ以上レスしません。


この投稿にコメントする

削除パスワード

No.4196

Re:DOUBLE LIST 登録
投稿者---聖子(2005/07/04 21:18:34)


いつもありがとうございます。

>同じ所ばっか見てても解決しないと思いますが?
>原因は他にあるかも知れません。
仰るとおりです。
(gccのGDBを使って一行一行実行して、初期化されているか・この変数・配列・構造体・・・の中身は何か、セグメンテーションフォールトがここで出るからここが原因だ、関数間の引数はどうなっているなど調べました。

>>wkdata = &keep[regist_num];
>wkdata -> num とか wkdata -> name などは表示できますか?
表示できます。

>複雑すぎて、「こうすれば動く」という解答は無理です。
>もう 1 度、全体を整理して、見直してみてください。
>printf などで、小まめに値をチェックするなどしてください。
もう一度全体を見てみます。(友達に教えてもらったものは私にとっても少し難解でした。)

>#もう付き合いきれないので、私は、これ以上レスしません。
大変ご迷惑をおかけしました。
今まで本当にありがとうございました。


この投稿にコメントする

削除パスワード

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




掲示板提供:Real Integrity