m0_68999546 2024-07-19 13:02 采纳率: 0%
浏览 3

C语言文件读入链表失败

输入文件路径和文件名还是打不开文件
遇到的现象和发生背景:

使用C语言编写学生管理系统(多文件),将文件中的数据保存到链表中实现一系列功能,上传文件时显示文件无法打开。

用代码块功能插入代码:
//work_list.h
#include <stdio.h>
#include <string.h>

typedef struct student {
    int id;            // 学号
    int grade;         // 年级
    char class[10];    // 班级
    char name[20];     // 姓名
    int age;           // 年龄
    char sex[10];      // 性别
    float score;       // 成绩
} Data;

typedef struct node {
    Data data;
    struct node* next;
} Node;

// 创建头节点
int create_head(Node** head, Data data);

// 头插法插入节点
int insert_head(Node** head, Data data);

// 查找节点
Node* find(Node* head, Data finddata);

// 更新节点
int update(Node* head, Data olddata, Data newdata);

// 删除节点
int del(Node** head, Data deldata);

// 按年级对成绩排序
Node* stor_grade(Node* head);

// 按班级对成绩排序
Node* stor_score(Node* head);

//根据班级名过滤链表
Node* filter_by_class(Node* head, const char* class_name);

void free_list(Node* head);

#endif

//work_list.c
#include "work_list.h"

// 创建头节点
int create_head(Node** head, Data data) {
    Node* p = (Node*)malloc(sizeof(Node));
    if (p == NULL) {
        puts("内存分配失败");
        return -1;
    }
    p->data = data;
    p->next = NULL;
    *head = p;
    return 0;
}
// 头插法插入节点
int insert_head(Node** head, Data data) {
    Node* p = (Node*)malloc(sizeof(Node));
    if (p == NULL) {
        puts("内存分配失败");
        return -1;
    }
    p->data = data;
    p->next = *head;
    *head = p;
    return 0;
}
// 查找节点
Node* find(Node* head, Data finddata) {
    Node* current = head;
    while (current != NULL) {
        if (memcmp(&(current->data), &finddata, sizeof(Data)) == 0) {
            return current;
        }
        current = current->next;
    }
    return NULL;
}
// 修改节点
int update(Node* head, Data olddata, Data newdata) {
    Node* current = head;
    while (current != NULL) {
        if (memcmp(&(current->data), &olddata, sizeof(Data)) == 0) {
            current->data = newdata;
            return 0;
        }
        current = current->next;
    }
    puts("找不到数据");
    return -1;
}
// 删除节点
int del(Node** head, Data deldata) {
    if (*head == NULL) {
        puts("链表为空");
        return -1;
    }
    Node* current = *head;
    Node* follow = NULL;
    while (current != NULL) {
        if (memcmp(&(current->data), &deldata, sizeof(Data)) == 0) {
            if (follow == NULL) { // 删除头节点
                *head = current->next;
            } else {
                follow->next = current->next;
            }
            free(current);
            return 0;
        }
        follow = current;
        current = current->next;
    }
    puts("要删除的数据不存在");
    return -1;
}

/*
// 辅助函数:获取链表的中间节点
Node* get_middle(Node* head) {
    if (head == NULL || head->next == NULL) {
        puts("链表为空或只有一个节点");
        return head;
    }
    Node* fast = head->next;  // 快指针
    Node* slow = head;        // 慢指针
    while (fast != NULL && fast->next != NULL) {
        fast = fast->next->next;  // 快指针一次移动两个位置
        slow = slow->next;        // 慢指针一次移动一个位置
    }
    return slow;  // 返回中间节点
}
// 辅助函数:合并两个已排序的链表(按年级排序)
Node* stor_by_grade(Node* left, Node* right) {
    Node dummy;         // 哑节点,不存储实际数据,作为占位符,简化算法逻辑
    Node* tail = &dummy;// 尾指针
    dummy.next = NULL;
    while (left != NULL && right != NULL) {
        if (strcmp(left->data.grade, right->data.grade) < 0 ||
            (strcmp(left->data.grade, right->data.grade) == 0 && left->data.score <= right->data.score)) {
            tail->next = left;
            left = left->next;
        } else {
            tail->next = right;
            right = right->next;
        }
        tail = tail->next;
    }
    if (left != NULL) {
        tail->next = left;
    }
    if (right != NULL) {
        tail->next = right;
    }
    return dummy.next;
}
// 按年级对成绩排序
Node* stor_grade(Node* head) {
    if (head == NULL || head->next == NULL) {
        return head;
    }
    Node* mid = get_middle(head);
    Node* left = head;
    Node* right = mid->next;
    mid->next = NULL;  // 将链表从中间断开
    left = stor_grade(left);
    right = stor_grade(right);
    return stor_by_grade(left, right);
}
// 辅助函数:合并两个已排序的链表(按成绩排序)
Node* stor_by_score(Node* left, Node* right) {
    Node dummy;         // 哑节点,不存储实际数据,作为占位符,简化算法逻辑
    Node* tail = &dummy;// 尾指针
    dummy.next = NULL;
    while (left != NULL && right != NULL) {
        if (left->data.score <= right->data.score) {
            tail->next = left;
            left = left->next;
        } else {
            tail->next = right;
            right = right->next;
        }
        tail = tail->next;
    }
    if (left != NULL) {
        tail->next = left;
    }
    if (right != NULL) {
        tail->next = right;
    }
    return dummy.next;
}
// 按班级对成绩排序
Node* stor_score(Node* head) {
    if (head == NULL || head->next == NULL) {
        return head;
    }
    Node* mid = get_middle(head);
    Node* left = head;
    Node* right = mid->next;
    mid->next = NULL;  // 将链表从中间断开
    left = stor_score(left);
    right = stor_score(right);
    return stor_by_score(left, right);
}
// 辅助函数:根据班级名过滤链表
Node* filter_by_class(Node* head, const char* class_name) {
    Node* filtered_head = NULL;
    Node* filtered_tail = NULL;
    while (head != NULL) {
        if (strcmp(head->data.class, class_name) == 0) {
            Node* new_node = (Node*)malloc(sizeof(Node));
            if (new_node == NULL) {
                perror("分配内存失败");
                exit(EXIT_FAILURE);
            }
            new_node->data = head->data;
            new_node->next = NULL;
            if (filtered_head == NULL) {
                filtered_head = new_node;
                filtered_tail = new_node;
            } else {
                filtered_tail->next = new_node;
                filtered_tail = new_node;
            }
        }
        head = head->next;
    }
    return filtered_head;
}*/
void free_list(Node* head) {
    Node* current = head;
    Node* next;


    while (current != NULL) {
        next = current->next;
        free(current);
        current = next;
    }
}
//work_file.h
#ifndef WORK_FILE_H
#define WORK_FILE_H

#include"work_list.h"

//读取文件
int read_file(Node** head,const char* file_name);

#endif

work_file.c
#include "work_file.h"
#include "work_list.h"
#include <stdio.h>

// 从文件读取数据并插入到链表中
int read_file(Node** head, const char* file_name) {
    FILE *fp = fopen(file_name, "r");
    if (fp == NULL) {
        perror("无法打开文件");  // 打开文件失败时输出错误信息
        return -1;
    }

    Data student;
    // 修正 fscan 的格式字符串以匹配数据结构
    while (fscanf(fp, "%d,%d,%[^,],%[^,],%d,%[^,],%f\n",
                  &student.id,
                  &student.grade,
                  student.class,
                  student.name,
                  &student.age,
                  student.sex,
                  &student.score) == 7) {
        // 将数据插入链表
        if (insert_head(head, student) != 0) {
            puts("插入链表失败");  // 插入链表失败时输出提示
            fclose(fp);  // 确保在返回前关闭文件
            return -1;
        }
    }

    if (ferror(fp)) {
        perror("读取文件时出错");  // 读取文件过程中出错时输出错误信息
        fclose(fp);
        return -1;
    }

    fclose(fp);
    return 0;
}

```c
//work_page.h
#ifndef WORK_PAGE_H
#define WORK_PAGE_H

#include "work_list.h"

// 打印菜单
void print_menu(void);

// 增加学生信息
void increase(Node** head);

// 删除学生信息
void delstu(Node** head);

// 查询学生信息
void search(Node* head);

// 修改学生信息
void updatestu(Node* head);

// 显示所有学生信息
void display_all(Node* head);
/*
// 排序学生信息
void sort(Node** head);

// 按班级过滤学生信息
void filter(Node* head);*/

#endif


//work_page.c
#include <stdio.h>
#include "work_page.h"
#include "work_list.h"

// 打印菜单
void print_menu() {
    printf("\n\n");
    printf("*****************************************************\n");
    printf("*----------------------duoduo------------------------\n");    
    printf("*                 学生信息管理系统                  *\n");
    printf("*****************************************************\n");
    printf("********************系统功能菜单*********************\n");
    printf("----------------------     --------------------------\n");
    printf("*****************************************************\n");
    printf("**    1、增加学生信息   *     2、删除学生信息      **\n");
    printf("*****************************************************\n");
    printf("**    3、查询学生信息   *     4、修改学生信息      **\n");
    printf("*****************************************************\n");
    printf("**    5、学生成绩排名   *     6、查看所有学生      **\n");
    printf("*****************************************************\n");
    printf("**    7、退出系统       *                         **\n");
    printf("*****************************************************\n");
    printf("----------------------     --------------------------\n");
}

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "work_list.h"  // 包含 Node 结构体定义和 insert_head 函数
#include "work_file.h"  // 包含文件操作函数

// 辅助函数:查找学号是否存在
int is_id_exist(Node* head, int id) {
    Node* current = head;
    while (current != NULL) {
        if (current->data.id == id) {
            return 1; // 学号已存在
        }
        current = current->next;
    }
    return 0; // 学号不存在
}

// 增加学生信息
void increase(Node** head) {
    Data Student;
    printf("输入学生信息(学号 年级 班级 姓名 年龄 性别 成绩)用空格隔开:\n");
    if (scanf("%d %d %s %s %d %s %f", &Student.id, &Student.grade, Student.class, Student.name, &Student.age, Student.sex, &Student.score) == 7) {
        // 检查学号是否已存在
        if (is_id_exist(*head, Student.id)) {
            printf("学号 %d 已存在,不能重复添加。\n", Student.id);
            return;
        }
        if (insert_head(head, Student) == 0) {
            printf("学生信息添加成功!\n");

            // 将新学生信息追加到文件中
            FILE *fp = fopen("student.txt", "a");
            if (fp == NULL) {
                perror("无法打开文件");
                return;
            }
            fprintf(fp, "%d,%d,%s,%s,%d,%s,%.2f\n", Student.id, Student.grade, Student.class, Student.name, Student.age, Student.sex, Student.score);
            fclose(fp);
        } else {
            printf("学生信息添加失败。\n");
        }
    } else {
        printf("输入格式错误。\n");
    }
}

// 删除学生信息
void delstu(Node** head) {
    Data Student;
    printf("输入删除学生信息(学号 年级 班级 姓名)用空格隔开:\n");
    if (scanf("%d %d %s %s", &Student.id, &Student.grade, Student.class, Student.name) == 4) {
        if (del(head, Student) == 0) {
            printf("学生信息删除成功!\n");

            // 从文件中删除学生信息
            FILE *fp = fopen("student.txt", "r");
            FILE *temp = fopen("temp.txt", "w");
            if (fp == NULL || temp == NULL) {
                perror("无法打开文件");
                return;
            }

            Data current;
            while (fscanf(fp, "%d,%d,%[^,],%[^,],%d,%[^,],%f\n",
                          &current.id, &current.grade, current.class, current.name, &current.age, current.sex, &current.score) == 7) {
                if (current.id != Student.id) {
                    fprintf(temp, "%d,%d,%s,%s,%d,%s,%f\n", current.id, current.grade, current.class, current.name, current.age, current.sex, current.score);
                }
            }
            fclose(fp);
            fclose(temp);

            remove("student.txt");
            rename("temp.txt", "student.txt");
        } else {
            printf("学生信息删除失败。\n");
        }
    } else {
        printf("输入格式错误。\n");
    }
}


// 查询学生信息
void search(Node* head) {
    Data student;
    printf("输入要查询的学生学号:\n");
    if (scanf("%d", &student.id) == 1) {
        Node* result = find(head, student);
        if (result != NULL) {
            printf("学号=%d, 年级=%d, 班级=%s, 姓名=%s, 年龄=%d, 性别=%s, 成绩=%.2f\n",
                   result->data.id, result->data.grade, result->data.class, result->data.name,
                   result->data.age, result->data.sex, result->data.score);
        } else {
            printf("未找到学号为 %d 的学生信息。\n", student.id);
        }
    } else {
        printf("输入格式错误。\n");
    }
}
// 修改学生信息
void updatestu(Node* head) {
    Data olddata, newdata;
    printf("请输入要修改的学生学号:\n");
    if (scanf("%d", &olddata.id) == 1) {
        Node* result = find(head, olddata);
        if (result != NULL) {
            printf("当前学生信息:\n");
            printf("学号=%d, 年级=%d, 班级=%s, 姓名=%s, 年龄=%d, 性别=%s, 成绩=%.2f\n",
                   result->data.id, result->data.grade, result->data.class, result->data.name,
                   result->data.age, result->data.sex, result->data.score);

            printf("请输入新的学生信息(学号 年级 班级 姓名 年龄 性别 成绩)用空格隔开:\n");
            if (scanf("%d %d %s %s %d %s %f", &newdata.id, &newdata.grade, newdata.class, newdata.name, &newdata.age, newdata.sex, &newdata.score) == 7) {
                result->data = newdata;
                printf("学生信息更新成功!\n");

                // 更新文件中的信息
                FILE *fp = fopen("student.txt", "r");
                FILE *temp = fopen("temp.txt", "w");
                if (fp == NULL || temp == NULL) {
                    perror("无法打开文件");
                    return;
                }

                Data current;
                while (fscanf(fp, "%d,%d,%[^,],%[^,],%d,%[^,],%f\n",
                              &current.id, &current.grade, current.class, current.name, &current.age, current.sex, &current.score) == 7) {
                    if (current.id == olddata.id) {
                        fprintf(temp, "%d,%d,%s,%s,%d,%s,%f\n", newdata.id, newdata.grade, newdata.class, newdata.name, newdata.age, newdata.sex, newdata.score);
                    } else {
                        fprintf(temp, "%d,%d,%s,%s,%d,%s,%f\n", current.id, current.grade, current.class, current.name, current.age, current.sex, current.score);
                    }
                }
                fclose(fp);
                fclose(temp);

                remove("student.txt");
                rename("temp.txt", "student.txt");
            } else {
                printf("输入格式错误。\n");
            }
        } else {
            printf("未找到学号为 %d 的学生信息。\n", olddata.id);
        }
    } else {
        printf("输入格式错误。\n");
    }
}


// 显示所有学生信息
void display_all(Node* head) {
    Node* current = head;
    printf("所有学生信息:\n");
    while (current != NULL) {
        printf("学号=%d, 年级=%d, 班级=%s, 姓名=%s, 年龄=%d, 性别=%s, 成绩=%.2f\n",
               current->data.id, current->data.grade, current->data.class, current->data.name,
               current->data.age, current->data.sex, current->data.score);
        current = current->next;
    }
}

/*
//成绩排名
void stor_stu_score(Node* head)
{
   printf("\n\n");
    printf("*****************************************************\n");
    printf("*----------------------duoduo------------------------\n");    
    printf("*                   学生成绩排名                    *\n");
    printf("*****************************************************\n");
    printf("********************系统功能菜单*********************\n");
    printf("----------------------     --------------------------\n");
    printf("*****************************************************\n");
    printf("**    1、按班级排名     *     2、按年级排名        **\n");
    printf("*****************************************************\n");
    printf("**    3、退出系统       *                         **\n");
    printf("*****************************************************\n");
    printf("----------------------     --------------------------\n");

    int num;
    printf("选择操作:");
    scanf("%d",&num);
    printf("\n");

    if(num == 1)
    {}
    else if (num == 2)
    {
       
    }
    else if (num == 3)
    {
    }
        
    else
    {
        puts("无效选择");
    }
}
*/
//work_mian.c
#include <stdio.h>
#include <stdlib.h>
#include "work_page.h"
#include "work_list.h"
#include "work_file.h"

// 主函数
int main() {
    Node* head = NULL;
    int choice;

    // 从文件读取数据到链表
    if (read_file(&head, "D:\\vscodePro\\work\\student.txt") != 0) {
        printf("读取文件失败,程序退出。\n");
        return -1;
    }

    while (1) {
        print_menu();  // 打印菜单

        printf("请选择操作(1-7):");
        if (scanf("%d", &choice) != 1) {
            printf("输入格式错误。\n");
            // 清空输入缓冲区
            while (getchar() != '\n');
            continue;
        }

        switch (choice) {
            case 1:
                increase(&head);
                break;
            case 2:
                delstu(&head);
                break;
            case 3:
                search(head);
                break;
            case 4:
                updatestu(head);
                break;
            case 5:
                // 这里可以调用成绩排名功能,当前功能未实现
                printf("成绩排名功能尚未实现。\n");
                break;
            case 6:
                display_all(head);
                break;
            case 7:
                // 退出系统前释放链表内存并退出
                free_list(head);
                printf("退出系统。\n");
                return 0;
            default:
                printf("无效选择,请重新输入。\n");
        }
    }

    return 0; // 这行在 while 循环后,用于结束 main 函数
}

运行结果及详细报错内容

编译运行时显示无法打开文件

img

我的解答思路和尝试过的方法,不写自己思路的,回答率下降 60%

尝试使用测试代码输出文件内容

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

// 定义数据结构
typedef struct {
    int id;
    int grade;
    char class[10];
    char name[50];
    int age;
    char sex[10];
    float score;
} Data;

// 定义节点结构
typedef struct Node {
    Data data;
    struct Node* next;
} Node;

// 在链表头部插入节点的函数
int insert_head(Node** head, Data student) {
    Node* new_node = (Node*)malloc(sizeof(Node));
    if (new_node == NULL) {
        return -1; // 内存分配失败
    }
    new_node->data = student;
    new_node->next = *head;
    *head = new_node;
    return 0;
}

// 从文件中读取数据并插入到链表中的函数
int read_file(Node** head, const char* file_name) {
    FILE *fp = fopen(file_name, "r");
    if (fp == NULL) {
        perror("无法打开文件");
        return -1;
    }

    Data student;
    while (fscanf(fp, "%d,%d,%[^,],%[^,],%d,%[^,],%f\n",
                  &student.id,
                  &student.grade,
                  student.class,
                  student.name,
                  &student.age,
                  student.sex,
                  &student.score) == 7) {
        if (insert_head(head, student) != 0) {
            puts("插入链表失败");
            fclose(fp);
            return -1;
        }
    }

    if (ferror(fp)) {
        perror("读取文件时出错");
        fclose(fp);
        return -1;
    }

    fclose(fp);
    return 0;
}

// 打印链表的函数
void list_print(Node* head) {
    Node* current = head;
    while (current != NULL) {
        printf("学号=%d, 年级=%d, 班级=%s, 姓名=%s, 年龄=%d, 性别=%s, 成绩=%.2f\n",
               current->data.id,
               current->data.grade,
               current->data.class,
               current->data.name,
               current->data.age,
               current->data.sex,
               current->data.score);
        current = current->next;
    }
}

// 释放链表的函数
void free_list(Node* head) {
    Node* current = head;
    Node* next;

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

int main() {
    Node* head = NULL;

    // 从文件中读取数据到链表中
    if (read_file(&head, "D:\\vscodePro\\work\\student.txt") == 0) {
        printf("数据成功读取到链表中\n");

        // 打印链表以验证数据
        list_print(head);
    } else {
        printf("读取文件失败\n");
    }

    // 释放链表
    free_list(head);

    return 0;
}


可以输出内容

img


尝试在函数中使用失败

我想要达到的结果:

文件可以读取并插入到链表中,可以正常实现功能。

  • 写回答

4条回答 默认 最新

  • 阿里嘎多学长 2024-07-19 13:02
    关注

    以下内容由AIGC及阿里嘎多学长共同生成、有用望采纳:


    根据你提供的信息和代码,我将提供一些可能的解决方案和建议来帮助你解决文件读取和链表插入的问题。

    1. 检查文件路径和权限: 确保文件路径正确,并且程序有足够的权限访问该文件。如果文件路径是相对路径,需要确保当前工作目录是正确的。如果是绝对路径,检查路径是否指向正确的文件位置。

    2. 使用access函数检查文件可访问性: 在尝试打开文件之前,使用access函数检查文件是否存在并且可读。例如:

      if (access("D:\\vscodePro\\work\\student.txt", R_OK) != -1) {
          // 文件存在且可读
      } else {
          // 文件不存在或不可读
          perror("文件不可访问");
      }
      
    3. 确保fscanf的格式字符串正确: 检查fscanf的格式字符串是否与结构体成员匹配。注意,对于字符串,%[^,]可以用来读取直到下一个逗号之前的所有字符。

    4. 内存分配错误处理: 每次调用malloc后,立即检查返回值。如果为NULL,表示内存分配失败,此时应输出错误信息并处理异常。

    5. 使用perror输出系统错误信息: 当fopenfscanf等函数失败时,使用perror输出系统级的错误信息,这有助于诊断问题。

    6. 增强代码的健壮性: 在读取文件和处理链表的代码中添加更多的错误检查和处理逻辑,确保在遇到错误时程序能够安全地退出并给出适当的提示。

    7. 编写测试代码: 创建一个已知格式正确的小文件,使用你的程序尝试读取它,并检查链表是否正确填充。这可以帮助你验证问题是否得到解决。

    8. 检查编译和链接命令: 确保所有相关的源文件都被正确编译和链接。从你提供的编译命令来看,似乎存在一些错误,比如work_mian.c应该是main.c,并且work_file.cwork_page.c的包含路径可能不正确。

    9. 检查代码中的逻辑错误: 例如,在updatestu函数中,更新链表节点后,没有写入文件的逻辑。你需要在更新链表后,将更新后的数据写回到文件中。

    10. 使用调试工具: 如果可能的话,使用调试工具(如gdb)来逐步执行程序,观察在哪个点程序崩溃或行为异常。

    根据你提供的截图和代码,我注意到你的main.c文件中的文件路径使用了Windows风格的路径,但是你的终端输出看起来像是在Linux环境中。请确保你的程序运行环境与文件路径格式一致。如果你在Linux环境中运行程序,需要使用Linux风格的路径,例如/home/user/work/student.txt

    希望这些建议能帮助你解决问题。如果问题仍然存在,请提供更多的错误信息或日志,以便进一步分析。

    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 7月19日

悬赏问题

  • ¥15 如何解除Uniaccess管控
  • ¥15 微信小程序跳转关联公众号
  • ¥15 Java AES 算法 加密采用24位向量报错如何处理?
  • ¥15 使用X11可以找到托盘句柄,监控到窗口点击事件但是如何在监听的同时获取托盘中应用的上下文菜单句柄
  • ¥45 字符串操作——数组越界问题
  • ¥15 Loss下降到0.08时不在下降调整学习率也没用
  • ¥15 QT+FFmpeg使用GPU加速解码
  • ¥15 为什么投影机用酷喵播放电影放一段时间就播放不下去了?提示发生未知故障,有什么解决办法吗?
  • ¥15 来个会搭建付费网站的有偿
  • ¥100 有能够实现人机模式的c/c++代码,有图片背景等,能够直接进行游戏