修改 的
为简单起见: 我只想制作最基本的可能光标,只需通过我的列表而不改变任何方式/形状或形成我的“开始”。我仍然希望在我返回一些东西时开始改变,而不是之前。那么有可能制作一个指针开始,通过列表而不改变任何东西,除非在我想添加一个新节点的最后?
我可以通过一个不是“节点”的简单指针进入列表吗?
的 /修改 的
我有一个简单的(单一)链接列表作为我作业的一部分。当然,除此之外我还有很多事情要做,但是在我把清单拿出来后,一切都应该是前进的,但是我已经使用了C ++一段时间了(这是我用的是C ++)我的很多东西知道要么被遗忘了,要么已经过时了。我已经在python中编程了一段时间,但所有这些意味着我一直对指针在C ++中的工作方式感到沮丧。
我的问题是当我尝试将新节点添加到列表中时,我的光标表现异常,我将在下面解释:
编辑: 好的,我更改了:
Node *cursor;
cursor = new Node
cursor = begin;
fiasco,但结果是一样的,在声明游标之后并开始指向同一个内存位置(类似于:0x32ce8)。
的 /修改 的
Node *add_node (Node *begin,string type, int sum, int ap_nr) // begin is the first node in the list
{
// if first node is dummy node
if (begin->ap_nr == -1)
{
begin->type = type;
begin->ap_nr = ap_nr;
begin->sum = sum;
begin->next = 0;
return begin;
}
// else create new node and insert it in sorted position
else
{
// EDIT:
Node *cursor = begin; // Same problem
//if node should be inserted before first node (begin)
if (ap_nr <begin->ap_nr)
{
cursor->ap_nr = ap_nr;
cursor->type = type;
cursor->sum = sum;
cursor->next = begin;
return cursor;
}
总是当我调试时,开始有一个类似的形式:0x32ce02,当我创建我的“光标”时它有一个非常不同的形式(也更长),但当我这样做:cursor = begin,然后光标变成这样的东西0x32df02。
然而问题是当我到达“if(ap_nr ap_nr)”然后绝对没有可行的原因光标变为:0x32ce02和“cursor - &gt; next = begin”确保无限循环。无论我添加多少个节点,这总是会发生,所以每当我打印列表时,它都是最后添加的节点的无限流。
我做错了吗?它是宣言还是主宰,创造?什么?
另外如果我有一个指针*从另一个模块中的某个地方开始,并且使用这个函数我会返回一个新的开始...应该可以正常工作,对吗?
P.S。我还要感谢一个简单的反制解决方案(如果我的方法不好,另一种方法就是这样做)
另外我应该指出我是如何制作我的清单的。它只是一个简单的节点链接:
struct Node {
string type;
int ap_nr;
int sum;
Node *next;
};
答案 0 :(得分:2)
此代码:
cursor = new Node;
cursor = begin;
以下内容:
current
begin
包含的地址即。它所做的就是泄漏一个新的Node
。 cursor
和begin
之后指向同一事物。
这一行:
cursor->next = begin;
制作一个循环。 cursor->next == begin == cursor
。
删除cursor = begin;
行,然后返回光标将执行您想要的操作。使用new Node
创建的节点将成为列表的新头部,begin
在函数开头指向的节点将成为该列表中的第二个节点。
现在,当您想要遍历(不添加)该列表时,您可以执行以下操作:
Node *cursor = begin; // assuming begin is the head of your list
while (cursor != 0) {
// process this node
cursor = cursor->next;
}
这将访问列表中的每个节点,假设您已正确构建它。
一些注意事项:
调用此函数的代码应该类似于:
list = add_node(list, ...);
如果你没有,那就得不到你想要的。
如果您在begin
中看到的地址非常与new
返回的地址不同,那么您可能会做错事,即{{ 1}}可以指向堆栈地址。不要将堆栈中的对象放在列表中,请确保使用begin
分配它们。 (如果new
指向一个全局静态变量,那很好 - 但请确保你没有begin
它。
除非你实际上需要一个虚拟节点,否则我建议你删除它 - 这会使你的delete
函数变得比它需要的更复杂。
这是一个如何在没有特殊虚拟节点(不完整代码)的情况下执行此操作的框架:
add_node
并使用它:
Node *add_node(Node *list, ...)
{
Node *new_node = new Node;
new_node->next = list;
// fill in other properties
return new_node;
}
答案 1 :(得分:1)
Node *cursor;
cursor = new Node;
cursor = begin;
在这里准确理解你在使用这三条线做什么 - 可能还有比实际意识更多的事情。
在第一行,您声明一个名为 cursor 的新变量 - 此变量是指针对象的名称,其类型为 Node * 。 (简单来说,Node *表示“指向 Node ”的指针) 存储在指针对象中的数据类型只是数字积分数据,恰好代表存储器中的地址。指针对象与任何其他类型的整数对象实际上没有什么不同 (注意“变量”和“对象”之间的区别 - 对象是存储在内存中的内容,例如数字/字符/内存地址,变量是 名称 < / strong>对象)
在第二行,发生了两件事 - 首先为 Node 对象分配内存,并在分配的内存中构造一个新的 Node 对象 - 这个内存没有变量名,它只是一个免费商店对象(这是新节点的工作原理的简短版本),然后使用=运算符(赋值运算符)来存储地址值(a 游标变量中新分配的节点对象的数字 存储新Node对象的地址值后,访问新分配的Node对象的唯一方法是通过游标变量名。
在第三行,您会立即覆盖游标变量存储的值;它不是存储新节点的地址数据,而是存储另一个对象的地址(从另一个指针变量复制的另一个对象的地址,名为 begin )。这会立即导致新分配的节点被“泄露”。
我试图提出的观点(我相信你可能没有意识到)是在这三行代码中可能有四个不同的对象(即“内存中的项目”)需要考虑。其中两个是名为 cursor 和 begin 的指针对象(整数),另外两个是自由存储对象(节点),它们没有名称,但可以使用地址访问指针对象存储的值。
你可能会发现有很多链接值得一读:
答案 2 :(得分:1)
指针cursor
和begin
指向相同的内存位置,因为您明确这样说:Node* cursor = begin;
字面上表示“创建一个名为{{的指针变量” 1}}指向与cursor
相同的位置。“所以毫不奇怪。
修改:根据错误的猜测删除了建议,并将其更改为更适用的建议
从评论中,我现在明白你想在某个位置插入一个节点,以便字段begin
在结果列表中增加,假设它最初在增加(如果它仍然不对,请清楚说明你做想要的东西。)
对于这种情况,ap_nr
的初始化当然是正确的。但是, 正确无法将对象cursor
指向:您希望在该节点之前插入新节点。但为此你必须做出一些改变:
首先,您需要另一个指针变量,该变量包含指向新创建节点的指针,如
cursor
然后你必须将那个节点插入到列表中。也就是说,代替Node* new_node = new Node;
等,你必须使用cursor->ap_nr=ap_nr;
等。此外,它后面的节点当然不列表的第一个节点(指向new_node->ap_nr=ap_nr;
)但你找到的那个(由first
指出)。
但是,现在您遇到了一个问题:您必须将新节点插入到列表中,这意味着您必须修改上一个节点的current
指针(但要点不是next
,而是新创建的节点!)。但是你没有更多指向前一个节点的指针,因为你的列表是单链接的,也就是说,你没有从找到的元素到前一个元素的指针。但要插入元素,您有来更改begin
。
但 所拥有的是指向 next 节点的指针。因此,更好的策略是让您的next
指向之前的节点,然后始终使用cursor
代替cursor->next
(移动{{1}时除外}, 当然)。这样你可以在之后设置cursor
,写下cursor
您的代码中缺少的其他内容是new_node->next
不为空的检查(它将在列表的末尾)和其他代码实际移动cursor->next = new_node;
向前(属于内部current
的{{1}}部分。
实际上我现在注意到您的块没有关闭,因此您的实际代码中可能会有前进的代码。
最后,提出一些一般建议:如果模块化函数代码,那么编写代码可能会更容易:有一个函数在给定函数之后插入一个新节点(只更改{{1}指针,并返回一个指向新插入的代码的指针),有另一个函数来查找应该插入新节点的节点,并让你的函数cursor
只调用其他的功能。这样,在每个函数中,您可以专注于其中一个子问题。