我正在尝试创建链接列表,我已经开始工作,但我仍然有点困惑。我正在使用以下结构:
typedef struct _MList
{
int dx;
int dy;
struct _MList *next;
} MList_t, *MList_p;
我已经测试过这个结构有意义,而且我有一个打印出列表的功能:
void mListPrint(MList_t *mList)
{
MList_p node = mList;
while (node->next != NULL)
{
printf("[%i,%i] ",node->dx,node->dy);
node = node->next;
}
printf("[%i,%i]\n",node->dx,node->dy);
}
创建第一个节点的函数:
MList_t mListNew(int dx, int dy)
{
MList_t newNode;
newNode.dx = dx;
newNode.dy = dy;
newNode.next = NULL;
return newNode;
}
有了这个工作正常,我想我会尝试创建一个在列表末尾添加节点的函数。我的第一次尝试是这样的:
void mListAdd(int dx, int dy, MList_t *mList)
{
MList_p node = mList;
while (node->next != NULL)
{
node = node->next;
}
MList_t newNode = mListNew(dx,dy);
node->next = &newNode;
}
这看起来不错,直到我添加了多个元素。经过大量调试后发现,在mListAdd中创建的“newNode”的内存地址始终相同。因此,列表最终链接回自身。这是为什么?
我改为使用指向新节点的指针实现mListAdd,如下所示:
void mListAdd(int dx, int dy, MList_t *mList)
{
MList_p node = mList;
while (node->next != NULL)
{
node = node->next;
}
MList_p newNode = malloc(sizeof(MList_t));
*newNode = mListNew(dx,dy);
mListPrint(newNode);
node->next = newNode;
}
这很有效,但我觉得另一种方式也应该有效。还是我错过了一些明显的东西?我正在尝试通过实现我在Java和ML中学到的不同数据结构来学习C进行面试。
我对代码的数量感到抱歉,但我认为最好尽可能彻底地解释我的问题。感谢您提前帮助!
答案 0 :(得分:3)
在mListNew
中你使用的是局部变量:
MList_t newNode;
一旦从函数返回,这将超出范围。所以你在未定义的领域。代码看起来好像只是因为内存管理器不会覆盖该局部变量占用的内存块。
您应该在mListNew
内使用malloc分配新的列表节点,并将指针返回到新节点,如下所示:
MList_p mListNew(int dx, int dy)
{
MList_p newNode = malloc(sizeof(MList_t));
newNode->dx = dx;
newNode->dy = dy;
newNode->next = NULL;
return newNode;
}
答案 1 :(得分:1)
第一个示例在堆栈上分配内存,因此它只能在函数内部使用,因此您不应在链接列表中使用其内存地址,该链接列表可能在函数外部存在。
答案 2 :(得分:0)
抱歉,我确信还有更多,但我没有阅读“和创建第一个节点的功能”
MList_t mListNew(int dx, int dy)
{
MList_t newNode;
newNode.dx = dx;
newNode.dy = dy;
newNode.next = NULL;
return newNode;
}
在堆栈上创建newNode。它的定义是函数mListNew()的本地定义,当返回时它是“未定义的”。
最佳做法是,您需要调用者在调用之前分配(并释放)内存。 E.g,
void mListNew(int dx, int dy, MList_t *newNode)
{
newNode->dx = dx;
newNode->dy = dy;
newNode->next = NULL;
}
我还没看过剩下的......
答案 3 :(得分:-1)
您必须使用malloc()或calloc()明确分配内存。你所做的就是使用只存在于堆栈上的结构,并且在mListAdd返回后不再存在;它恰好还没有被覆盖。