• 締切済み

双方向リストの関数

双方向リストにデータファイルから読み込んだ氏名と成績のデータを追加し,リストの末尾から順にデータを表示するプログラムを作成したのですが、insertLast() 関数を用いて末尾ノードの後ろに新しいノードを連結するという部分をどのようにして良いのかわからず困っています。 どのように記述して良いのかわからなかった部分を/*** ***/のコメントで示してあります。 どなたかアドバイスやヒント、その他の指摘などご教授してくださる方いましたらよろしくお願いします。 #include <stdio.h> #include <stdlib.h> #include <string.h> #define NAME_LENGTH 20 /* 名前を格納する文字列の長さ */ /* 双方向リストのノードとなる構造体の定義 */ typedef struct sList{  struct sList *prev; /* 前のノードのアドレス */  char name[NAME_LENGTH]; /* 名前 */  char grade; /* 成績 */  struct sList *next; /* 次のノードのアドレス */ } sNode; /* この構造体を sNode型 と定義する */ /* 双方向リストの先頭と末尾を格納するための構造体 */ typedef struct {  sNode *firstNode; /* リストの先頭ノードのアドレス */  sNode *lastNode; /* リストの末尾ノードのアドレス */ } manageList; /*  双方向リストの末尾にノードを追加する関数 insertLast()  引数   manageList *list リストの先頭・末尾ノードを管理する構造体のアドレス   sNode *node 末尾に追加したいノードのアドレス  返値   なし */ void insertLast(manageList *list, sNode *node ) {  /*** リストの末尾にノードを追加する ***/  return; } /*  双方向リストの新しいノードを作成する関数 makeNewNode()  引数   char *aName 名前(文字列)の先頭アドレス   char aGrade 成績  返値   sNode * 新しく作成したノードの先頭アドレス */ sNode *makeNewNode(char *aName, char aGrade ) {  sNode *pNewData;  /* sNode 型のメモリ領域を確保 */  pNewData = (sNode *) malloc( sizeof(sNode) );  /* 名前と成績のデータを設定する */  strcpy( pNewData->name, aName );  pNewData->grade = aGrade;  pNewData->prev = NULL;  pNewData->next = NULL;  return( pNewData ); } /*  main()  引数   なし  返値   int 正常終了の時 0     異常終了の時 -1 (ファイルの読み込み失敗など) */ int main( void ) {  manageList list; /* リストの先頭・末尾ノードのアドレスを持つ構造体 */  sNode *pNew; /* 新しく作成したノードのアドレスを持つ変数 */  sNode *pNow; /* 現在見ているノードのアドレスを持つ変数 */  FILE *fp; /* データファイルのファイルポインタ */  char name[ NAME_LENGTH ]; /* ファイルから読み込んだ名前を一時的に保持する変数 */  char grade; /* ファイルから読み込んだ成績を一時的に保持する変数 */  /* 初期状態では先頭・末尾ノードともNULL */  list.firstNode = NULL;  list.lastNode = NULL;  /* データファイル exer6.txt を読み込み用に開く.    ファイルが開けなかった場合,エラーメッセージを表示し異常終了する.*/  fp = fopen("exer6.txt","r");  if(NULL == firstNode){   printf( "ファイルが開けませんでした. \n" );   return( -1 );  }  /* データをファイルの最後(EOF)まで読み込み,双方向リストにデータを追加する */  while( EOF != fscanf( fp, "%s %c", name, &grade ) ) {   /* 新しいノードを作成 */   pNew = makeNewNode( name, grade );   /*** insertLast() 関数を用いて末尾ノードの後ろに新しいノードを連結する ***/   pNow->next = pNew ;   pNew->prev = pNow ;   pNow = pNew ;  /* ファイルを閉じる */  fclose( fp );  /* 現在見ているノードを末尾ノードにセットする */  pNow = lastNode  /* 末尾のノードから前のノードへたどりながらデータを出力する */  while( NULL != pNow ) {   /* 出力 */   printf( "%s %c\n", pNow->name, pNow->grade );   /* 現在見ているノードを一つ前のノードにする */   pNow = pNow->prev;  }  return( 0 ); }

みんなの回答

  • plh
  • ベストアンサー率50% (4/8)
回答No.8

あはは、すみません。コンパイルも通るし、間違いでも無いので、化石的コーディングとは言い過ぎたかもしれません。 言いたかったのは、typedef で始めて、構造体を定義するのは、(私が思うに)、あまり良いスタイルとは言えないというだけのことです。 ただでさえ、理解するのが少し難しい typedef と構造体の定義を絡ませてわざわざ複雑にすべきではなく、typedef を使うのなら Tacosan のおっしゃるように typedef struct sList sList; struct sList {   sList* m_pslist; }; というように分けて書いた方がよほど分かりやすく、自己参照構造体にしてもすっきりと定義できるので、こちらの方が良いと思うと、単にそう言いたかっただけなのでした。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.7

C++ では無意味だけど C では「無意味」というほどではない>#5, #6. 文法上は「struct と書かなくていい」程度 (プログラムを読む人間の意味としては違うけど) ではあるので, 個人的には typedef struct sList { ... } sList; または typedef struct sList sList; struct sList { ... }; の方が好み. さておいて, 「先頭に挿入する」のも「末尾に挿入する」のも同じことで, 図を描いて「どのようにリンクを張り直せばよいか」を考えればわかる.

  • asuncion
  • ベストアンサー率33% (2127/6289)
回答No.6

> typedef struct sList { ... } sNode; 自己参照構造体を定義するときには十分意味がある書き方のように見えます。 化石的コーディングではないと思います。

  • plh
  • ベストアンサー率50% (4/8)
回答No.5

あと、その他の指摘として、本質とは無関係ですが、構造体を次のように typedef で定義するのは(未だに良く見かけますが)、もはや、化石的コーディングなので止めましょう。 typedef struct sList { ... } sNode; この場合、同じ構造体に sList と sNode という二つの名前が付いてしまいます。だから、間違いというわけではないですが、無意味であり、混乱の元になるだけです。 次のように定義してください。 struct sNode { ... }; 課題のコードが元から typedef を使って書かれていたのであれば、先生の頭がちょっと古いのかもしれませんよ。

  • asuncion
  • ベストアンサー率33% (2127/6289)
回答No.4

リスト構造について解説しているサイトはそれこそ山のようにありますが、 私が見かけた中で「これはわかりやすそうだ」と思った場所を 参考URLに挙げておきます。 なお、ds03.html~ds06.htmlがありまして、最後のds06で双方向リストについて解説しています。 線形リストについてご存じであっても、復習をかねて ds03~ds05もごらんになっておくとよいかもしれません。

参考URL:
http://tdweb.cssa.chs.nihon-u.ac.jp/ds/ds03.html
  • plh
  • ベストアンサー率50% (4/8)
回答No.3

main() 側で、   /*** insertLast() 関数を用いて末尾ノードの後ろに新しいノードを連結する ***/   insertLast(list, pNew); のように insertLast() を呼び出し、insertLast() 側では、渡された引数を元に list の最後に pNew を連結するということですね。 課題なのであれば、ここかさ先は自分で考えたほうが良いと思います。 あと、malloc() で確保したメモリは、必ず開放するということをお忘れなく。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

リストの先頭にノードを追加することはできますか?

iriiri_001
質問者

補足

リストの先頭にノードを追加するというのは課題の指示に無かったので、たぶんできないと思います。

  • plh
  • ベストアンサー率50% (4/8)
回答No.1

このプログラムの目的は何でしょう? データを逆順にプリントすること? そうであれば、無理して双方向リストを使うより、単純な配列を使った方が簡単です。 お勉強というのなら話は別になりますが。

iriiri_001
質問者

補足

双方向リストの課題なので双方向リストを使っています。

関連するQ&A