コメントに記載されているように、機能にのアドレス-のリストを渡さないために問題が発生しています。問題は基本的なものですが、多くの人を捉えています。リンクされたリストのアドレスは、の最初のノードのアドレスです。したがって、最初のノードを削除するときは、新しいリストアドレスを次のノードアドレスに設定して、リストを引き続き操作する必要があります。
関数にポインタを渡すと、次のようになります。 void deleteNode(card *head, ...
の場合、deleteNode
には、head
のコピーが入ります。コピーにはすべて独自のアドレスがあり、そのアドレスは呼び出し元関数のポインタのアドレスとは関係ありません。ポインターの値は、発信者にあるとおり、deleteNode
と同じですが、アドレスはまったく異なります。
deleteNode
の最初のノードを削除すると問題が発生します。メモリはfree
'dであり、deleteNode
関数が戻ります。今すぐ呼び出し元に戻って(おそらくmain()
)、次にhead
- bamにアクセスしようとすると! segfault。どうして? head
のアドレスはmain
に更新されていないので、元のノードを指しています。元のノードのメモリには何をしましたか?deleteNode
? (あなたが最初のノードを保持するメモリのブロックを指摘ポインタにfree
と呼ばれる - そのなくなって...)
問題を解決するには、単にdeleteNode
にアドレスのリスト(head
)を渡します。 (例えば、void deleteNode(card **head, ...
)。次に、あなたはのアドレスがhead
(例えば、ポインタのポインタのポインタ)で動作しています。最初のノードを削除する前に、*head = head->listp;
を設定し、新しいリストアドレスを呼び出し元の関数に反映させます(main()
)。たとえば、コードは次のように書くことができます。
void delnode (card **head, int coordinate)
{
card *current = *head;
card *victim = NULL;
victim = current;
int count = 1;
while (current != NULL) {
if (coordinate == 0) {
*head = current->listp;
free (victim);
break;
}
else if (count == coordinate) {
victim = current->listp;
current->listp = current->listp->listp;
free (victim);
break;
}
else {
count++;
current = current->listp;
}
}
}
ただし、最小限の労力で機能のロジックを少し改善することができます。例えば
void delnode (card **head, int coordinate)
{
card *current = *head;
card *victim = current;
int count = 1;
if (coordinate == 0) {
*head = current->listp;
free (victim);
return;
}
while (current != NULL)
{
if (count == coordinate) {
victim = current->listp;
current->listp = current->listp->listp;
free (victim);
return;
}
count++;
current = current->listp;
}
}
最後に、How to Ask a QuestionとHow to create a Minimal, Complete, and Verifiable exampleを記述するリンクをご覧ください。あなたのコードや関連するエラーを含む必要な情報を提供することで、皆さんがあなたの質問にお手伝いします。
この質問は完璧な例です。誰かがあなたを助け、実際に問題や答えをコンパイルして確認するために、ここであなたの基礎的なリスト構造が何であるかを知るためのサンプルプログラムを書くように頼んでいます。ここで質問をするとき、MCVEを提供する目的は、他の人があなたのコードをコンパイルして問題を確認し、必要に応じてデバッガでコンパイルされたコードを実行することです。私たちがあなたを助けるのに役立つサイトの最小限の提案やルールに従えば、さらに多くの助けと肯定的な反応が得られます。
これは、サンプルコードのこの小さなビットで削除の操作を確認できます。任意のコードでは
#include <stdio.h>
#include <stdlib.h>
typedef struct card {
int cardno;
struct card *listp;
} card;
card *createnode (int c);
card *insert (card **list, int c);
void prnlist (card *list);
void delnode (card **head, int coordinate);
void dellist (card *list);
void *xcalloc (size_t nmemb, size_t sz);
int main (void) {
card *list = NULL;
insert (&list, 18); /* insert test nodes */
insert (&list, 6);
insert (&list, 54);
insert (&list, 12);
insert (&list, 60);
insert (&list, 30);
printf ("\noriginal list:\n");
prnlist (list);
printf ("\ndeleting node: 2\ndeleting node: 0\n");
delnode (&list, 2); /* delete 3rd & 1st nodes */
delnode (&list, 0);
printf ("\nfinal list:\n");
prnlist (list);
dellist (list); /* free allocated memory */
return 0;
}
card *createnode (int c)
{
card *node = xcalloc (1, sizeof *node);
node->listp = NULL;
node->cardno = c;
return node;
}
card *insert (card **list, int c)
{
card *iter = *list;
card *node = createnode (c);
if (!*list) { /* add 1st node to list */
*list = node;
return *list;
}
/* insert all other nodes at end */
for (; iter->listp; iter = iter->listp) {}
iter->listp = node;
return *list;
}
void prnlist (card *list)
{
card *iter = list;
for (; iter->listp; iter = iter->listp)
printf (" cardno : %d\n", iter->cardno);
printf (" cardno : %d\n", iter->cardno);
}
void delnode (card **head, int coordinate)
{
card *current = *head;
card *victim = current;
int count = 1;
if (coordinate == 0) {
*head = current->listp;
free (victim);
return;
}
while (current != NULL)
{
if (count == coordinate) {
victim = current->listp;
current->listp = current->listp->listp;
free (victim);
return;
}
count++;
current = current->listp;
}
}
void dellist (card *list)
{
card *iter = list;
while (iter) {
card *victim = iter;
iter = iter->listp;
free (victim);
}
}
void *xcalloc (size_t nmemb, size_t sz)
{
void *memptr = calloc (nmemb, sz);
if (!memptr) {
fprintf (stderr, "xcalloc() error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
return memptr;
}
使用例/出力
$ ./bin/lldelcard
original list:
cardno : 18
cardno : 6
cardno : 54
cardno : 12
cardno : 60
cardno : 30
deleting node: 2
deleting node: 0
final list:
cardno : 6
cardno : 12
cardno : 60
cardno : 30
メモリエラーチェック
動的にメモリを割り当て、あなたの書き込みには、割り当てられたメモリの任意のブロックに関する2 responsibilitesを持っています: (1)常にメモリブロックの開始アドレスへのポインタを保持する、(2)不要になったときに解放することができる。
メモリエラーチェックプログラムを使用して、割り振られたメモリブロックの外側または外側に書き込まれていないことを確認し、初期化されていない値の読み込みまたはベースを試み、最後に解放したことを確認することが不可欠ですあなたが割り当てたすべてのメモリ。
Linuxの場合valgrind
が通常の選択です。新しいメモリブロックを誤用する方法はたくさんあります。メモリエラーチェッカーを使用すると、問題を特定して、segfault
を介して問題を発見するのではなく、割り当てたメモリの適切な使用を検証できます。すべてのプラットフォームに同様のメモリチェッカーがあります。それらはすべて使いやすく、プログラムを実行するだけです。
$ valgrind ./bin/lldelcard
==9094== Memcheck, a memory error detector
==9094== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==9094== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==9094== Command: ./bin/lldelcard
==9094==
original list:
cardno : 18
cardno : 6
cardno : 54
cardno : 12
cardno : 60
cardno : 30
deleting node: 2
deleting node: 0
final list:
cardno : 6
cardno : 12
cardno : 60
cardno : 30
==9094==
==9094== HEAP SUMMARY:
==9094== in use at exit: 0 bytes in 0 blocks
==9094== total heap usage: 6 allocs, 6 frees, 96 bytes allocated
==9094==
==9094== All heap blocks were freed -- no leaks are possible
==9094==
==9094== For counts of detected and suppressed errors, rerun with: -v
==9094== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)
必ず確認すべてのヒープブロックが解放された - 何の漏れがERROR概要可能と同様に重要ではない:0エラーを0コンテキストから。
あなたのコーディングで幸運を祈る。
最初のノードを削除するとリストのアドレスが変更されます(リストアドレスは最初のノードのアドレス)。 –
head == nullはいつですか? – Pemdas