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
相关产品推荐
相关产品推荐

