指针在链表深拷贝构造函数中永远不会到达 null
Pointer never reaches null in linked list deep copy constructor
我目前正在构建一个名为 Sequence 的链表 class。有四个私有节点 - headPtr、tailPtr、cursor(当前节点)和 precursor(前一个节点)。
当光标是列表中的最后一项时,我的复制构造函数工作正常,但是当光标出于某种原因位于中间时,该函数永远不会退出 while 循环。
复制构造函数如下:
Sequence::Sequence(const Sequence& copyMe) {
copy(copyMe);
}
void Sequence::copy(const Sequence& copyMe) {
numitems = 0;
if (copyMe.headPtr == nullptr) {
cursor = precursor = headPtr = tailPtr = nullptr;
}
else {
// allocate a new node for the new sequence
node* newPtr = new node;
newPtr -> data = copyMe.headPtr -> data;
numitems++;
// start the new sequence with this node
headPtr = newPtr;
precursor = nullptr;
cursor = headPtr;
tailPtr = headPtr;
// create a node to traverse the origin sequence
node* originPtr = copyMe.headPtr -> next;
while (originPtr != nullptr) {
// add node to the new list, make it the current, & assign data
newPtr->next = new node;
newPtr = newPtr->next;
newPtr->data = originPtr->data;
numitems++;
// Correct cursor and precursor positions
if(originPtr == copyMe.cursor) {
this->cursor = newPtr;
}
else if (originPtr == copyMe.precursor) {
this->precursor = newPtr;
}
originPtr = originPtr->next;
// if the thing being copied is the last thing, make it tailptr
if (originPtr == nullptr) {
tailPtr = newPtr->next;
cout << "tail assigned" << endl;
newPtr->next = nullptr;
originPtr = nullptr;
}
}
}
}
这里是 driver 程序:
const size_t TESTSIZE = 30;
Sequence original; // A Sequence that we'll copy.
double items[2 * TESTSIZE];
size_t i;
// Set up the items array to conatin 1...2*TESTSIZE.
for (i = 1; i <= 2 * TESTSIZE; i++)
items[i - 1] = i;
// This section works fine //
// Test copying of an empty Sequence. After the copying, we change original.
cout << "Copy constructor test: for an empty Sequence." << endl;
Sequence copy1(original);
original.attach(1); // Changes the original Sequence, but not the copy.
// Test copying of a Sequence with current item at the tail.
cout << "Copy constructor test: for a Sequence with cursor at tail." << endl;
for (i = 2; i <= 2 * TESTSIZE; i++) {
original.attach(i);
}
Sequence copy2(original);
original.remove_current();
original.start();
original.advance();
original.remove_current(); // Delete 2 from original, but not the copy.
// This section gets stuck in the while loop of my copy constructor //
// Test copying of a Sequence with cursor near the middle.
cout << "Copy constructor test: with cursor near middle." << endl;
original.insert(2);
for (i = 1; i < TESTSIZE; i++)
original.advance();
// Cursor is now at location [TESTSIZE] (counting [0] as the first spot).
Sequence copy3(original);
我很困惑为什么光标的位置会影响 originPtr
的前进,以及为什么 originPtr
不会变为 null 并分配尾巴。我尝试输出它指向的内容,但它似乎只是以循环方式不断地在内存插槽中前进。一旦达到 60,它会立即返回到从 2 添加而不是终止。
感谢您的帮助!
编辑:
这是在添加一些 cout 语句后最后使用游标时输出的样子:
Copy constructor test: for a Sequence with cursor at tail.
Copy constructor test: for a Sequence with cursor at tail.
newPtr is: 0x7fa6dcd00140 and originPtr is: 0x7fa6dcd00000
newPtr is: 0x7fa6dce00010 and originPtr is: 0x7fa6dcd00020
newPtr is: 0x7fa6dce00020 and originPtr is: 0x7fa6dcd00030
newPtr is: 0x7fa6dce00030 and originPtr is: 0x7fa6dcd00040
newPtr is: 0x7fa6dce00040 and originPtr is: 0x7fa6dcd00050
newPtr is: 0x7fa6dce00050 and originPtr is: 0x7fa6dcd00060
newPtr is: 0x7fa6dce00060 and originPtr is: 0x7fa6dcd00070
newPtr is: 0x7fa6dce00070 and originPtr is: 0x7fa6dcd00080
newPtr is: 0x7fa6dce00080 and originPtr is: 0x7fa6dcd00090
newPtr is: 0x7fa6dce00090 and originPtr is: 0x7fa6dcd000a0
newPtr is: 0x7fa6dce000a0 and originPtr is: 0x7fa6dcd000b0
newPtr is: 0x7fa6dce000b0 and originPtr is: 0x7fa6dcd000c0
newPtr is: 0x7fa6dce000c0 and originPtr is: 0x7fa6dcd000d0
newPtr is: 0x7fa6dce000d0 and originPtr is: 0x7fa6dcd000e0
newPtr is: 0x7fa6dce000e0 and originPtr is: 0x7fa6dcd000f0
newPtr is: 0x7fa6dce000f0 and originPtr is: 0x7fa6dcd00100
newPtr is: 0x7fa6dce00100 and originPtr is: 0x7fa6dcd00110
newPtr is: 0x7fa6dce00110 and originPtr is: 0x7fa6dcd00120
NULL REACHED
tail assigned
与光标在中间的下一个测试
newPtr is: 0x7fa6dcf00030 and originPtr is: 0x7fa6dcd00000
newPtr is: 0x7fa6dcf00040 and originPtr is: 0x7fa6dcd00020
newPtr is: 0x7fa6dcf00050 and originPtr is: 0x7fa6dcd00030
newPtr is: 0x7fa6dcf00060 and originPtr is: 0x7fa6dcd00040
newPtr is: 0x7fa6dcf00070 and originPtr is: 0x7fa6dcd00050
newPtr is: 0x7fa6dcf00080 and originPtr is: 0x7fa6dcd00060
newPtr is: 0x7fa6dcf00090 and originPtr is: 0x7fa6dcd00070
newPtr is: 0x7fa6dcd00010 and originPtr is: 0x7fa6dcd00080
newPtr is: 0x7fa6dcd00120 and originPtr is: 0x7fa6dcd00090
newPtr is: 0x7fa6dcd00150 and originPtr is: 0x7fa6dcd000a0
newPtr is: 0x7fa6dcd00160 and originPtr is: 0x7fa6dcd000b0
newPtr is: 0x7fa6dcd00170 and originPtr is: 0x7fa6dcd000c0
newPtr is: 0x7fa6dcd00180 and originPtr is: 0x7fa6dcd000d0
newPtr is: 0x7fa6dcd00190 and originPtr is: 0x7fa6dcd000e0
newPtr is: 0x7fa6dce00120 and originPtr is: 0x7fa6dcd000f0
newPtr is: 0x7fa6dce00130 and originPtr is: 0x7fa6dcd00100
newPtr is: 0x7fa6dce00140 and originPtr is: 0x7fa6dcd00110
newPtr is: 0x7fa6dce00150 and originPtr is: 0x7fa6dcd00120
newPtr is: 0x7fa6dce00160 and originPtr is: 0x7fa6dcd00150
newPtr is: 0x7fa6dce00170 and originPtr is: 0x7fa6dcd00160
newPtr is: 0x7fa6dce00180 and originPtr is: 0x7fa6dcd00170
newPtr is: 0x7fa6dce00190 and originPtr is: 0x7fa6dcd00180
newPtr is: 0x7fa6dce001a0 and originPtr is: 0x7fa6dcd00190
newPtr is: 0x7fa6dce001b0 and originPtr is: 0x7fa6dce00120
newPtr is: 0x7fa6dce001c0 and originPtr is: 0x7fa6dce00130
newPtr is: 0x7fa6dce001d0 and originPtr is: 0x7fa6dce00140
newPtr is: 0x7fa6dce001e0 and originPtr is: 0x7fa6dce00150
newPtr is: 0x7fa6dce001f0 and originPtr is: 0x7fa6dce00160
newPtr is: 0x7fa6dce00200 and originPtr is: 0x7fa6dce00170
newPtr is: 0x7fa6dce00210 and originPtr is: 0x7fa6dce00180
newPtr is: 0x7fa6dce00220 and originPtr is: 0x7fa6dce00190
newPtr is: 0x7fa6dce00230 and originPtr is: 0x7fa6dce001a0
// and so on forever because its stuck in a loop and endlessly advancing somehow
复制构造函数的正确语法是:
Sequence::Sequence(const Sequence& copyMe) {...}
您写了:
void Sequence::copy(const Sequence& copyMe) {...}
这意味着你定义了一个成员函数而不是构造函数。所以你的构造函数永远不会被调用。当您创建 copy1、copy2 和 copy3 时,将使用默认构造函数。
更新
if (originPtr == nullptr) {
tailPtr = newPtr->next; // newPtr->next is not initialized here
// consider tailPtr = newPtr instead
cout << "tail assigned" << endl;
newPtr->next = nullptr; // good
originPtr = nullptr; // originPtr is nullptr here because of if condition
}
更新2
我无法检查您移动光标当前位置和先前位置的实现,但请注意,在您的复制构造函数中,您假定当前指针和先前指针始终不同。
else if (originPtr == copyMe.precursor) { // consider removing 'else' here
更新3
Sequence copy2(original);
original.remove_current(); // here you remove the last element
看起来问题出在 remove_current()
。构造函数中的循环不依赖于光标位置。但这取决于原始序列的 node->next 值。所以创建副本的错误不会导致死循环。无限循环的唯一原因是原始序列格式错误。我怀疑您在从序列中删除最后一个元素后忘记更新最后一个节点的 next
值。在您发布 remove_current().
的代码之前,我无法证明我的话
更新4
void Sequence::remove_current() {
if (is_item()) {
node* temp;
temp = cursor;
if (cursor == headPtr && cursor == tailPtr) {
cursor = nullptr;
precursor = nullptr;
headPtr = nullptr;
tailPtr = nullptr;
}
else if (cursor == headPtr) {
headPtr = cursor->next;
cursor = headPtr;
precursor = nullptr;
}
else {
if (cursor == tailPtr) {
precursor->next = nullptr;
tailPtr = precursor;
cursor = precursor;
if (precursor == headPtr) {
precursor = nullptr;
}
else {
for(precursor = headPtr; precursor->next->next; precursor = precursor->next);
}
}
else {
precursor->next = cursor->next;
cursor = cursor->next;
}
}
delete temp;
numitems--;
}
}
我目前正在构建一个名为 Sequence 的链表 class。有四个私有节点 - headPtr、tailPtr、cursor(当前节点)和 precursor(前一个节点)。
当光标是列表中的最后一项时,我的复制构造函数工作正常,但是当光标出于某种原因位于中间时,该函数永远不会退出 while 循环。
复制构造函数如下:
Sequence::Sequence(const Sequence& copyMe) {
copy(copyMe);
}
void Sequence::copy(const Sequence& copyMe) {
numitems = 0;
if (copyMe.headPtr == nullptr) {
cursor = precursor = headPtr = tailPtr = nullptr;
}
else {
// allocate a new node for the new sequence
node* newPtr = new node;
newPtr -> data = copyMe.headPtr -> data;
numitems++;
// start the new sequence with this node
headPtr = newPtr;
precursor = nullptr;
cursor = headPtr;
tailPtr = headPtr;
// create a node to traverse the origin sequence
node* originPtr = copyMe.headPtr -> next;
while (originPtr != nullptr) {
// add node to the new list, make it the current, & assign data
newPtr->next = new node;
newPtr = newPtr->next;
newPtr->data = originPtr->data;
numitems++;
// Correct cursor and precursor positions
if(originPtr == copyMe.cursor) {
this->cursor = newPtr;
}
else if (originPtr == copyMe.precursor) {
this->precursor = newPtr;
}
originPtr = originPtr->next;
// if the thing being copied is the last thing, make it tailptr
if (originPtr == nullptr) {
tailPtr = newPtr->next;
cout << "tail assigned" << endl;
newPtr->next = nullptr;
originPtr = nullptr;
}
}
}
}
这里是 driver 程序:
const size_t TESTSIZE = 30;
Sequence original; // A Sequence that we'll copy.
double items[2 * TESTSIZE];
size_t i;
// Set up the items array to conatin 1...2*TESTSIZE.
for (i = 1; i <= 2 * TESTSIZE; i++)
items[i - 1] = i;
// This section works fine //
// Test copying of an empty Sequence. After the copying, we change original.
cout << "Copy constructor test: for an empty Sequence." << endl;
Sequence copy1(original);
original.attach(1); // Changes the original Sequence, but not the copy.
// Test copying of a Sequence with current item at the tail.
cout << "Copy constructor test: for a Sequence with cursor at tail." << endl;
for (i = 2; i <= 2 * TESTSIZE; i++) {
original.attach(i);
}
Sequence copy2(original);
original.remove_current();
original.start();
original.advance();
original.remove_current(); // Delete 2 from original, but not the copy.
// This section gets stuck in the while loop of my copy constructor //
// Test copying of a Sequence with cursor near the middle.
cout << "Copy constructor test: with cursor near middle." << endl;
original.insert(2);
for (i = 1; i < TESTSIZE; i++)
original.advance();
// Cursor is now at location [TESTSIZE] (counting [0] as the first spot).
Sequence copy3(original);
我很困惑为什么光标的位置会影响 originPtr
的前进,以及为什么 originPtr
不会变为 null 并分配尾巴。我尝试输出它指向的内容,但它似乎只是以循环方式不断地在内存插槽中前进。一旦达到 60,它会立即返回到从 2 添加而不是终止。
感谢您的帮助!
编辑: 这是在添加一些 cout 语句后最后使用游标时输出的样子:
Copy constructor test: for a Sequence with cursor at tail.
Copy constructor test: for a Sequence with cursor at tail.
newPtr is: 0x7fa6dcd00140 and originPtr is: 0x7fa6dcd00000
newPtr is: 0x7fa6dce00010 and originPtr is: 0x7fa6dcd00020
newPtr is: 0x7fa6dce00020 and originPtr is: 0x7fa6dcd00030
newPtr is: 0x7fa6dce00030 and originPtr is: 0x7fa6dcd00040
newPtr is: 0x7fa6dce00040 and originPtr is: 0x7fa6dcd00050
newPtr is: 0x7fa6dce00050 and originPtr is: 0x7fa6dcd00060
newPtr is: 0x7fa6dce00060 and originPtr is: 0x7fa6dcd00070
newPtr is: 0x7fa6dce00070 and originPtr is: 0x7fa6dcd00080
newPtr is: 0x7fa6dce00080 and originPtr is: 0x7fa6dcd00090
newPtr is: 0x7fa6dce00090 and originPtr is: 0x7fa6dcd000a0
newPtr is: 0x7fa6dce000a0 and originPtr is: 0x7fa6dcd000b0
newPtr is: 0x7fa6dce000b0 and originPtr is: 0x7fa6dcd000c0
newPtr is: 0x7fa6dce000c0 and originPtr is: 0x7fa6dcd000d0
newPtr is: 0x7fa6dce000d0 and originPtr is: 0x7fa6dcd000e0
newPtr is: 0x7fa6dce000e0 and originPtr is: 0x7fa6dcd000f0
newPtr is: 0x7fa6dce000f0 and originPtr is: 0x7fa6dcd00100
newPtr is: 0x7fa6dce00100 and originPtr is: 0x7fa6dcd00110
newPtr is: 0x7fa6dce00110 and originPtr is: 0x7fa6dcd00120
NULL REACHED
tail assigned
与光标在中间的下一个测试
newPtr is: 0x7fa6dcf00030 and originPtr is: 0x7fa6dcd00000
newPtr is: 0x7fa6dcf00040 and originPtr is: 0x7fa6dcd00020
newPtr is: 0x7fa6dcf00050 and originPtr is: 0x7fa6dcd00030
newPtr is: 0x7fa6dcf00060 and originPtr is: 0x7fa6dcd00040
newPtr is: 0x7fa6dcf00070 and originPtr is: 0x7fa6dcd00050
newPtr is: 0x7fa6dcf00080 and originPtr is: 0x7fa6dcd00060
newPtr is: 0x7fa6dcf00090 and originPtr is: 0x7fa6dcd00070
newPtr is: 0x7fa6dcd00010 and originPtr is: 0x7fa6dcd00080
newPtr is: 0x7fa6dcd00120 and originPtr is: 0x7fa6dcd00090
newPtr is: 0x7fa6dcd00150 and originPtr is: 0x7fa6dcd000a0
newPtr is: 0x7fa6dcd00160 and originPtr is: 0x7fa6dcd000b0
newPtr is: 0x7fa6dcd00170 and originPtr is: 0x7fa6dcd000c0
newPtr is: 0x7fa6dcd00180 and originPtr is: 0x7fa6dcd000d0
newPtr is: 0x7fa6dcd00190 and originPtr is: 0x7fa6dcd000e0
newPtr is: 0x7fa6dce00120 and originPtr is: 0x7fa6dcd000f0
newPtr is: 0x7fa6dce00130 and originPtr is: 0x7fa6dcd00100
newPtr is: 0x7fa6dce00140 and originPtr is: 0x7fa6dcd00110
newPtr is: 0x7fa6dce00150 and originPtr is: 0x7fa6dcd00120
newPtr is: 0x7fa6dce00160 and originPtr is: 0x7fa6dcd00150
newPtr is: 0x7fa6dce00170 and originPtr is: 0x7fa6dcd00160
newPtr is: 0x7fa6dce00180 and originPtr is: 0x7fa6dcd00170
newPtr is: 0x7fa6dce00190 and originPtr is: 0x7fa6dcd00180
newPtr is: 0x7fa6dce001a0 and originPtr is: 0x7fa6dcd00190
newPtr is: 0x7fa6dce001b0 and originPtr is: 0x7fa6dce00120
newPtr is: 0x7fa6dce001c0 and originPtr is: 0x7fa6dce00130
newPtr is: 0x7fa6dce001d0 and originPtr is: 0x7fa6dce00140
newPtr is: 0x7fa6dce001e0 and originPtr is: 0x7fa6dce00150
newPtr is: 0x7fa6dce001f0 and originPtr is: 0x7fa6dce00160
newPtr is: 0x7fa6dce00200 and originPtr is: 0x7fa6dce00170
newPtr is: 0x7fa6dce00210 and originPtr is: 0x7fa6dce00180
newPtr is: 0x7fa6dce00220 and originPtr is: 0x7fa6dce00190
newPtr is: 0x7fa6dce00230 and originPtr is: 0x7fa6dce001a0
// and so on forever because its stuck in a loop and endlessly advancing somehow
复制构造函数的正确语法是:
Sequence::Sequence(const Sequence& copyMe) {...}
您写了:
void Sequence::copy(const Sequence& copyMe) {...}
这意味着你定义了一个成员函数而不是构造函数。所以你的构造函数永远不会被调用。当您创建 copy1、copy2 和 copy3 时,将使用默认构造函数。
更新
if (originPtr == nullptr) {
tailPtr = newPtr->next; // newPtr->next is not initialized here
// consider tailPtr = newPtr instead
cout << "tail assigned" << endl;
newPtr->next = nullptr; // good
originPtr = nullptr; // originPtr is nullptr here because of if condition
}
更新2
我无法检查您移动光标当前位置和先前位置的实现,但请注意,在您的复制构造函数中,您假定当前指针和先前指针始终不同。
else if (originPtr == copyMe.precursor) { // consider removing 'else' here
更新3
Sequence copy2(original);
original.remove_current(); // here you remove the last element
看起来问题出在 remove_current()
。构造函数中的循环不依赖于光标位置。但这取决于原始序列的 node->next 值。所以创建副本的错误不会导致死循环。无限循环的唯一原因是原始序列格式错误。我怀疑您在从序列中删除最后一个元素后忘记更新最后一个节点的 next
值。在您发布 remove_current().
更新4
void Sequence::remove_current() {
if (is_item()) {
node* temp;
temp = cursor;
if (cursor == headPtr && cursor == tailPtr) {
cursor = nullptr;
precursor = nullptr;
headPtr = nullptr;
tailPtr = nullptr;
}
else if (cursor == headPtr) {
headPtr = cursor->next;
cursor = headPtr;
precursor = nullptr;
}
else {
if (cursor == tailPtr) {
precursor->next = nullptr;
tailPtr = precursor;
cursor = precursor;
if (precursor == headPtr) {
precursor = nullptr;
}
else {
for(precursor = headPtr; precursor->next->next; precursor = precursor->next);
}
}
else {
precursor->next = cursor->next;
cursor = cursor->next;
}
}
delete temp;
numitems--;
}
}