几周前我刚开始学习C ++。所以现在我有这个学校作业问题,要求我实现链接列表而不使用“新”或任何与动态分配内存有关(并且不能使用STL中的任何ADT)。教授说一切都可以在堆栈上完成,但是如何?我从星期五开始就一直在努力,但仍然没有运气。
它说:保持一堆文件名被读取。对堆栈使用以下数据结构:
struct Node {
string fileName;
Node *link;
};
我试图避免使用new,但是当我将列表的头部传递给递归方法调用时,它总是给我“分段错误”或“BUS错误”。关于我如何解决这个问题的任何想法?
答案 0 :(得分:10)
堆和堆栈之间的区别主要是(不仅是,但主要是为了这个问题)分配内存的方式以及如何释放内存。如果要在堆上分配节点,则说new Node
,系统将为您提供内存,跟踪使用哪些块以及哪些块是空闲的,并为您提供释放的方法。一旦你不再需要它就会大块。
但是你也可以在堆栈中的数组中拥有一个节点池。 (自动变量是堆栈变量。)您可以从该池“分配”,跟踪阵列中的哪些节点以及哪些节点是空闲的,并将未使用的节点标记为不再需要它们的免费节点。但是,由于数组的大小在编译时是固定的,这意味着您的列表具有最大长度。
答案 1 :(得分:7)
我创建了一个你可能会觉得很有启发性的小样本。我在堆栈上创建了一个单独链接的元素列表。注意如何反向创建列表以及如何使用递归来“分配”所需的itmes数量。还要注意列表如何作为参数传递给参数。希望这有帮助,祝你好运。
#include <cstdio>
using namespace std;
struct Node {
Node* next_;
int value_;
};
// Creates a linked list of nodes containing raising values.
void intList(Node* prevNode, int restValue) {
if (restValue) {
// A node on the stack, which is linked to list created so far.
Node node;
node.next_ = prevNode;
node.value_ = restValue;
// Create a next node or print this list if rest runs to zero.
intList(&node, rest - 1);
}
else {
// Depest recursion level, whole list is complete.
for (Node* iter = prev; iter; iter = iter->next_)
printf("item %d\n", iter->value_);
}
}
int main() {
intList(NULL, 10);
}
答案 2 :(得分:2)
调用函数后,该函数的堆栈分配是固定的。
分配更多堆栈内存的唯一方法是调用另一个函数。然后可以调用另一个函数。然后可以调用另一个函数。或者也许它们都可以是相同的功能......
每个函数调用都有自己的固定大小的堆栈,但函数调用图本身就是这些堆栈的可变大小堆栈。
答案 3 :(得分:2)
你可能应该和你的教授谈谈并澄清要求,因为根据你的描述,对于一个新的c ++程序员来说,这似乎是一个非常奇怪的任务。要求只在堆栈上实现具有内存的链表是至关重要的。
答案 4 :(得分:1)
想想数组。如果需要,可能不止一个。
答案 5 :(得分:1)
没有太多信息:
递归实现是否需要?进行递归调用时,会得到一个新堆栈。 也许你可以使用迭代方法。
答案 6 :(得分:1)
使用alloca()
而不是malloc()
函数在调用函数的堆栈帧上动态分配内存而不是堆。您不必担心释放内存,因为它会在函数返回时自动释放。
答案 7 :(得分:0)
如果您知道需要存储多少个文件名,可以使用struct Node数组并从中构建列表。
使用迭代一个可能的替代方法是在函数中有一个结构Node对象,并在递归调用中将指针传递给它,在那里你使用指针作为该函数堆栈框架中Node对象的下一个链接。
请注意,在后一种情况下,列表仅在最深的递归时有效,当递归调用返回其调用者时,列表会再次被分解。
答案 8 :(得分:0)
要“在堆栈上创建链接列表”,通常使用像alloca这样的函数来获取更多的堆栈内存。然而,这听起来并不像你被要求做的那样。
听起来你应该在堆栈上保留堆栈,而不是任意链接列表。作为提示,您要执行的操作的一般语法:
void push(struct Node *oldHead, String elem) {
struct Node newHead;
head.fileName = elem;
head.next = oldHead.
struct Node *head = &newHead
// then you need to continue what you're doing in this function, since
// returning will effectively pop the stack.
有一些(非平凡的)技术可以沿着这些方式实现完整的垃圾收集列表,但这超出了你正在做的范围。
答案 9 :(得分:0)
可以使用C ++ address-of operator (&amp;)来检索指向堆栈上对象的指针,而不是使用 new 动态分配内存。 / p>
由于以这种方式生成链表是有问题的,除了作为家庭作业,我不确定这是否是实际需要的。如果没有代码示例,很难确切地说出问题所在。