c - 使用 malloc 时出现段错误

标签 c segmentation-fault

作为练习,我正在尝试在二叉搜索树上工作!

我已经创建了代码并且它似乎可以运行,但是当我尝试添加客户时它崩溃了。调试代码后,我在第 82 行遇到段错误,我尝试将内存分配给根...研究了一段时间,我发现它与内存有关,但无法弄清楚我的代码发生了什么...关于尝试分配内存时导致此失败的原因有什么建议吗?

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

#define MAX_STRING 50

void flush();

struct customer {
    char *name;
    char *address;
    char *email;
};

struct double_linked_list {
    struct customer *data;
    struct double_linked_list *previous;
    struct double_linked_list *next;
};

struct double_linked_list *customers_head = 0;

struct BST_node {
    struct double_linked_list *data;
    struct BST_node *left;
    struct BST_node *right;
};

struct BST_node *BST_email_root = 0;

struct BST_node *BST_find_customer(struct BST_node *root, char *email) {
    if (root == NULL)
        return NULL;
    if (strcmp(email, root->data->data->email) == 0)
        return root;
    else {
        if (strcmp(email, root->data->data->email) == -1)
            return BST_find_customer(root->left, email);
        else
            return BST_find_customer(root->right, email);
    }
}

void find_customer() {
    char email[MAX_STRING];
    struct double_linked_list *l;
    struct BST_node *b;

    printf("Give the email of the customer (up to %d characters) : ", MAX_STRING - 1);
    gets(email);

    b = BST_find_customer(BST_email_root, email);
    if (b == 0)
        printf("There is no customer with this email.\n");
    else {
        l = b->data;
        printf("Customer found! \n");
        printf("Name    : %s\n", l->data->name);
        printf("Address : %s\n", l->data->address);
        printf("Email   : %s\n", l->data->email);
    }
}

struct BST_node *new_BST_node(struct BST_node *root, struct double_linked_list *l) {
    if (root == NULL);
    {
        root = (struct BST_node *)malloc(sizeof(struct BST_node));
        if (root == NULL) {
            printf("Out of Memory!");
            exit(1);
        }
        root->data = l;
        root->left = NULL;
        root->right = NULL;
    }

    if (strcmp(l->data->email, root->data->data->email) == -1)
        root->left = new_BST_node(root->left, l);
    else 
        root->right = new_BST_node(root->right, l);
    return root;
};

struct double_linked_list *new_customer() {
    char name[MAX_STRING], address[MAX_STRING], email[MAX_STRING];
    struct BST_node *b;
    struct double_linked_list *l;
    struct customer *c;

    printf("\nADDING NEW CUSTOMER\n=\n\n");
    printf("Give name (up to %d characters): ", MAX_STRING - 1);
    gets(name);

    printf("Give address (up to %d characters): ", MAX_STRING - 1);
    gets(address);

    printf("Give email (up to %d characters): ", MAX_STRING - 1);
    gets(email);

    b = BST_find_customer(BST_email_root, email);
    if (b) {
        printf("Duplicate email. Customer aborted.\n");
        return 0;
    }

    c = (struct customer *)malloc(sizeof(struct customer));
    if (c == 0) {
        printf("Not enough memory.\n");
        return 0;
    }

    c->name = strdup(name); // check for memory allocation problem
    if (c->name == 0)
        return 0;
    c->address = strdup(address);   // check for memory allocation problem
    if (c->address == 0)
        return 0;
    c->email = strdup(email);   // check for memory allocation problem
    if (c->email == 0)
        return 0;

    l = (struct double_linked_list*)malloc(sizeof(struct double_linked_list));
    if (l == 0) {
        printf("Not enough memory.\n");
        free(c->name);
        free(c->address);
        free(c->email);
        free(c);
        return 0;
    }

    l->data = c;
    l->previous = 0;
    l->next = customers_head;

    if (customers_head)
        customers_head->previous = l;

    customers_head = l;

    BST_email_root = new_BST_node(BST_email_root, l);

    return l;
}

void displaymenu() {
    printf("\n\n");
    printf("1. New customer\n");
    printf("2. Find customer using email\n");
    printf("0. Exit\n\n");
    printf("Give a choice (0-6) : ");
}

void flush() {
    char ch;
    while ((ch = getchar()) != '\n' && ch != EOF);
}

int main() {
    int choice;
    do {
        displaymenu();
        scanf("%d", &choice);
        flush();
        switch (choice) {
          case 1:
            new_customer();
            break;
          case 2:
            find_customer();
            break;
        }
    } while (choice != 0);

    return 0;
}

Codeblocks 调试器提供以下信息

事件调试器配置:GDB/CDB 调试器:默认

构建以确保源是最新的

选择目标:

调试 添加源目录:C:\debug\

添加源目录:C:\debug\

添加文件:C:\debug\bin\Debug\debug.exe

将目录更改为:C:/debug/。

设置变量:PATH=.;C:\Program Files\CodeBlocks\MinGW\bin;C:\Program Files\CodeBlocks\MinGW;C:\Windows\System32;C:\Windows;C:\Windows\System32\wbem;C:\Windows\System32\WindowsPowerShell\v1.0;C:\Program Files\ATI Technologies\ATI.ACE\Core-Static;C:\Users\baskon\AppData\Local\Microsoft\WindowsApps

启动调试器:C:\Program Files\CodeBlocks\MINGW\bin\gdb.exe -nx -fullname -quiet -args C:/debug/bin/Debug/debug.exe

完成

注册新类型:wxString

注册新类型:STL String

注册新类型:STL Vector

设置断点

调试器名称和版本:GNU gdb (GDB) 7.6.1

子进程PID:5908

程序接收到信号 SIGSEGV,段错误。

在?? () ()

9 0x00401480 in new_BST_node (root=0x0, l=0xbe0ec8) 在 C:\debug\main.c:82 C:\debug\main.c:82:1907:beg:0x401480

在 C:\debug\main.c:82

9 0x00401480 in new_BST_node (root=0x0, l=0xbe0ec8) 在 C:\debug\main.c:82 C:\debug\main.c:82:1907:beg:0x401480

调用栈如下

enter image description here

最佳答案

您的代码中存在多个问题:

  • 这里有一个典型的错误:

    struct BST_node *new_BST_node(struct BST_node *root, struct double_linked_list *l) {
    if (root == NULL);
    {
        root = (struct BST_node *)malloc(sizeof(struct BST_node));
    

    ;if 的末尾语句行被解析为空语句。后续 block ,由 { 引入将始终执行。

    您可以通过始终对复合语句使用大括号并将它们放在与语句开头相同的行而不是下一行来避免这种愚蠢的错误。这与 40 多年前 C 语言的创造者使用的原始 K&R 风格很接近。

  • 变量类型 ch在函数中 flush应该是 int允许正确区分 getc() 返回的所有值: unsigned char 的所有值加上特殊值 EOF :

     void flush(void) {
        int ch;
        while ((ch = getchar()) != EOF && ch != '\n') {
            continue;
        }
    }
    

    请注意,您应该像我上面所做的那样使空语句更加明确,以避免像上一个那样的混淆和错误。

  • 你不应该使用过时的不安全函数 gets() : 使用 fgets()并用 strcspn() 去掉尾随的换行符.

  • 将字符串与 strcmp() 进行比较时,你应该只依赖于返回值的符号。在函数中 BST_find_customer()new_BST_node() , 你比较 -1 : 这个不靠谱。使用 if (strcmp(email, root->data->data->email) < 0)相反。

  • 在函数中 new_BST_node() ,你不回root当您在树中创建一个新节点时。这是更正后的版本:

    struct BST_node *new_BST_node(struct BST_node *root, struct double_linked_list *l) {
        if (root == NULL) {
            root = malloc(sizeof(*root));
            if (root == NULL) {
                printf("Out of Memory!");
                exit(1);
            }
            root->data = l;
            root->left = NULL;
            root->right = NULL;
            return root;
        }
    
        if (strcmp(l->data->email, root->data->data->email) < 0) {
            root->left = new_BST_node(root->left, l);
        } else {
            root->right = new_BST_node(root->right, l);
        }
        return root;
    }
    

    请注意,这会导致您的错误,因为您可能在此处进行了无限递归。

  • 最后是几点建议:

    • 使用NULL而不是 0将指针与空指针进行比较时。它更具可读性。
    • 避免命名变量 l因为这个名称在图形上太接近 1使用编程环境中使用的固定间距字体。有时几乎无法区分。

关于c - 使用 malloc 时出现段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41780524/

相关文章:

mysql - mysql_stmt_close 时出现段错误

c++ - 结构与对象属性和 C++ 中的 std::vector 的交互

c - Xlib:如何检查窗口是否最小化?

c - 构建静态库并在编译时将其链接到内核模块

c - 深奥的 C 指定初始化程序失败,编译器错误或功能?

c++ - 测试从 qt4 迁移到 qt5 的库时出现段错误

c - Fedora 中的 GCC math.h 与 Ubuntu 的比较

c - 指针和内存池 : Simple Test Program

有人可以向我解释为什么这段代码会给我一个段错误吗?

c - 使用 mmap 将文件读取为字符串