【问题标题】:Adding to the front of a Simple Linked List添加到简单链表的前面
【发布时间】:2016-03-26 05:02:14
【问题描述】:

我正在尝试实现一个链表,并从 addToFront 函数开始。 这里我只是将数字 5 添加到列表的前面。我知道如果列表为空,则列表指针应该为 Null,但是,情况似乎并非如此。

编辑文件: 我已经编辑了文件(感谢 taskinoor 的回答),现在提供了

的输出
0 5

代替

5

我有头文件:

#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>

typedef struct List {
    struct list * next;
    int value;
    int size;
}list;

void addToFront(int num, list **l);

void printList(list * l);

int getSize(list * l);

void initialize(list * l);

void freeList(list *l);

一个c文件“main.c”

#include "Header.h"

int main() {

    list l;

    initialize(&l);

    addToFront(5, &l);
    printList(&l);


    _getch();
    freeList(&l);
    return 0;
}

void printList(list * l) {
    list *current = l;
    while (current != NULL) {
        printf("%d ", current->value);
        current = current->next;
    }
}

void freeList(list *l) {
    list *current = l;
    while (current != NULL) {
        list *tmp = current;
        current = current->next;
        free(tmp);
    }
}

还有一个接口c文件(不完整)

#include "Header.h"

int getSize(list * l) {
    return l->size;
}

void initialize(list * l) {
    l->next = NULL;
    l->value = 0;
    l->size = 0;
}

// need to pass **l to update it
void addToFront(int num, list **l) {
    // allocate memory for new node
    list *tmp = (list *)malloc(sizeof(list));

    tmp->value = num;

    // new node should point to whatever head is currently pointing
    // even if head is NULL at beginning
    tmp->next = *l;

    // finally l needs to point to new node
    // thus new node becomes the first node
    *l = tmp;
}

但是,当调用 addToFront 函数时,永远不会执行 if 语句。哪个没有意义,如果列表为空,列表指针不应该为空吗?

接下来我尝试在Initialize function 中手动设置l == NULL,但这也没有任何作用。此外,我的打印函数无限循环,我认为这是 malloc 的问题。任何帮助将不胜感激。

【问题讨论】:

  • 如果if (l == NULL) 那么你不能l-&gt;value= ...一样取消引用它!!
  • 嗯,但是我将如何设置要插入的新节点的值(恰好是列表中的第一个节点)。尽管如此,更大的问题是为什么 if 语句没有执行。
  • ...和“手动set l == NULL”也不起作用,因为== 是比较运算符,而不是赋值运算符。也许你想检查l-&gt;next == NULL
  • 但是'l->next'不是列表中的第二个节点,而不是第一个节点吗?
  • if 语句可能已执行,但 l 不是 NULL,因为您已在 main 中为其分配了内存。 l-&gt;next 虽然是 NULL

标签: c++ c algorithm data-structures linked-list


【解决方案1】:

条件if (l == NULL)addToFront 中不成立,因为l 在此处不为空。您在main 的开头调用了l = malloc(sizeof(list));,这使得l 不为NULL。这样就不用malloc和初始化l了。我想l 是指指向列表的头指针。这应该在开始时为 NULL(即不要在 main 调用 malloc 并将返回的地址分配给 l)并且您的节点内存应该在 addToFront 中分配,如下所示:

// need to pass **l to update it
void addToFront(int num, list **l) {
    // allocate memory for new node
    list *tmp = (list *) malloc(sizeof(list));

    tmp->value = num;

    // new node should point to whatever head is currently pointing
    // even if head is NULL at beginning
    tmp->next = *l;

    // finally l needs to point to new node
    // thus new node becomes the first node
    *l = tmp;
}

main 中删除malloc

int main() {
    list *l;
    addToFront(5, &l);  // pass address of l
    printList(l);

    // other stuffs
}

打印会是这样的:

void printList(list * l) {
    list *current = l;
    while (current != NULL) {
        printf("%d ", current->value);
        current = current->next;
    }
}

最后,仅释放l 是不够的。您需要遍历整个列表并释放其中的每个节点。

void freeList(list *l) {
    list *current = l;
    while (current != NULL) {
        list *tmp = current;
        current = current->next;
        free(tmp);
    }
}

【讨论】:

  • 这当然消除了无限循环,但似乎仍然只打印零,而不是 5。同样使用 list *l 在 Visual Studio 中引发另一个异常,而使用 list l 有效(结果为零输出)。此时感觉问题出在 Visual Studio 上,而不是程序本身。
  • @TTEd,你也修复了打印功能吗?请仔细阅读我的代码并尝试了解 cmets。您的代码中有许多地方需要修复。
  • 是的,我修复了它,就像你展示的那样,除了 list * l 抛出异常,所以我不得不使用 list l
  • 我编辑了我的addToFronttmp-&gt;next = l; 应该是 tmp-&gt;next = *l;l 之前的那个 * 不见了。
  • 好的,现在打印 0 5。哪一半有效,因为它应该只打印 5,它是唯一的第一个元素?对于这样一个简单的链表,我使用指向指针的指针似乎很荒谬,不知道发生了什么。
【解决方案2】:

好的,让我们从最后一部分开始:

我尝试在 Initialize 函数中手动设置 l == NULL,但这也没有做任何事情

实际上它做了一些事情,但是一旦你从初始化函数返回,那个改变就丢失了。原因如下:

当你说initialize(l)时,在initialize函数体中你会得到一个原始指针l的副本。然后你把那个指针指向NULL。当该函数返回原始指针 l 时,仍然指向初始内存(使用 malloc 分配的内存)。如果您确实希望此初始化函数具有此类行为,则应将其更改为:

initalize(list **l)

关于 addToFront() 函数,实际上如果它被执行,你会得到一个段错误!你检查:

if (l == null)

如果是,则尝试取消对 NULL 指针的引用!

l->value = num;
l->next = NULL;
l->size++;

最后,在您的打印功能中,您不会前进指针。你应该写类似

l=l->next

为了工作

【讨论】:

  • initalize(list **l) 是错误的和/或没有必要的。 l 是一个指针。 Initialize 仅将成员设置为零。
  • 没必要我同意。为什么错了?我说如果你想要这样的行为(修改函数内的列表指针)就这样做。 @PaulOgilvie 您建议的更改函数内指针的方法是什么?
  • 重点是OP写的initialize不会修改指针。因此不需要**。
  • 您在我的回答开头看到问题的引用了吗?那就是说他试图做到这一点——改变初始化函数中的 l 指针。但我想你已经看到了,你只需要评论/投反对票。我明白了
  • 他只是试图通过插入一些语句来修复一个错误,并在这样做时制造了更多错误。
【解决方案3】:

这是因为您的打印功能。 您只打印在它们之后具有下一个节点的值。因此只有 1 个值不会打印任何内容。相反,你应该有:

void printList(list * l) {

    while (l !=NULL)
    {
    printf("%d ", l->value);
    l=l->next;
    }

}

同样在你的addToFront 函数中,你有一个逻辑错误,如果传入的列表实际上是NULL,你只是在设置数据和大小,事实并非如此。

【讨论】:

  • 这似乎引发了一个奇怪的异常,“0xCDCDCDCD.”。此外,我目前只向列表中添加一个元素(仅调用 addToFront 一次),这意味着在这种情况下列表为 Null(因为我只调用一次)。
  • 只有在你没有为它分配内存的情况下,这个列表才会为 NULL,你在 main 函数中这样做了
  • 0xCDCDCDCD 表示 Visual Studio 中未初始化的堆内存:stackoverflow.com/a/127404/487892
【解决方案4】:

用途:

void addToFront(int num, list **l) {
    list *tmp= malloc(sizeof(list));
    tmp->value = num;
    tmp->next = *l;
    *l= tmp;
}

注意:不需要initialize。只需传递一个空或非空列表,main 就可以这样做:

int main()
{
    list * l= NULL;
    addToFront(5, &l);
...

查看ForeverStudent他修复打印错误的解决方案。

【讨论】:

  • 那是错误的。 addToFront 接受指针,而不是指向指针的指针,当给定函数的签名时,您建议了另一种行为
  • addToFront 的正确解决方案,但更正 size 字段会很麻烦
  • @sestus,它不再因为前面被改变了。
  • @ForeverStudent,size字段一般不需要或者应该在列表之外维护。
  • @PaulOgilvie 100% 同意,但无论如何他都有这个领域。如果他将列表和节点结构分开会更好
猜你喜欢
  • 2011-06-20
  • 2015-06-01
  • 1970-01-01
  • 2016-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-16
  • 1970-01-01
相关资源
最近更新 更多