質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
87.20%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

解決済

C++ 線形リスト構造体(双方向)の任意のノードを削除する関数のコードを教えてください。

don
don

総合スコア10

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

1回答

-1評価

0クリップ

239閲覧

投稿2022/06/06 14:26

編集2022/06/09 00:03

開発環境はvisual studio2022です。
私のコードでは
・登録されているノードのうち先頭のノードを削除する場合に、エラーは表示されませんが、先頭も含むすべてのノードが削除されてしまう
末尾ノードを削除する場合にはエラーになります。
「例外がスローされました:読み取りアクセス違反。this が 0xFFFFFFFFFFFFFFE7 でした。」
というエラーが表示されます。
修正箇所の検討がつかないため、改善点、改善方法をご指摘いただきたいです。
その他にもおかしい点があればご指摘いただけるとありがたいです。
よろしくお願いいたします。

以下、ソースコードになります。

C++

#include <iostream> using namespace std; #include <fstream> #include <string> #include <direct.h> typedef struct CharacterStatus{ string strName; int nCharaNum; // 登録順ソートのため CharacterStatus *pPrev; CharacterStatus *pNext; } CharaNode; typedef struct CharacterNodeList{ CharaNode *pHead; // 先頭のノードを指すポインタ CharaNode *pTail; // 末尾のノードを指すポインタ } CharaList; // リストの先頭にノードを挿入 CharaList *AddNodeToLead( CharaList *pList, int nCharaNum, string strName ) { if( nullptr == pList ){ // 異常系 return nullptr; } CharaNode *pLeadNode = new CharaNode; // 追加するノードpLeadNodeとメモリの確保 if( nullptr == pLeadNode ){ // 異常系 return nullptr; } pLeadNode->pPrev = nullptr; pLeadNode->pNext = nullptr; pLeadNode->strName = strName; pLeadNode->nCharaNum = nCharaNum; if( nullptr == pList->pHead && nullptr == pList->pTail ){ // リストが空の場合(追加するノードが唯一のノード) pList->pHead = pLeadNode; pList->pTail = pLeadNode; } else{ // 他のノードがある場合 pLeadNode->pNext = pList->pHead; // 追加するノードが持つ次を指すポインタが指すノードを追加前の先頭ノードに変更 pList->pHead = pLeadNode; // 先頭ノードの更新 pList->pHead->pPrev = pLeadNode; // 追加前の先頭要素が持つ前を指すポインタの指す先を追加するノードに変更 } return pList; } // 線形リストの末尾にノードを追加 CharaList *addNodeToEnd( CharaList *pList, int nCharaNum, string strName ) { if( nullptr == pList ){ // 異常系 return nullptr; } CharaNode *pEndNode = new CharaNode; // 追加するノードとメモリの確保 if( nullptr == pEndNode ){ // 異常系 return nullptr; } pEndNode->pPrev = nullptr; pEndNode->pNext = nullptr; pEndNode->strName = strName; pEndNode->nCharaNum = nCharaNum; if( nullptr == pList->pHead && nullptr == pList->pTail ){ // リストが空の場合(追加するノードが唯一のノード) pList->pHead = pEndNode; pList->pTail = pEndNode; } else{ // 他のノードがある場合 pEndNode->pPrev = pList->pTail; // 追加するノードが持つ次ポインタが指す先を追加前の末尾ノードに変更 pList->pTail->pNext = pEndNode; // 追加前の末尾要素が持つ次を指すポインタの指すノードを追加するノードに変更 pList->pTail = pEndNode; // 末尾ノードの更新 } return pList; } // 指定のメンバーを持つノードを検索する関数 CharaNode *searchTargetNode( CharaList *pList, string strTargetCharaName ) { if( nullptr == pList ) { return nullptr; } CharaNode *pTargetNode = pList->pHead; // 比較対象のノードを先頭のノードにする while( nullptr != pTargetNode ) { if( strTargetCharaName == pTargetNode->strName ) { return pTargetNode; } pTargetNode = pTargetNode->pNext; } } //指定したノードを削除 CharaList *deleteNode( CharaList *pList, string strTargetCharaName ) { if( nullptr == pList ) { return nullptr; } CharaNode *pTargetNode = pList->pHead; if( nullptr == pTargetNode ) { cout << "ノードが空なので削除出来ません" << endl; return nullptr; } CharaNode *pDeleteNode = searchTargetNode( pList, strTargetCharaName ); if( nullptr == pDeleteNode ){ return nullptr; } CharaNode *pPrevNode = pTargetNode; while( nullptr != pTargetNode ) { if( pTargetNode == pDeleteNode ) { if( nullptr == pTargetNode->pPrev && nullptr == pTargetNode->pNext ) { pList->pHead = nullptr; pList->pTail = nullptr; } else if( nullptr == pTargetNode->pPrev ) { // 先頭を削除 pList->pHead = pTargetNode->pNext; pList->pHead->pPrev = nullptr; } else if( nullptr == pTargetNode->pNext ) { // 末尾を削除 pList->pTail = pTargetNode->pPrev; pList->pTail->pNext = pTargetNode->pNext; } else { pPrevNode->pNext = pTargetNode->pNext; // 先頭と末尾以外のノードを削除 pTargetNode->pNext->pPrev = pPrevNode; } delete pTargetNode; return pList; } pPrevNode = pTargetNode; pTargetNode = pTargetNode->pNext; } } // 登録順に並び替え CharaList *sortListOrderRegist( CharaList *pList ) { if( nullptr == pList ){ // 異常系 return nullptr; } CharaNode *pTargetNode; CharaNode *pUnsortNode; CharaNode *pMax; CharaNode *pPrevMax; CharaNode *pSortNode = NULL; pUnsortNode = pList->pHead; while( NULL != pUnsortNode ){ pMax = pUnsortNode; pPrevMax = NULL; pTargetNode = pUnsortNode; for( pTargetNode = pUnsortNode; NULL != pTargetNode->pNext; pTargetNode = pTargetNode->pNext ){ // 最大値要素と比較対象要素を比較する if( pTargetNode->pNext->nCharaNum > pMax->nCharaNum ){ // 最大値要素の更新 pMax = pTargetNode->pNext; pPrevMax = pTargetNode; } } // 最大値要素を未ソートリストから削除 if( NULL == pPrevMax ){ pUnsortNode = pMax->pNext; } else { pPrevMax->pNext = pMax->pNext; } // 最大値要素をソート済リストの先頭に追加 if( NULL == pSortNode ){ pSortNode = pMax; pMax->pNext = NULL; } else { pSortNode->pPrev = pMax; pMax->pNext = pSortNode; pSortNode = pMax; } } if( NULL != pSortNode ){ pSortNode->pPrev = NULL; } pList->pHead = pSortNode; } //名前順に並び替え CharaList *sortListOrderName( CharaList *pList ) { if( nullptr == pList ){ //異常系 return nullptr; } CharaNode *pTargetNode; CharaNode *pUnsortNode; CharaNode *pMax; CharaNode *pPrevMax; CharaNode *pSortNode = NULL; pUnsortNode = pList->pHead; while( NULL != pUnsortNode ){ pMax = pUnsortNode; pPrevMax = NULL; pTargetNode = pUnsortNode; for( pTargetNode = pUnsortNode; NULL != pTargetNode->pNext; pTargetNode = pTargetNode->pNext ){ // 最大値要素と比較対象要素を比較する if( pTargetNode->pNext->strName > pMax->strName ){ /* 最大値要素の更新 */ pMax = pTargetNode->pNext; pPrevMax = pTargetNode; } } // 最大値要素を未ソートリストから削除 if( NULL == pPrevMax ){ pUnsortNode = pMax->pNext; } else { pPrevMax->pNext = pMax->pNext; } // 最大値要素をソート済リストの先頭に追加 if( NULL == pSortNode ){ pSortNode = pMax; pMax->pNext = NULL; pMax->pPrev = NULL; } else { pSortNode->pPrev = pMax; pMax->pNext = pSortNode; pSortNode = pMax; } } if( NULL != pSortNode ){ pSortNode->pPrev = NULL; } pList->pHead = pSortNode; } //リストの全ノードの情報を表示する関数 CharaList *dispList( CharaList *pList ) { if( nullptr == pList ){ // 異常系 return nullptr; } if( nullptr == pList->pHead ){ cout << "リストが空であり、表示する情報がありません。" << endl << endl; return nullptr; } cout << endl; cout << "氏名" << " " << "キャラクター番号" << endl; for( CharaNode *pNode = pList->pHead; pNode != nullptr; pNode = pNode->pNext ){ cout.width( 16 ); cout << left << pNode->strName; cout.width( 5 ); cout << pNode->nCharaNum << endl; } cout << endl; return pList; } // 検索して見つけたノードの情報(1つだけ)を表示する関数 CharaNode *dispSingleNode( CharaNode *pTargetNode ) { if( nullptr == pTargetNode ){ return nullptr; } cout << "(検索結果)" << endl; cout << "氏名" << " " << "キャラクター番号" << endl; cout.width( 16 ); cout << left << pTargetNode->strName; cout.width( 5 ); cout << pTargetNode->nCharaNum; cout << endl << endl; return pTargetNode; } int inputOperateNumber() { int nOperateNum = 0; cout << " 1 : 先頭にキャラクター追加" << endl; cout << " 2 : 末尾にキャラクター追加" << endl; cout << " 3 : リストを表示" << endl; cout << " 4 : キャラクター検索" << endl; cout << " 5 : 指定したキャラクターを削除" << endl; cout << " 6 : 登録順に表示" << endl; cout << " 7 : 名前順に表示" << endl; cout << "10 : 終了" << endl << endl; cout << "どの操作を行いますか(1~11)" << endl; cin >> nOperateNum; cin.clear(); cin.ignore( 256, '\n' ); while( nOperateNum < 1 || 10 < nOperateNum ){ cout << "もう一度入力してください。" << endl; cin >> nOperateNum; cin.clear(); cin.ignore( 256, '\n' ); } return nOperateNum; } string inputCharaName() { string strName = ""; cout << "キャラクター名を入力してください。" << endl; getline( cin, strName ); if( !cin.good() ){ cin.clear(); cin.ignore( 256, '\n' ); } return strName; } void SuccessOrFail( CharaList *pList ) { if( nullptr == pList ){ cout << "処理に失敗しました。\n" << endl; } else{ cout << "処理に成功しました。\n" << endl; } } void dispFailMessageOrListMemb( CharaList *pList ) { if( nullptr == pList ){ cout << "リストを表示できませんでした。"; } else{ dispList( pList ); } } int main() { string strPathOfCSVFile = "G:\\mondai16.csv"; int nCharaNum = 1; string strName = "\0"; CharaList *pList = new CharaList; if( nullptr == pList ){ return 0; } pList->pHead = nullptr; pList->pTail = nullptr; while( 1 ){ int nOperateNum = inputOperateNumber(); if( 1 == nOperateNum ){ cout << "先頭にキャラクターを追加します。" << endl; strName = inputCharaName(); pList = AddNodeToLead( pList, nCharaNum, strName ); SuccessOrFail( pList ); nCharaNum += 1; cout << "(追加後)" << endl; dispFailMessageOrListMemb( pList ); } if( 2 == nOperateNum ){ cout << "末尾にキャラクターを追加します。" << endl; strName = inputCharaName(); pList = addNodeToEnd( pList, nCharaNum, strName ); SuccessOrFail( pList ); nCharaNum += 1; cout << "(追加後)" << endl; dispFailMessageOrListMemb( pList ); } if( 3 == nOperateNum ){ cout << "現時点でのリストを表示します。" << endl; dispFailMessageOrListMemb( pList ); } if( 4 == nOperateNum ){ cout << "検索するキャラクター名を入力してください。" << endl; string strTargetName = "\0"; cin >> strTargetName; CharaNode *pTargetNode = searchTargetNode( pList, strTargetName ); if( searchTargetNode( pList, strTargetName ) ){ cout << strTargetName << "をメンバに持つキャラクターの情報を表示します。" << endl << endl; dispSingleNode( pTargetNode ); } else{ cout << strTargetName << "はリストに存在しません。\n" << endl; } } if( 5 == nOperateNum ){ cout << "削除するキャラクター名を入力してください。" << endl; string strDeleteName = "\0"; getline( cin, strDeleteName ); cout << "”" << strDeleteName << " ”をメンバーに持つノードを削除します。" << endl; deleteNode( pList, strDeleteName ); SuccessOrFail( pList ); cout << "(削除後)" << endl; dispFailMessageOrListMemb( pList ); cout << endl << endl; } if( 6 == nOperateNum ){ cout << "登録順に表示します。\n" << endl; pList = sortListOrderRegist( pList ); dispFailMessageOrListMemb( pList ); } if( 7 == nOperateNum ){ cout << "名前順に表示します。\n" << endl; pList = sortListOrderName( pList ); dispFailMessageOrListMemb( pList ); } if( 10 == nOperateNum ){ delete pList; // メモリ開放 cout << "プログラムを終了します。" << endl; return 0; } } }

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

kazuma-s

2022/06/06 15:11

提示されているコード以外の部分に原因があると思われます。 searchTargetNode や リストを作成する部分などのコード全部と 実際のテストデータを追記してください。
int32_t

2022/06/06 21:25

まずはデバッグビルドをして、Visual Studio のデバッガ上で実行してみてください。
y_waiwai

2022/06/06 23:27

質問は編集できます 無駄に質問建てないで追記修正しましょう

まだ回答がついていません

会員登録して回答してみよう

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
87.20%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。