• ベストアンサー

ノード作成時、特別な処理を行わないプログラム

ファイルから読み込んだデータを構造体へ格納するプログラムを作成したのですが、最初のノードを作成する際にも特別な処理を行わないプログラムを作成するように指示されて、どのようにしていけば良いのかわからず困っています。 良ければどなたかヒントなどご指導いただける方いましたらよろしくお願いします。 #include <stdio.h> #include <stdlib.h> #include <string.h> #define NAME_LENGTH 20 /* 名前を格納する文字列の長さ */ #define ADDRESS_LENGTH 30 /* 住所を格納する文字列の長さ */ /* 構造体の定義 */ typedef struct p_tag{ /* タグ */  char name[NAME_LENGTH]; /* 名前 */  char address[ADDRESS_LENGTH]; /* 住所 */  int age; /* 年齢 */  struct p_tag *next; /* 自分自身の型へのポインタ変数 */ } personal_t; /* 住所データ型の定義 */ /*  リスト構造の新しいノードを作成する関数 makeNewNode()  引数   char *aName 名前(文字列)の先頭アドレス   char *aAddr 住所(文字列)の先頭アドレス   int aAge 年齢 返値   personal_t * 新しく作成したノードの先頭アドレス */ personal_t *makeNewNode(char *aName, char *aAddr, int aAge) {  personal_t *pNewData;  /*** personal_t 型のメモリ領域を確保 ***/  pNewData = (personal_t *) malloc( sizeof(personal_t) );  /*** 氏名・住所・年齢のデータを設定する   nextはNULLにする ***/  strcpy( pNewData->name, aName );  strcpy( pNewData->address, aAddr );  pNewData->age = aAge;  pNewData->next = NULL;  return( pNewData ); } /*  main()  引数   なし  返値   int 正常終了の時 0    異常終了の時 -1 (ファイルの読み込み失敗など) */ int main( void ) {  personal_t *pTop = NULL; /* リストの先頭ノードのアドレスを持つ変数 */  personal_t *pNew; /* 新しく作成したノードのアドレスを持つ変数 */  personal_t *pNow; /* 現在見ているノードのアドレスを持つ変数 */  FILE *fp; /* データファイルのファイルポインタ */  char name[ NAME_LENGTH ]; /* ファイルから読み込んだ名前を一時的に保持する変数 */  char address[ ADDRESS_LENGTH ]; /* ファイルから読み込んだ住所を一時的に保持する変数 */  int age; /* ファイルから読み込んだ年齢を一時的に保持する変数 */  /*** データファイル exer4.txt を読み込み用に開く.   ファイルが開けなかった場合,エラーメッセージを表示し異常終了する.***/  fp = fopen( "exer4.txt", "r" );  if ( NULL == fp ) {   printf( "ファイルが開けませんでした.\n" );   return( -1 );  }  /* データファイルから1件目のデータを読み込む   ファイルの終わり(返値がEOF)ならばエラーメッセージを表示し異常終了する.*/   if ( EOF == fscanf( fp, "%s %s %d", name, address, &age ) ) {   printf( "データの読み込みに失敗しました.\n" );    fclose( fp );   return( -1 );  }  /*** 1件目のデータを格納するために,最初のノードを作成する ***/  pTop = makeNewNode( name, address, age );  /*** 現在見ているノードを最初のノードにセットする ***/  pNow = pTop;  /* 2件目以降のデータをファイルの最後(EOF)まで読み込み,   新しく作成したノードに格納していく */  while( EOF != fscanf( fp, "%s %s %d", name, address, &age ) ) {   /*** 新しいノードを作成 ***/   pNew = makeNewNode( name, address, age );  /*** 現在見ているノードに新しいノードを連結し,新しいノードを現在見ているノードとする ***/   pNow->next = pNew;   pNow = pNew;  }  /* ファイルを閉じる */  fclose( fp );  /*** リストを終わりまでたどりながらデータを表示する ***/  /* 現在見ているノードを最初のノードにセットする */  pNow = pTop; /* pTop がないと最初のノードのアドレスが分からなくなる */  /* リストの終わりまでたどり着くと,pNowがNULLになる */  while( pNow != NULL ) {  /* 出力 */   printf( "%-10s %-10s %d\n", pNow->name, pNow->address, pNow->age);   /* 次のデータへ */   pNow = pNow->next;  }  return( 0 ); }

質問者が選んだベストアンサー

  • ベストアンサー
  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.1

> 最初のノードを作成する際にも特別な処理を行わないプログラムを > 作成するように指示されて の意味は 1件目の作成とそれ以後を1回の処理の記述でしなさいといったことでしょう pNew = makeNewNode( name, address, age ); if ( pTop == NULL ) {   // 初回のノードの場合   pTop = pNew; } else {   pNow->next = pNew; } pNow = pNew; といった具合で処理可能なように思います

iriiri_001
質問者

お礼

なるほど。 特別な処理を行わないという解釈がいまいちわからなかったのですが、 一回の処理で記述すれば上手くいきそうですね。 参考になりました。ありがとうございます

その他の回答 (3)

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

ポインタのポインタを使う.

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

新しいノードをリストの最後に追加する関数を作成して、これを繰り返し呼ぶようにすれば良いと思います。 makeNewNode() の代わりに次のようなプロトタイプの関数を作成するということです。 personal_t* Push_back_new_node(personal_t* pperson, char* acName, char* acAddr, int iAge); pperson が 0 なら、新しいノードを作成して返せばよいし、非 0 なら、リストを最後まで手繰ってから新しいノードを追加すればよいということです。 上記を使って、main() のコードは次のようになるでしょう。 personal_t* ppersonTail = 0; while (データを 1 行分入力する) {   ppersonTail = Push_back_new_node(ppersonTail, acName, acAddr, iAge); } C でプログラムしなくてはならなくて、教育課程の課題なのであれば上記のような感じかと思います。 一点注意としては malloc() で確保したメモリは、正しく開放した方が良いですね。C ではこの辺りがスマートに書けないので、出来れば C++ を使える方が良いのですが。 C++ を使っても良くて、仕事ならば、STL の list とか vector を使うべきですが、これでは課題解決にならないんでしょうね。 STL は C++ 標準ライブラリの一部なので、C++ を使っても良いのならば教育課程の課題であったとしても list を使用することは違反ではないでしょう。 むしろ、標準ライブラリにある list 機能を自作するのは車輪を再発明するのに似ているとも言えます。 参考までに C++ で回答に近いものを書くと次のようになります。 #include <cstdio> #include <list> #include <string> using namespace std; struct CPerson {   string m_strName;   int  m_iAge;   CPerson(const string& rstrName, int iAge) : m_strName(rstrName), m_iAge(iAge) {} }; int main() {   list<CPerson> listperson;   FILE* pfile = fopen("D:\\Desktop\\Data.txt", "r");   if (!pfile) { return -1; }   int iAge = 0;   char acName[1000];   while (fscanf(pfile, "%s %d", acName, &iAge) != EOF) {     listperson.push_back(CPerson(acName, iAge));   }   fclose(pfile);   {for (list<CPerson>::iterator itperson = listperson.begin(); itperson != listperson.end(); itperson++) {     printf("%-10s %d\n", itperson->m_strName.c_str(), itperson->m_iAge);   }}   return 0; } list には push_back() という関数があるので、これを使うだけです。Push_back_new_node() を作る必要が無いということですね。 list 自体が pTop、pNew、pNow などにあたるものを全て管理しているので、あとは何でもありということになります。 ご参考にとどめてください。

iriiri_001
質問者

お礼

非常に専門的な回答ありがとうございます。 まだ習っていなくわからない部分も多いですが、今後の参考にさせていただきます。ありがとうございました

回答No.2

 頭にダミーのノードを置く。