You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言文件与链表操作:调用openBook后addContact崩溃求助

问题分析与修复方案

看起来你遇到的崩溃问题根源在于内存分配的错误,而且这个错误的触发和堆内存的布局变化有关——单独调用addContact()时,堆的初始布局可能刚好没让越界访问立刻崩溃,但打开文件(哪怕只是打开再关闭)会改变堆的状态,导致越界操作直接触发程序崩溃。

核心错误:错误的内存分配大小

在addContact()函数里,你写了:

ite->next = (NODE*)malloc(sizeof(NODE*));
// 还有这行
head = (NODE*)malloc(sizeof(NODE*));

这里的问题是sizeof(NODE*)获取的是指针类型的大小(通常是4或8字节,取决于系统),但你需要分配的是整个NODE结构体的内存空间。结构体NODE包含多个字符数组,大小远大于指针,这样分配的内存严重不足,当你用scanf往里面写入数据时,会直接越界写入,破坏堆的完整性,导致后续操作崩溃。

正确的写法应该是分配sizeof(NODE):

ite->next = (NODE*)malloc(sizeof(NODE));
head = (NODE*)malloc(sizeof(NODE));

其他潜在问题修复

除了这个核心错误,你的代码还有几个需要修正的地方,避免后续出现其他问题:

1. feof()的错误使用

在openBook()里,你用!feof(read)作为循环条件,这会导致最后一次读取重复或者读取错误的数据(因为feof是在读取失败后才会置位)。正确的做法应该是把fscanf的返回值作为循环条件:

// 替换原来的读取逻辑
NODE *current = NULL;
int result;
while ((result = fscanf(read, "%s%s%s%s", name, email, ad, phone)) == 4) {
    NODE *new_node = (NODE*)malloc(sizeof(NODE));
    strcpy(new_node->name, name);
    strcpy(new_node->email, email);
    strcpy(new_node->ad, ad);
    strcpy(new_node->phone, phone);
    new_node->next = NULL;
    
    if (head == NULL) {
        head = new_node;
        current = head;
    } else {
        current->next = new_node;
        current = new_node;
    }
}

这样可以确保只有当成功读取4个字段时才创建节点,避免无效数据被加入链表。

2. fflush(stdin)的未定义行为

C标准里,fflush(stdin)是未定义行为,不同编译器处理方式不同。如果你想清除输入缓冲区的换行符,可以用如下方式替代:

// 替换fflush(stdin)
int c;
while ((c = getchar()) != '\n' && c != EOF);

3. 内存泄漏风险

程序结束前没有释放链表的内存,虽然是小问题,但养成好习惯可以避免内存泄漏。可以添加一个freeList()函数:

void freeList() {
    NODE *temp;
    while (head != NULL) {
        temp = head;
        head = head->next;
        free(temp);
    }
}

然后在main()的return 0;前调用freeList();。

修复后的完整代码

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

typedef struct node {
    char name[50];
    char email[50];
    char ad[200];
    char phone[11];
    struct node *next;
} NODE;

NODE *head = NULL;

void openBook() {
    FILE *read = fopen("Book.txt", "r");
    if (read == NULL) {
        printf("Failed to open Book.txt\n");
        return;
    }

    char name[50] = "", email[50] = "", ad[200] = "", phone[11] = "";
    NODE *current = NULL;
    int result;

    while ((result = fscanf(read, "%s%s%s%s", name, email, ad, phone)) == 4) {
        NODE *new_node = (NODE*)malloc(sizeof(NODE));
        if (new_node == NULL) {
            printf("Memory allocation failed\n");
            fclose(read);
            return;
        }
        strcpy(new_node->name, name);
        strcpy(new_node->email, email);
        strcpy(new_node->ad, ad);
        strcpy(new_node->phone, phone);
        new_node->next = NULL;

        if (head == NULL) {
            head = new_node;
            current = head;
        } else {
            current->next = new_node;
            current = new_node;
        }
    }

    fclose(read);
}

void clearInputBuffer() {
    int c;
    while ((c = getchar()) != '\n' && c != EOF);
}

void addContact() {
    NODE *ite = head;
    NODE *new_node = (NODE*)malloc(sizeof(NODE));
    if (new_node == NULL) {
        printf("Memory allocation failed\n");
        return;
    }
    new_node->next = NULL;

    if (head != NULL) {
        while (ite->next != NULL)
            ite = ite->next;
        ite->next = new_node;
    } else {
        head = new_node;
    }
    ite = new_node;

    printf("Enter name (no space): ");
    scanf("%s", ite->name);
    clearInputBuffer();

    printf("Enter email : ");
    scanf("%s", ite->email);
    clearInputBuffer();

    printf("Enter address : ");
    scanf("%s", ite->ad);
    clearInputBuffer();

    printf("Enter phone : ");
    scanf("%s", ite->phone);
    clearInputBuffer();
}

void printList() {
    NODE *iterator = head;
    if (iterator == NULL) {
        printf("Contact list is empty\n");
        return;
    }
    while (iterator != NULL) {
        printf("Name: %s\nEmail: %s\nAddress: %s\nPhone: %s\n\n", 
               iterator->name, iterator->email, iterator->ad, iterator->phone);
        iterator = iterator->next;
    }
}

void freeList() {
    NODE *temp;
    while (head != NULL) {
        temp = head;
        head = head->next;
        free(temp);
    }
}

int main() {
    openBook();
    addContact();
    printList();
    freeList();
    return 0;
}

为什么单独调用addContact()没事?

这是因为堆内存的初始状态下,你分配的过小内存后面可能刚好是未使用的空间,越界写入暂时没有破坏关键的堆结构。但当你打开文件后,fopen和fclose会进行一些堆内存操作,改变了堆的布局,此时越界写入直接覆盖了堆的管理信息,导致程序崩溃。

内容的提问来源于stack exchange,提问作者mohammad mozafari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:10:08