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

C语言读取文件图书数据并输出最便宜图书所在城市的代码求助

C语言图书数据处理问题:读取文件并找最低售价图书所在城市

我正在开发一个C语言程序,需要从input_data.txt读取图书结构体数据,找出售价最低的图书所在城市并写入output_data.txt。

输入输出示例

输入文件(input_data.txt):

2
Book Title 1
10
200
Author 1
2021
Publisher 1
City 1
Book Title 2
15
150
Author 2
2022
Publisher 2
City 2

预期输出文件(output_data.txt):

City 1

我的代码

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

struct izdatel {
    int god;
    char naz[100];
    char gor[100];
};

struct Book {
    char title[100];
    int price;
    int numPages;
    char author[100];
    struct izdatel publisherInfo;
};

void check_number(const char name[], int *s, FILE *input_data) {
    int ret_code;
    do {
        //printf("Input %s:\n", name);
        ret_code = fscanf(input_data, "%d", s);
        while (getchar() != '\n');  // clear the buffer (as not using fgets)
    } while (ret_code != 1 || *s <= 0);
}

void check_year(const char name[], int *s, FILE *input_data) {
    int ret_code;
    do {
        //printf("Input %s (between 1458 and 2024):\n", name);
        ret_code = fscanf(input_data, "%d", s);
        while (getchar() != '\n');  
    } while (ret_code != 1 || *s < 1458 || *s > 2024);
}

void check_string(const char name[], char s[], FILE *input_data) {
    int invalid_input;
    do {
        invalid_input = 0;
        //printf("Input %s:\n", name);
        fscanf(input_data, "%s", s);
        while (getchar() != '\n'); 

        for (int i = 0; i < strlen(s); i++) {
            if (!isalpha(s[i]) && !isspace(s[i])) {
                invalid_input = 1;
                printf("Invalid input. Please enter a string without numbers or special characters.\n");
                break;
            }
        }

    } while (invalid_input || strlen(s) == 0);
}

void input(struct Book *books, const int numStructs, FILE *input_data) {
    fscanf(input_data, "%d", &numStructs);
    while (getchar() != '\n');
    for (int i = 0; i < numStructs; i++) {
        //printf("Book #%d\n", i + 1);
        check_string("Title", books[i].title, input_data);
        check_number("Price", &books[i].price, input_data);
        check_number("Number of pages", &books[i].numPages, input_data);
        check_string("Author", books[i].author, input_data);

        //printf("Publishing company:\n");
        check_year("Year of publication", &books[i].publisherInfo.god, input_data);
        check_string("Publisher name", books[i].publisherInfo.naz, input_data);
        check_string("Publishing city", books[i].publisherInfo.gor, input_data);
    }
}


void solution(struct Book *books, const int numStructs, FILE *output_data){
    float minPrice = books[0].price;
    for (int i = 0; i < numStructs; i++) {
        if (books[i].price < minPrice) {
            minPrice = books[i].price;
        }
    }

    fprintf(output_data, "\nCities where the cheapest books are published:\n");
    for (int i = 0; i < numStructs; i++) {
        if (books[i].price == minPrice) {
            fprintf(output_data, "%s\n", books[i].publisherInfo.gor);
        }
    }
}

int main() {
    int numStructs;
    FILE *inputFile;

    struct Book books[numStructs];
    // input file
    char *inputFilename = "input_data.txt";
    char *outputFilename = "output_data.txt";

    inputFile = fopen(inputFilename, "r");
    FILE *outputFile = fopen(outputFilename, "w");
    
    if (inputFile == NULL || outputFile == NULL) {
        printf("Error opening files.\n");
        return 1;
    }

    if (inputFile) {
        input(books, numStructs, inputFile);
        solution(books, numStructs, outputFile);
    } else {
        printf("Failed to open the input file.\n");
    }
    
    fclose(inputFile);
    fclose(outputFile);

    return 0;
}

我一直绞尽脑汁解决这个问题,恳请您帮忙,非常感谢!


代码核心问题及修正方案

1. 未初始化变长数组导致内存错误

main中numStructs未赋值就用来定义变长数组struct Book books[numStructs];,会引发内存访问异常。

修正:
先读取文件中的图书数量,再创建数组:

int main() {
    int numStructs;
    FILE *inputFile, *outputFile;
    char *inputFilename = "input_data.txt";
    char *outputFilename = "output_data.txt";

    inputFile = fopen(inputFilename, "r");
    outputFile = fopen(outputFilename, "w");
    
    if (inputFile == NULL || outputFile == NULL) {
        printf("Error opening files.\n");
        return 1;
    }

    // 先读取图书数量并验证
    if (fscanf(inputFile, "%d", &numStructs) != 1 || numStructs <= 0) {
        printf("Invalid number of books.\n");
        fclose(inputFile);
        fclose(outputFile);
        return 1;
    }
    while (getchar() != '\n'); // 清除换行符

    struct Book books[numStructs];
    input(books, numStructs, inputFile);
    solution(books, numStructs, outputFile);
    
    fclose(inputFile);
    fclose(outputFile);
    return 0;
}

同时删除input函数中读取numStructs的代码,因为已在main中完成。

2. fscanf("%s")无法读取带空格的字符串

输入中的Book Title 1、Author 1包含空格,fscanf("%s")只会读取第一个空格前的内容,导致字符串不完整。

修正:
改用fgets读取整行,再处理换行符:

void check_string(const char name[], char s[], FILE *input_data) {
    int invalid_input;
    do {
        invalid_input = 0;
        if (!fgets(s, 100, input_data)) {
            invalid_input = 1;
            printf("Input error.\n");
            exit(1);
        }
        s[strcspn(s, "\n")] = '\0'; // 移除换行符

        if (strlen(s) == 0) {
            invalid_input = 1;
            printf("Invalid input. String cannot be empty.\n");
            continue;
        }

        for (int i = 0; i < strlen(s); i++) {
            if (!isalpha((unsigned char)s[i]) && !isspace((unsigned char)s[i])) {
                invalid_input = 1;
                printf("Invalid input. Please enter a string without numbers or special characters.\n");
                break;
            }
        }
    } while (invalid_input);
}

3. 输出格式不符合预期

原solution函数输出额外提示文字,需改为仅输出城市名称:

void solution(struct Book *books, const int numStructs, FILE *output_data){
    if (numStructs == 0) return;
    int minPrice = books[0].price;
    for (int i = 1; i < numStructs; i++) {
        if (books[i].price < minPrice) {
            minPrice = books[i].price;
        }
    }

    for (int i = 0; i < numStructs; i++) {
        if (books[i].price == minPrice) {
            fprintf(output_data, "%s\n", books[i].publisherInfo.gor);
        }
    }
}

同时将minPrice改为int类型(与price类型一致)。

4. 输入验证的缓冲区清理问题

原check_number和check_year中getchar()可能导致无限循环,改用fgets+sscanf更安全:

void check_number(const char name[], int *s, FILE *input_data) {
    char buffer[100];
    int ret_code;
    do {
        if (!fgets(buffer, sizeof(buffer), input_data)) {
            printf("Input error.\n");
            exit(1);
        }
        ret_code = sscanf(buffer, "%d", s);
    } while (ret_code != 1 || *s <= 0);
}

void check_year(const char name[], int *s, FILE *input_data) {
    char buffer[100];
    int ret_code;
    do {
        if (!fgets(buffer, sizeof(buffer), input_data)) {
            printf("Input error.\n");
            exit(1);
        }
        ret_code = sscanf(buffer, "%d", s);
    } while (ret_code != 1 || *s < 1458 || *s > 2024);
}

修正后的完整代码

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

struct izdatel {
    int god;
    char naz[100];
    char gor[100];
};

struct Book {
    char title[100];
    int price;
    int numPages;
    char author[100];
    struct izdatel publisherInfo;
};

void check_number(const char name[], int *s, FILE *input_data) {
    char buffer[100];
    int ret_code;
    do {
        if (!fgets(buffer, sizeof(buffer), input_data)) {
            printf("Input error.\n");
            exit(1);
        }
        ret_code = sscanf(buffer, "%d", s);
    } while (ret_code != 1 || *s <= 0);
}

void check_year(const char name[], int *s, FILE *input_data) {
    char buffer[100];
    int ret_code;
    do {
        if (!fgets(buffer, sizeof(buffer), input_data)) {
            printf("Input error.\n");
            exit(1);
        }
        ret_code = sscanf(buffer, "%d", s);
    } while (ret_code != 1 || *s < 1458 || *s > 2024);
}

void check_string(const char name[], char s[], FILE *input_data) {
    int invalid_input;
    do {
        invalid_input = 0;
        if (!fgets(s, 100, input_data)) {
            invalid_input = 1;
            printf("Input error.\n");
            exit(1);
        }
        s[strcspn(s, "\n")] = '\0';

        if (strlen(s) == 0) {
            invalid_input = 1;
            printf("Invalid input. String cannot be empty.\n");
            continue;
        }

        for (int i = 0; i < strlen(s); i++) {
            if (!isalpha((unsigned char)s[i]) && !isspace((unsigned char)s[i])) {
                invalid_input = 1;
                printf("Invalid input. Please enter a string without numbers or special characters.\n");
                break;
            }
        }
    } while (invalid_input);
}

void input(struct Book *books, const int numStructs, FILE *input_data) {
    for (int i = 0; i < numStructs; i++) {
        check_string("Title", books[i].title, input_data);
        check_number("Price", &books[i].price, input_data);
        check_number("Number of pages", &books[i].numPages, input_data);
        check_string("Author", books[i].author, input_data);

        check_year("Year of publication", &books[i].publisherInfo.god, input_data);
        check_string("Publisher name", books[i].publisherInfo.naz, input_data);
        check_string("Publishing city", books[i].publisherInfo.gor, input_data);
    }
}

void solution(struct Book *books, const int numStructs, FILE *output_data){
    if (numStructs == 0) return;
    int minPrice = books[0].price;
    for (int i = 1; i < numStructs; i++) {
        if (books[i].price < minPrice) {
            minPrice = books[i].price;
        }
    }

    for (int i = 0; i < numStructs; i++) {
        if (books[i].price == minPrice) {
            fprintf(output_data, "%s\n", books[i].publisherInfo.gor);
        }
    }
}

int main() {
    int numStructs;
    FILE *inputFile, *outputFile;
    char *inputFilename = "input_data.txt";
    char *outputFilename = "output_data.txt";

    inputFile = fopen(inputFilename, "r");
    outputFile = fopen(outputFilename, "w");
    
    if (inputFile == NULL || outputFile == NULL) {
        printf("Error opening files.\n");
        return 1;
    }

    if (fscanf(inputFile, "%d", &numStructs) != 1 || numStructs <= 0) {
        printf("Invalid number of books.\n");
        fclose(inputFile);
        fclose(outputFile);
        return 1;
    }
    while (getchar() != '\n');

    struct Book books[numStructs];
    input(books, numStructs, inputFile);
    solution(books, numStructs, outputFile);
    
    fclose(inputFile);
    fclose(outputFile);
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 18:55:54