【问题标题】:Passing linked list from array by reference通过引用从数组传递链表
【发布时间】:2017-07-10 20:17:00
【问题描述】:

我的问题是,当尝试添加到数组中的链表时,它似乎不起作用,我几乎完全不知道为什么会这样。首先我声明对象move,如下所示:

struct move {
    move(int startX, int startY, int endX, int endY)
    {
        this->startX = startX;
        this->startY = startY;
        this->endX = endX;
        this->endY = endY;
        this->next = nullptr;
    }
    move()
    {
        next = nullptr;
        this->startX = -1;
    }
    int startX;
    int startY;
    int endX;
    int endY;
    move* next;
};

然后我声明 2 个数组,一个包含 100 个 moveobject 的链表,另一个包含指向第一个数组中每个链表中元素的指针。如下图:

move possibleMoves[100];
move * endOfLists[100];

然后我初始化这些数组,如下所示:

for (int i = 0; i < 100; i++) {
    possibleMoves[i] = move();
    endOfLists[i] = &possibleMoves[i];
}

转到添加到 possibleMoves 数组中的一个链表的函数本身,我将其原型如下:

void listAdd(move * list, move * object, int width);

我这样称呼它:

if (possibleMoves[0].startX == -1) {
    possibleMoves[0] = *(new move(x, y, x + xOffset, y + yOffset));
}else {
    listAdd(endOfLists[width], new move(x, y, x + xOffset, y + yOffset), width);
}

函数声明如下:

void listAdd(move * list, move * object, int width) {
    int count = 0;
    while (list->next != nullptr){
        count++;
        list = (*list).next;
    }
    std::cout << "\nCount: " << count << std::endl;
    list->next = object;
    endOfLists[width] = list->next;
}

Count 始终输出为“0”。 这是所有代码(https://pastebin.com/E5g58N6L)的链接,它并不漂亮。 listAdd 过程在第 188、197 和 444 行调用。这是 MCVE:

#include<stdio.h>
#include <stdlib.h>
#include<math.h>
#include<iostream>

    struct move {
        move(int startX, int startY, int endX, int endY)
        {
            this->startX = startX;
            this->startY = startY;
            this->endX = endX;
            this->endY = endY;
            this->next = nullptr;
        }
        move()
        {
            next = nullptr;
            this->startX = -1;
        }
        int startX;
        int startY;
        int endX;
        int endY;
        move* next;
    };
void listAdd(move * list, move * object, int width);
move possibleMoves[100];
move * endOfLists[100];

int main() {
    int x = 0;
    int y = 0;
    int xOffset = 1;
    int yOffset = 1;
    int width = 0;
    for (int i = 0; i < 100; i++) {
        possibleMoves[i] = move();
        endOfLists[i] = &possibleMoves[i];
    }
    if (possibleMoves[0].startX == -1) {
        possibleMoves[0] = *(new move(x, y, x + xOffset, y + yOffset));
    }else {
        listAdd(endOfLists[width], new move(x, y, x + xOffset, y + yOffset), width);
    }

void listAdd(move * list, move * object, int width) {
    int count = 0;
    while (list->next != nullptr) 
    {
        count++;
        list = (*list).next; //Go down the list until it reaches an item with nothing next.
    }

    std::cout << "\nCount: " << count << std::endl;
    list->next = object;
    endOfLists[width] = list->next;
}

【问题讨论】:

  • 仅供参考,初始化循环的第一行 possibleMoves[i] = move(); 毫无意义。已经为该数组中的所有实例调用了该构造函数。
  • 我们只是测试以确保。 (不过感谢您的确认,我们正在质疑我们现在所知道的一切)
  • 你能发布你用来调用listAdd的实际代码吗?你可以写的最短的 main 来测试它。
  • 我添加了整个代码的 pastebin,但我已经检查了 'x'、'y'、'yOffset'、'xOffset' 和 'width'。我几乎可以肯定这些参数设置正确。
  • 我很确定@kabanus 正在请求MCVE,这可能对您自己发现问题以及帮助任何试图回答您的问题的人有用。

标签: c++ arrays pointers reference linked-list


【解决方案1】:

NM 完整的代码。你没有告诉我们最初的width 是什么,但假设它是有效的(即-1&lt;width&lt;100),那没关系。看看这里发生了什么(添加函数结束):

list->next = object;

此时list endOfLists[width]。现在,您正确地将 next 设置为新对象,到目前为止一切顺利。

但是现在呢?

endOfLists[width] = list->next;

因此,保存在全局(为什么?)中的“头”指针绕过了它最初指向的内容(谁有正确的next!)并直接指向后代,即下一个为 NULL 的新对象。我猜这不是你想要的:

  1. 内存泄漏 0 - 最初是静态分配,但如果您以经常使用的方式调用此函数,这很快就会变成动态的。
  2. 在函数结束时,头指针仍然是下一个为 NULL 的对象。确实是一个新的,但下一个仍然是 NULL - 所以下一个调用将执行相同的操作。

基本上你是在交换头部指针,同时泄露内存。您想要:

  1. 首先设置对象:object-&gt;next=endOfLists[width],然后设置第二行让endOfLists[width]=object,有点颠倒列表。
  2. 删除第二行,保留原来的头部。

还有:

  1. 我看不出使用全局变量的充分理由
  2. 为什么 add 函数不是 move 方法?
  3. 您需要确保您拥有delete 所有这些new 对象。

编辑

我看到了您的添加 - 第一次调用 将始终返回 0,因为所有初始对象都有 NULL next,即使您修复了代码。您需要至少两次调用同一索引 (width) 才能开始测试。

图形附录​​

一开始我们有 100 个对象,存储在一个数组中,看起来像这样:

head->list->NULL

list 这里是endOfLists 在某个索引处指向的对象,我们称该指针为head。现在,我们要添加新对象。我们输入加法函数,第一个参数endOfLists[width],所以这将是函数本身中的list 参数。

我们立即跳过 while(因为我们的 next 已经是 NULL)。到上面的第一行,我们现在将我们的头连接到新对象:

list->object->NULL

所以在数组中我们有:

head->list->object->NULL

同样,head 是存储在endOfLists[width] 中的指针。现在我们告诉endOfLists[width] 将头部换成另一个头部,设置它等于list-&gt;next,即对象。那么我们的记忆是怎样的呢?

head->object->NULL
list->^

head(数组单元)和list 都指向对象,没有任何东西指向list。我们去那里泄漏。下次我们用更新的单元格调用函数时,我们将重复这个过程,泄漏对象:

head->     object2->NULL
list->object->^

等等。

【讨论】:

  • 我更新了帖子,使其不会总是返回 0 并且声明了宽度,但考虑到您帖子的其余部分,您能否澄清一些术语,因为我对 C++ 比较陌生。
猜你喜欢
  • 2021-08-15
  • 2011-08-09
  • 2019-09-11
  • 2020-07-30
  • 2012-04-17
  • 2014-08-06
  • 2020-03-09
  • 2019-06-29
相关资源
最近更新 更多