【问题标题】:Can anyone see why this program generates a segmentation fault谁能明白为什么这个程序会产生分段错误
【发布时间】:2015-07-23 12:50:48
【问题描述】:

我正在编写一个程序来使用单链表实现地图。在编写并包含此插入方法后,程序会生成分段错误,但我不确定这是从哪里来的。

int map_insert(Map *theMap, char *theKey, void *theItem){

   node *newNode = malloc(sizeof(node));

   node *cursor = theMap->root;

   while(cursor->next !=  NULL){
      cursor = cursor->next;
    }

    newNode->key = theKey;
    newNode->item = theItem;
    newNode->next = NULL;


    cursor->next = newNode;

    return (node *)newNode;
}

【问题讨论】:

  • 你将什么作为参数传递给map_insert?使用调试器,您能否确定在哪一行执行期间发生了段错误?
  • 除了作为int返回的指针(这可能是segfault的原因):你确定theMap被正确传递(即:它是一个有效的指针),并且是theMap->root 有效(如果是 NULLcursor->next 取消引用 NULL 指针)并检查 malloc 的返回值,它可以返回 NULL。无论哪种方式,使用 -g 标志 (gcc) 编译,并逐步执行代码 (gdb)

标签: c segmentation-fault


【解决方案1】:

node *cursor = theMap->root;

我假设如果地图为空,root 将为 NULL。

while(cursor->next != NULL)

如果 rootNULLcursor 也是 NULL,并且您在访问 next 字段时取消引用它。

也许将 while 条件更改为:

while (cursor && cursor->next)?


编辑:这是一个完整的功能:

node * map_insert(Map *theMap, char *theKey, void *theItem){

    node *newNode = malloc(sizeof(node));

    newNode->key = theKey;
    newNode->item = theItem;
    newNode->next = NULL;

    node *cursor = theMap->root;

    if (cursor) {
       while(cursor->next !=  NULL){
          cursor = cursor->next;
        }
        cursor->next = newNode;
    }
    else
    {
        theMap->root = newNode;
    }

    return newNode;
}

【讨论】:

  • 这可能是真的,但是你怎么知道 root 不是哨兵对象呢?可能失败的 malloc 也会返回 null。
  • 嗯,没错。并且在对原始问题的评论中建议检查 malloc 返回值,但是..与其他常见错误相比,由于 malloc 失败而遇到错误的频率是多少?你上一次 malloc 失败是什么时候?
  • 关于哨兵对象,如果是这种情况,代码的结构可能会有所不同。此外,我很难相信有人会实现哨兵对象,并且没有指向列表尾部的指针。
  • int map_insert(Map *theMap, char *theKey, void *theItem){ node *newNode = malloc(sizeof(node));节点 *cursor = theMap->root; // map 为空,root 为 NULL if(cursor == NULL){ cursor->key = theKey;光标->项目=项目;光标->下一个 = NULL; } else{ while(cursor->next != NULL){ cursor = cursor->next; } newNode->key = theKey; newNode->item = theItem;新节点->下一个 = NULL;光标->下一个=新节点;如果(新节点!= NULL)返回1;返回0; }
  • 这保证了一个段错误:) 您正在检查游标是否为 NULL,如果它是,您正在取消引用它。如果地图是空的,你只需要做theMap->root = newNode;
【解决方案2】:

函数map_insert的签名是

int map_insert(Map *theMap, char *theKey, void *theItem)

如您所见,它旨在返回int。但是你返回一个node*。通过将其更改为来解决问题:

node* map_insert(Map *theMap, char *theKey, void *theItem){


这里的演员表:
return (node *)newNode;

不是必需的,因为 newNode 已经是 node* 类型。

【讨论】:

  • 这必须至少是一个编译时警告。但在 32 位系统上,它可能最终会工作。我认为这不是段错误的来源,而是@ 987654329@ cursor 可能为 NULL。
猜你喜欢
  • 2011-01-27
  • 2017-10-14
  • 2011-03-04
  • 2013-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多