【问题标题】:C Segmentation Fault (core dumped) Linked ListC Segmentation Fault (core dumped) 链表
【发布时间】:2015-12-28 19:04:18
【问题描述】:

我不断收到Segmentation Fault (core dumped) 运行时错误,我不知道为什么。

我的代码:

struct Node
{
    void *next;
    void *val;
};
typedef struct Node* NodePtr;

struct List
{
    NodePtr head;
};
typedef struct List* ListPtr;

ListPtr create()
{
    ListPtr ptr = malloc(sizeof(struct List));

    return ptr;
}

int insert(ListPtr list, void *obj)
{
    NodePtr newObj = malloc(sizeof(struct Node));

    //Cast next as a self referencing Node
    newObj->next = (NodePtr) newObj->next;

    //Point to beginning of list
    NodePtr current = list->head;

    if(list->head == NULL)
    {
        newObj->val = obj;
        list->head->next = newObj;
        newObj->next = NULL;

        return 1;
    }

    return 0;
}

int main(int argc, char *argv[])
{
    int x = 2;
    int *p = &x;

    ListPtr thing = create();

    insert(thing, p);

    return 0;
}

错误在这里:list->head->next = newObj 经过一些调试。我以为我必须为 list->head->next 分配内存,但是当我为此添加代码时,它仍然给了我同样的错误。我是投错了还是没有正确分配内存?任何帮助将不胜感激,谢谢!

【问题讨论】:

  • list->head->next = newObj; if(list->head == NULL) ==> NULL->next = newObj;list->head 也没有初始化。
  • 专业提示:在 C 的第一年,不要使用 typedef。它只会让你感到困惑。
  • 谢谢,我忘了初始化磁头。添加了它,但仍然没有运气。我还必须使用 typedef,赋值中有 typedef。我发布的代码不是其中的一部分,但它是相似的。
  • 在结构节点定义中:void *next; 是不好的做法,它会抑制类型检查,从而抑制强类型。 (例如,您可以这样做 struct Node *p= malloc(sizeof *p) ; p->next = "Hello, world\n"; ,编译器不会发出任何警告或错误。
  • 你永远不会初始化列表头。在您尝试访问它之前,您需要这样做。

标签: c memory segmentation-fault void-pointers coredump


【解决方案1】:

把它放在一起,运行良好。

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


struct Node {
        void *next;
        void *val;
};
typedef struct Node* NodePtr;

struct List {
    NodePtr head;
};
typedef struct List* ListPtr;

ListPtr CreateList() {
    ListPtr ptr = malloc(sizeof(struct List));
    return ptr;
}

void Insert(ListPtr list, void *obj) {
        // create and initialize new node
    NodePtr newObj = malloc(sizeof(struct Node));
    newObj->val = obj;
    newObj->next = NULL;

    //Point to beginning of list
    NodePtr curr = list->head;
    // Add node to the list
    if(curr == NULL) // if no head node, make newObj the head node
    {
        list->head = newObj;
    }
    else{ // otherwise traverse the list until you find the last node (the one that points to a null as the next)
        while(1) {
                if(curr->next != NULL) {
                        curr = curr -> next;
                } else {
                        curr->next = newObj;
                }
                list->head = newObj;
                newObj->val = obj;
                list->head->next = newObj;
                newObj->next = NULL;
        }
    }
}
int main() {
    int x = 2;
    int *p = &x;

    ListPtr thing = CreateList();

    Insert(thing, p);

    return 0;
}

【讨论】:

  • 谢谢,这很有效,我终于也理解了其他人。
【解决方案2】:

您检查list-&gt;head 是否为NULL,然后对其进行一些操作。将其更改为if(list->head != NULL) { ... }

【讨论】:

    【解决方案3】:

    想一想,malloc 并不能保证分配的内存是空的。最好在分配后将所有值设置在重要的位置。 list->head 可能不为空

    还有:newObj->next = (NodePtr) newObj->next; 没有设置为合理值,它设置为设置的任何内存 - 您是否打算 newObj->next = (NodePtr) newObj; ?

    如果为 null,则不应引用

    list->head。 list->head->next 只有在不为 null 时才有效。

    如果你真的想建立一个列表,

    newObj->val = obj;
    if (list->head == NULL) { newObj->next = list->head; }
    list->head = newObj;
    

    或者沿着 list->head->next 链向下移动,直到 next 为 null,并将其设置为 newObj->next。如果那样的话,那可能是个好主意,newObj->next 应该设置为 NULL 而不是它自己。

    可能想弄清楚您的列表将如何表现 - 它是循环的吗?它是从头部 (list->head) 还是尾部 (last ->next) 增长的?当 listObject->next == NULL 或 listObject->next == listObject 时,你发现尾巴了吗?

    【讨论】:

    • 你是说我应该在mallo()之后使用memset()吗?在 Java 中,当你创建一个单链表时,你有一个自引用节点。例如,public class Node { Node link; int value; }。这就是我做newObj-&gt;next = (NodePtr) newObj-&gt;next 的原因。我希望 next 像在 Java 中一样具有自我参照性。你也是对的,我试图做 list->head->next == NULL。我如何让它像在 Java 中一样自引用?
    • memset 有效。在大多数平台上 NULL=0。 (这也是一个问题,但通常不是非常重要)。自引用是 newObj->next = newObj;但是为什么要自引用呢?这是否意味着 (listIter=list->head; listiter!=listiter->next; listiter = listiter->next) 是你想要的迭代风格? (其中 listiter 是一个 NodePtr)
    • 为了自我参考,我的意思是我希望 void *next 成为 NodePtr next。但是,我不能在 Node 结构中写它,所以我试着在外面做。
    • @Maru :有三种方法可以避免这种情况:1)struct Node *next; 2)不完整类型上的 typedef 0)不要使用 typedef(见我的第一条评论)
    • typedef struct Node* NodePtr; struct Node { NodePtr next; void *val; }; 应该可以工作 - 根据@wildplasser,这将是(2)在不完整类型上的 typedef
    【解决方案4】:

    我意识到这个答案主要是风格。但我确实认为(坏)风格和(坏)习惯是(坏)编程的(重要)部分。总结一下……


    • (在大多数情况下)不需要 typedef;他们只是为已经存在的东西引入别名。
    • [七规则] 人类读者可以跟踪的标识符(“名称”)数量有限。这可能是 7。减少不同单词的数量使阅读更容易。
    • 另外,读者必须记住 xPtr 和 xNode 是相关的 (typeof *xPtr === typeof xNode)
    • 在阅读源代码时,关键字和特殊字符标记(如运算符)不作为标识符,因为您不必记住它们。 (语法高亮也有帮助)
    • 如果你的程序只有一种表达方式,就不可能出现像iPtr *p; p = (qPtr) malloc (sizeof xNode);这样的错误
    • 再创建一个结构体(为它加上typedefs),仅仅为了容纳一个root 指针会更加破坏你的心理命名空间。

    现在对(预期的)代码进行了修改:

    #include <stdio.h>
    #include <stdlib.h>
    
    struct node {
        struct node *next;
        void *payload;
        };
    
    struct node *root=NULL;
    
    void initialize() { /* nothing .... */ }
    
    int insert(struct node **pp, void *pv) {
       struct node *p;
    
       p = malloc(sizeof *p);
       if (!p) { /* handle error */ return -1; }
    
       p->payload = pv;
       p->next = *pp;
       *pp = p;
       return 1; /* inserted one element */
     }
    
    int main(void)
    {
    int i;
    
    i=666;
    
     /* note: this function call will pass a pointer to a local variable `i`
     ** to the insert() function, which will remember it.
     ** This is generally a bad idea, to say the least.
     */
    insert( &root, &i);
    
    return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-11
      • 1970-01-01
      • 2022-11-22
      • 2019-04-04
      • 1970-01-01
      相关资源
      最近更新 更多