【问题标题】:Segmentation fault at free()free() 处的分段错误
【发布时间】:2012-04-13 20:53:40
【问题描述】:

当我在以下链表实现的删除函数中执行 free() 时遇到分段错误。请看一下并告诉我哪里出错了。当我用 valgrind 运行这个程序时,没有 seg。故障,运行正常。所以我无法找出问题所在。

typedef struct node {
    char name[100];
    int id;
    struct node* next;
} Node;

void insert(Node** p, char* _name, int _id)
{
    Node *temp, *prev;
    temp = malloc(sizeof(struct node));
    temp->next = NULL;
    strcpy(temp->name,_name);
    temp->id = _id;

    if(*p == NULL) {
            *p = temp;
    }
    else {
            for(prev = *p; prev->next!=NULL; prev=prev->next);
            prev->next=temp;
    }
}

/* Delete entry
  @params p    first element
       _id     ID to delete
*/
void delete_by_id(Node** p, int _id) {
    Node *temp, *prev;
    prev = NULL;
    for(temp = *p; temp!= NULL; prev = temp, temp=temp->next) {
            if(temp->id == _id) {
                printf("Deleting entry with id: %d\n", temp->id);
                if(prev == NULL)
                     *p = temp->next;
                else
                     prev->next= temp->next;
                free(temp);
                return;
            }
    }     
}

这是主程序的部分代码:

Node* p;  
int main() {
      ...
      ...
      buf[rval]=0;
      char* tokens = strtok(buf, "+");
      char* strArray[5]; /* up-to 5 words can be stored */
      int n = 0;
      while (tokens)
      {
        strArray[n] = malloc(strlen(tokens) + 1);
        strcpy(strArray[n++], tokens);
        tokens = strtok(NULL, "+");
      }
      int type = 0;
      if(strcmp(strArray[0], "1") == 0)
            type = 1;
      else
            type = 2;
      char* name = "";  
      if(type == 1) {
            name = strArray[1];
            insert(&p, name, clients[i]);
            display(&p);
      } else {
            name = strArray[1];
            rval = search(&p, name);
            if(rval) { 
                delete_by_id(&p, rval);
                display(&p);
            }
      }

      for (i = 0; i < 5; i++)
      {
        if (strArray[i]) // check for null data 
            free(strArray[i]);
      }
      ...
      ...
}

int search(Node** p, char* _name) {
    Node *temp;
    for (temp = *p; temp!= NULL; temp = temp->next) {
            if (strcmp((char *)temp->name, _name)==0) {
                    printf("Name matched: %s\n", temp->name);
                    return temp->id;
            }
    }
    return 0;
}

Valgrind 抱怨用于 strArray 而不是链表的 malloc 和 free。

【问题讨论】:

  • 值得展示一个简短的(10-20 行)main() 程序,该程序显示您如何使用所示函数分配和释放列表。
  • 你应该使用 strncpy 来避免 node.name 溢出。
  • @Jonathan Leffler 我已经添加了 main() 代码,请看一下。
  • 释放指针时不需要检查NULLfree(NULL); 是定义明确的行为(它什么都不做,free 被定义为忽略 NULL 指针)。
  • 你为什么要 char* name = "";如果(类型 == 1){ 名称 = strArray[1];...?字符 * 名称 = "";创建只读的字符串文字(确切地说是未定义的行为,但主要是硬编码到程序中以不可读的内存块)。

标签: c linked-list segmentation-fault nodes


【解决方案1】:

打印出malloc()返回的地址,并在调用free()之前立即打印出temp的值。确保传递给free() 的内容符合您的预期。如果您以某种方式传递了指向 free() 的指针,而该指针并非来自 malloc(),那么您可能会遇到您所看到的问题。

函数delete_by_id() 也有可能使用了无效指针。 p 参数在检查 NULL 之前被取消引用。我建议在调试器中遍历该函数,并确保所有指针看起来都符合您的预期。

【讨论】:

    【解决方案2】:

    让你的程序转储内核并在 GDB 中分析内核:

    gdb -c yourprog.core yourprog
    

    然后做一个完整的回溯:

    (gdb) bt full
    

    这将向您显示段错误的确切原因以及传递给函数的值。

    (编辑)哦,使用 GCC -g 开关编译您的程序以获得调试信息。

    【讨论】:

      【解决方案3】:

      通过 valgrind 运行您的程序。空闲的段错误通常是由于在分配的内存之外写入(这会覆盖/破坏系统在分配的内存之前/之后放置的包装器)。 Valgrind 通常是找出相关写入发生时间的最简单方法。

      【讨论】:

      • 我使用了 valgrind,但随后程序运行良好。没有段。发生故障并且 valgrind 似乎没有指出任何内存错误。只有当我自己运行程序时才会发生故障。
      • 在这种情况下,我必须同意 Jonathan Leffler 的观点:请告诉我们您如何在代码中调用函数。如果您还没有尝试过,请在使用优化编译时通过 valgrind 运行它。在您进行优化编译之前,内存错误有时不会显示出来。
      • 好的,谢谢 Leo。我已经添加了main()代码,请看一下。
      • @ddd:向我们展示你是如何调用 valgrind 的。对于初学者来说,试试valgrind -v --leak-check=full ./executable 看看你会得到什么。
      • 感谢@dreamlax。我尝试了该命令,这就是我得到的: ==11512== HEAP 摘要:==11512== 退出时使用:0 个块中的 0 个字节 ==11512== 总堆使用量:8 个分配,8 个释放,191分配的字节数 ==11512== ==11512== 所有堆块都被释放 - 没有泄漏是可能的 ==11512== ==11512== 使用 --track-origins=yes 查看未初始化值的来源 == 11512== 错误摘要:21 个上下文中的 109 个错误(抑制:6 个中的 11 个)
      猜你喜欢
      • 2021-12-18
      • 1970-01-01
      • 1970-01-01
      • 2012-11-13
      • 2015-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多