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

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

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

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

Q&A

解決済

1回答

775閲覧

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

don

総合スコア10

C++

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

0グッド

0クリップ

投稿2022/06/06 14:26

編集2022/06/07 13:35

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

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

C++

1#include <iostream> 2using namespace std; 3#include <fstream> 4#include <string> 5#include <direct.h> 6 7typedef struct CharacterStatus{ 8 string strName; 9 int nCharaNum; // 登録順ソートのため 10 CharacterStatus *pPrev; 11 CharacterStatus *pNext; 12} CharaNode; 13 14typedef struct CharacterNodeList{ 15 CharaNode *pHead; // 先頭のノードを指すポインタ 16 CharaNode *pTail; // 末尾のノードを指すポインタ 17} CharaList; 18 19// リストの先頭にノードを挿入 20CharaList *AddNodeToLead( CharaList *pList, int nCharaNum, string strName ) 21{ 22 if( nullptr == pList ){ // 異常系 23 return nullptr; 24 } 25 26 CharaNode *pLeadNode = new CharaNode; // 追加するノードpLeadNodeとメモリの確保 27 28 if( nullptr == pLeadNode ){ // 異常系 29 return nullptr; 30 } 31 32 pLeadNode->pPrev = nullptr; 33 pLeadNode->pNext = nullptr; 34 pLeadNode->strName = strName; 35 pLeadNode->nCharaNum = nCharaNum; 36 37 if( nullptr == pList->pHead && nullptr == pList->pTail ){ // リストが空の場合(追加するノードが唯一のノード) 38 pList->pHead = pLeadNode; 39 pList->pTail = pLeadNode; 40 } 41 else{ // 他のノードがある場合 42 pLeadNode->pNext = pList->pHead; // 追加するノードが持つ次を指すポインタが指すノードを追加前の先頭ノードに変更 43 pList->pHead = pLeadNode; // 先頭ノードの更新 44 pList->pHead->pPrev = pLeadNode; // 追加前の先頭要素が持つ前を指すポインタの指す先を追加するノードに変更 45 } 46 return pList; 47} 48 49// 線形リストの末尾にノードを追加 50CharaList *addNodeToEnd( CharaList *pList, int nCharaNum, string strName ) 51{ 52 if( nullptr == pList ){ // 異常系 53 return nullptr; 54 } 55 56 CharaNode *pEndNode = new CharaNode; // 追加するノードとメモリの確保 57 58 if( nullptr == pEndNode ){ // 異常系 59 return nullptr; 60 } 61 62 pEndNode->pPrev = nullptr; 63 pEndNode->pNext = nullptr; 64 pEndNode->strName = strName; 65 pEndNode->nCharaNum = nCharaNum; 66 67 if( nullptr == pList->pHead && nullptr == pList->pTail ){ // リストが空の場合(追加するノードが唯一のノード) 68 pList->pHead = pEndNode; 69 pList->pTail = pEndNode; 70 } 71 else{ // 他のノードがある場合 72 pEndNode->pPrev = pList->pTail; // 追加するノードが持つ次ポインタが指す先を追加前の末尾ノードに変更 73 pList->pTail->pNext = pEndNode; // 追加前の末尾要素が持つ次を指すポインタの指すノードを追加するノードに変更 74 pList->pTail = pEndNode; // 末尾ノードの更新 75 } 76 return pList; 77} 78 79// 指定のメンバーを持つノードを検索する関数 80CharaNode *searchTargetNode( CharaList *pList, string strTargetCharaName ) 81{ 82 if( nullptr == pList ) { 83 return nullptr; 84 } 85 86 CharaNode *pTargetNode = pList->pHead; // 比較対象のノードを先頭のノードにする 87 88 while( nullptr != pTargetNode ) { 89 if( strTargetCharaName == pTargetNode->strName ) { 90 return pTargetNode; 91 } 92 pTargetNode = pTargetNode->pNext; 93 } 94} 95 96//指定したノードを削除 97CharaList *deleteNode( CharaList *pList, string strTargetCharaName ) 98{ 99 if( nullptr == pList ) { 100 return nullptr; 101 } 102 103 CharaNode *pTargetNode = pList->pHead; 104 105 if( nullptr == pTargetNode ) { 106 cout << "ノードが空なので削除出来ません" << endl; 107 return nullptr; 108 } 109 110 CharaNode *pDeleteNode = searchTargetNode( pList, strTargetCharaName ); 111 if( nullptr == pDeleteNode ){ 112 return nullptr; 113 } 114 115 CharaNode *pPrevNode = pTargetNode; 116 while( nullptr != pTargetNode ) { 117 if( pTargetNode == pDeleteNode ) { 118 if( nullptr == pTargetNode->pPrev && nullptr == pTargetNode->pNext ) { 119 pList->pHead = nullptr; 120 pList->pTail = nullptr; 121 } 122 else if( nullptr == pTargetNode->pPrev ) { // 先頭を削除 123 pList->pHead = pTargetNode->pNext; 124 pList->pHead->pPrev = nullptr; 125 } 126 else if( nullptr == pTargetNode->pNext ) { // 末尾を削除 127 pList->pTail = pTargetNode->pPrev; 128 pList->pTail->pNext = pTargetNode->pNext; 129 } 130 else { 131 pPrevNode->pNext = pTargetNode->pNext; // 先頭と末尾以外のノードを削除 132 pTargetNode->pNext->pPrev = pPrevNode; 133 } 134 delete pTargetNode; 135 return pList; 136 } 137 pPrevNode = pTargetNode; 138 pTargetNode = pTargetNode->pNext; 139 } 140} 141 142// 登録順に並び替え 143CharaList *sortListOrderRegist( CharaList *pList ) 144{ 145 if( nullptr == pList ){ // 異常系 146 return nullptr; 147 } 148 149 CharaNode *pTargetNode; 150 CharaNode *pUnsortNode; 151 CharaNode *pMax; 152 CharaNode *pPrevMax; 153 CharaNode *pSortNode = NULL; 154 155 pUnsortNode = pList->pHead; 156 while( NULL != pUnsortNode ){ 157 pMax = pUnsortNode; 158 pPrevMax = NULL; 159 pTargetNode = pUnsortNode; 160 for( pTargetNode = pUnsortNode; NULL != pTargetNode->pNext; pTargetNode = pTargetNode->pNext ){ 161 // 最大値要素と比較対象要素を比較する 162 if( pTargetNode->pNext->nCharaNum > pMax->nCharaNum ){ 163 // 最大値要素の更新 164 pMax = pTargetNode->pNext; 165 pPrevMax = pTargetNode; 166 } 167 } 168 169 // 最大値要素を未ソートリストから削除 170 if( NULL == pPrevMax ){ 171 pUnsortNode = pMax->pNext; 172 } 173 else { 174 pPrevMax->pNext = pMax->pNext; 175 } 176 177 // 最大値要素をソート済リストの先頭に追加 178 if( NULL == pSortNode ){ 179 pSortNode = pMax; 180 pMax->pNext = NULL; 181 } 182 else { 183 pSortNode->pPrev = pMax; 184 pMax->pNext = pSortNode; 185 pSortNode = pMax; 186 } 187 } 188 if( NULL != pSortNode ){ 189 pSortNode->pPrev = NULL; 190 } 191 pList->pHead = pSortNode; 192} 193 194 195//名前順に並び替え 196CharaList *sortListOrderName( CharaList *pList ) 197{ 198 if( nullptr == pList ){ //異常系 199 return nullptr; 200 } 201 202 CharaNode *pTargetNode; 203 CharaNode *pUnsortNode; 204 CharaNode *pMax; 205 CharaNode *pPrevMax; 206 CharaNode *pSortNode = NULL; 207 208 pUnsortNode = pList->pHead; 209 while( NULL != pUnsortNode ){ 210 pMax = pUnsortNode; 211 pPrevMax = NULL; 212 pTargetNode = pUnsortNode; 213 for( pTargetNode = pUnsortNode; NULL != pTargetNode->pNext; pTargetNode = pTargetNode->pNext ){ 214 // 最大値要素と比較対象要素を比較する 215 if( pTargetNode->pNext->strName > pMax->strName ){ 216 /* 最大値要素の更新 */ 217 pMax = pTargetNode->pNext; 218 pPrevMax = pTargetNode; 219 } 220 } 221 222 // 最大値要素を未ソートリストから削除 223 if( NULL == pPrevMax ){ 224 pUnsortNode = pMax->pNext; 225 } 226 else { 227 pPrevMax->pNext = pMax->pNext; 228 } 229 230 // 最大値要素をソート済リストの先頭に追加 231 if( NULL == pSortNode ){ 232 pSortNode = pMax; 233 pMax->pNext = NULL; 234 pMax->pPrev = NULL; 235 } 236 else { 237 pSortNode->pPrev = pMax; 238 pMax->pNext = pSortNode; 239 pSortNode = pMax; 240 } 241 } 242 if( NULL != pSortNode ){ 243 pSortNode->pPrev = NULL; 244 } 245 pList->pHead = pSortNode; 246} 247 248//リストの全ノードの情報を表示する関数 249CharaList *dispList( CharaList *pList ) 250{ 251 if( nullptr == pList ){ // 異常系 252 return nullptr; 253 } 254 255 if( nullptr == pList->pHead ){ 256 cout << "リストが空であり、表示する情報がありません。" << endl << endl; 257 return nullptr; 258 } 259 260 cout << endl; 261 cout << "氏名" << " " << "キャラクター番号" << endl; 262 for( CharaNode *pNode = pList->pHead; pNode != nullptr; pNode = pNode->pNext ){ 263 cout.width( 16 ); 264 cout << left << pNode->strName; 265 cout.width( 5 ); 266 cout << pNode->nCharaNum << endl; 267 } 268 cout << endl; 269 return pList; 270} 271 272// 検索して見つけたノードの情報(1つだけ)を表示する関数 273CharaNode *dispSingleNode( CharaNode *pTargetNode ) 274{ 275 if( nullptr == pTargetNode ){ 276 return nullptr; 277 } 278 279 cout << "(検索結果)" << endl; 280 cout << "氏名" << " " << "キャラクター番号" << endl; 281 cout.width( 16 ); 282 cout << left << pTargetNode->strName; 283 cout.width( 5 ); 284 cout << pTargetNode->nCharaNum; 285 286 cout << endl << endl; 287 return pTargetNode; 288} 289 290int inputOperateNumber() 291{ 292 int nOperateNum = 0; 293 cout << " 1 : 先頭にキャラクター追加" << endl; 294 cout << " 2 : 末尾にキャラクター追加" << endl; 295 cout << " 3 : リストを表示" << endl; 296 cout << " 4 : キャラクター検索" << endl; 297 cout << " 5 : 指定したキャラクターを削除" << endl; 298 cout << " 6 : 登録順に表示" << endl; 299 cout << " 7 : 名前順に表示" << endl; 300 cout << "10 : 終了" << endl << endl; 301 cout << "どの操作を行いますか(1~11)" << endl; 302 cin >> nOperateNum; 303 cin.clear(); 304 cin.ignore( 256, '\n' ); 305 306 while( nOperateNum < 1 || 10 < nOperateNum ){ 307 cout << "もう一度入力してください。" << endl; 308 cin >> nOperateNum; 309 cin.clear(); 310 cin.ignore( 256, '\n' ); 311 } 312 return nOperateNum; 313} 314 315string inputCharaName() 316{ 317 string strName = ""; 318 cout << "キャラクター名を入力してください。" << endl; 319 getline( cin, strName ); 320 321 if( !cin.good() ){ 322 cin.clear(); 323 cin.ignore( 256, '\n' ); 324 } 325 return strName; 326} 327 328void SuccessOrFail( CharaList *pList ) 329{ 330 if( nullptr == pList ){ 331 cout << "処理に失敗しました。\n" << endl; 332 } 333 else{ 334 cout << "処理に成功しました。\n" << endl; 335 } 336} 337 338void dispFailMessageOrListMemb( CharaList *pList ) 339{ 340 if( nullptr == pList ){ 341 cout << "リストを表示できませんでした。"; 342 } 343 else{ 344 dispList( pList ); 345 } 346} 347 348int main() 349{ 350 string strPathOfCSVFile = "G:\\mondai16.csv"; 351 int nCharaNum = 1; 352 string strName = "\0"; 353 354 CharaList *pList = new CharaList; 355 if( nullptr == pList ){ 356 return 0; 357 } 358 pList->pHead = nullptr; 359 pList->pTail = nullptr; 360 361 while( 1 ){ 362 int nOperateNum = inputOperateNumber(); 363 364 if( 1 == nOperateNum ){ 365 cout << "先頭にキャラクターを追加します。" << endl; 366 strName = inputCharaName(); 367 pList = AddNodeToLead( pList, nCharaNum, strName ); 368 SuccessOrFail( pList ); 369 nCharaNum += 1; 370 371 cout << "(追加後)" << endl; 372 dispFailMessageOrListMemb( pList ); 373 } 374 375 if( 2 == nOperateNum ){ 376 cout << "末尾にキャラクターを追加します。" << endl; 377 strName = inputCharaName(); 378 pList = addNodeToEnd( pList, nCharaNum, strName ); 379 SuccessOrFail( pList ); 380 nCharaNum += 1; 381 cout << "(追加後)" << endl; 382 dispFailMessageOrListMemb( pList ); 383 } 384 385 if( 3 == nOperateNum ){ 386 cout << "現時点でのリストを表示します。" << endl; 387 dispFailMessageOrListMemb( pList ); 388 } 389 390 if( 4 == nOperateNum ){ 391 cout << "検索するキャラクター名を入力してください。" << endl; 392 string strTargetName = "\0"; 393 cin >> strTargetName; 394 CharaNode *pTargetNode = searchTargetNode( pList, strTargetName ); 395 if( searchTargetNode( pList, strTargetName ) ){ 396 cout << strTargetName << "をメンバに持つキャラクターの情報を表示します。" << endl << endl; 397 dispSingleNode( pTargetNode ); 398 } 399 else{ 400 cout << strTargetName << "はリストに存在しません。\n" << endl; 401 } 402 } 403 404 if( 5 == nOperateNum ){ 405 cout << "削除するキャラクター名を入力してください。" << endl; 406 string strDeleteName = "\0"; 407 getline( cin, strDeleteName ); 408 cout << "”" << strDeleteName << " ”をメンバーに持つノードを削除します。" << endl; 409 deleteNode( pList, strDeleteName ); 410 SuccessOrFail( pList ); 411 412 cout << "(削除後)" << endl; 413 dispFailMessageOrListMemb( pList ); 414 cout << endl << endl; 415 } 416 417 if( 6 == nOperateNum ){ 418 cout << "登録順に表示します。\n" << endl; 419 pList = sortListOrderRegist( pList ); 420 dispFailMessageOrListMemb( pList ); 421 } 422 423 if( 7 == nOperateNum ){ 424 cout << "名前順に表示します。\n" << endl; 425 pList = sortListOrderName( pList ); 426 dispFailMessageOrListMemb( pList ); 427 } 428 429 if( 10 == nOperateNum ){ 430 delete pList; // メモリ開放 431 cout << "プログラムを終了します。" << endl; 432 return 0; 433 } 434 } 435} 436

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kazuma-s

2022/06/06 15:11

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

2022/06/06 21:25

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

2022/06/06 23:27

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

回答1

0

ベストアンサー

AddNodeToLead の中の次の 2行の順序が逆です。

C++

1pList->pHead = pLeadNode; 2pList->pHead->pPrev = pLeadNode;

投稿2022/06/07 17:07

kazuma-s

総合スコア8224

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

don

2022/06/08 15:03

エラー出ずにデバックできました。 ありがとうございます! ノードの更新より先に、ポインタが指す先の変更をしなければならない、という理解でいいんでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問