c - 为什么这段 C 代码会在 macOS 上生成段错误,而在其他系统上不会?

标签 c macos data-structures segmentation-fault doubly-linked-list

在尝试用 C 语言实现双向链表时,我注意到以下代码片段会在 macOS 10.11 El Capitan 上引发段错误。然而,当在 Linux 或 Haiku 中测试时,它会运行得很愉快,并产生预期的结果。

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

typedef struct node_structure {
    int data;
    struct node_structure *prev;
    struct node_structure *next;
} *node;

node createNode(int value) {
    node newNode = (node) malloc(sizeof(node));
    if (newNode != NULL) {
        newNode->data = value;
        newNode->prev = NULL;
        newNode->next = NULL;
    }
    return newNode;
}

void displayLinkedList(node linked_list) {
    node cursor = linked_list;
    while (cursor != NULL) {
        printf("DATA: %d \tTHIS:%p \tPREV:%p \tNEXT:%p\n", cursor->data, (void*)cursor, (void *)cursor->prev, (void *)cursor->next);
        cursor=cursor->next;
    }
}

int insertAtHead(node *head, int value) {
    node newHead = createNode(value);
    if(newHead != NULL) {
        (*head)->prev = newHead;
        newHead->next = *head;
        *head = newHead;
        return 0;
    }
    else return 1;
}

int main() {
    printf("\nCreating a single element linked list.\n");
    node head = createNode(10);
    displayLinkedList(head);

    printf("\nInserting 10 elements at head.\n");
    for(int i = 0; i < 10; i++) { 
        insertAtHead(&head, 8); 
    }
    displayLinkedList(head);
    return 0;
}

这是控制台输出:

$ gcc --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 8.0.0 (clang-800.0.42.1)
Target: x86_64-apple-darwin15.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

$ gcc -Wall -pedantic 04_doubly_linked_lists__debugging.c

$ ./a.out

Creating a single element linked list.
DATA: 10        THIS:0x7fd19a403390     PREV:0x0        NEXT:0x0

Inserting 10 elements at head.
DATA: 8         THIS:0x7fd19a403430     PREV:0x0        NEXT:0x7fd19a403420
DATA: 8         THIS:0x7fd19a403420     PREV:0x7fd19a403430     NEXT:0x7fd100000008
Segmentation fault: 11

如您所见,在崩溃前的最后一次迭代中,next 指针似乎被结构的 data 字段中的值覆盖(在此示例中,值为 8 的整数)。

特别奇怪的是,相同的代码在其他操作系统中运行时没有任何问题,完成了 10 个元素的插入循环,并在屏幕上正确显示了所有元素和各自的内存地址。

我是不是做错了什么?

最佳答案

问题是这样的:

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

如果你不想修改其他任何东西,你可以用这个更正它:

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

但是,我想在您的代码中解决一些问题。首先,不要强制转换 malloc,因为它完全没有必要,除非您出于某种原因正在使用 C++ 编译器。

其次,将变量而不是类型作为 malloc 的参数要好得多,因为它避免了代码重复。在这种情况下,它也可以解决您的错误。有了这两件事,你可以这样写:

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

第三,绝对没有理由为 node_structurenode 使用不同的名称。改为这样写:

typedef struct node {
    int data;
    struct node *prev;
    struct node *next;
} *node;

第四,当你创建一个库的接口(interface)时,你可以使用 typedefs 来隐藏结构和指针的继承(有些人争论以这种方式隐藏指针)有效性,但不要在实际操作它们的代码中使用它们。您的创建应如下所示:

struct node *createNode(int value) {
    struct node *newNode = malloc(sizeof(*newNode));
    // Same as before in the rest

What makes this especially weird is that the same code runs without any trouble in other operating systems

这并不奇怪。这几乎可以 100% 确定您的代码有未定义的行为

关于c - 为什么这段 C 代码会在 macOS 上生成段错误,而在其他系统上不会?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56997602/

相关文章:

c++ - Clang++ 不理解 mac 终端中的 c++11

javascript - 在 JavaScript 中构建一棵树

c - 初始化结构指针数组的正确方法是什么?

比较两个语音

c - C函数的有趣返回行为

objective-c - 如何在 OS X 桌面上制作全屏叠加层?

c++ - 理解C++中指针的操作

在 C 中创建 Mallocate 数组函数

c - Visual Studio 更改数据类型的字节数

excel - Solver.xlam 丢失?