#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <stdbool.h>
#define MAX_RECORDS 1000
#define MAX_NAME_LEN 50
#define MAX_LOC_LEN 100
#define MAX_WEATHER_LEN 50
#define FILENAME_LEN 150
#define DATE_LEN 20
typedef struct {
char location[MAX_LOC_LEN];
char fishSpecies[MAX_NAME_LEN];
float weight;
char weather[MAX_WEATHER_LEN];
time_t date;
bool isRare;
} FishingRecord;
FishingRecord records[MAX_RECORDS];
int recordCount = 0;
void addRecord();
void displayRecords();
bool saveRecords();
bool loadRecords();
void generateStatistics();
void searchRecords();
bool editRecord();
bool deleteRecord();
void markRareFish();
void displayMenu();
void clearInputBuffer();
void toLowerCase(char *str);
int compareStringsIgnoreCase(const char *str1, const char *str2);
bool isValidWeight(float weight);
bool isValidDate(const char *dateStr);
bool parseDate(const char *dateStr, struct tm *tm);
void printRecord(FishingRecord record, int index);
void printHeader();
int main() {
if (!loadRecords()) {
printf("警告:加载记录失败,将从空记录开始\n");
}
int choice;
do {
displayMenu();
printf("请输入您的选择(1-8): ");
if (scanf("%d", &choice) != 1) {
clearInputBuffer();
printf("输入无效,请输入数字\n");
continue;
}
clearInputBuffer();
switch(choice) {
case 1: addRecord(); break;
case 2: displayRecords(); break;
case 3: searchRecords(); break;
case 4: editRecord(); break;
case 5: deleteRecord(); break;
case 6: generateStatistics(); break;
case 7: markRareFish(); break;
case 8:
if (saveRecords()) {
printf("记录已保存,程序退出。\n");
} else {
printf("保存失败,是否仍要退出?(y/n): ");
char confirm = getchar();
if (tolower(confirm) != 'y') {
choice = 0;
}
}
break;
default:
printf("无效的选择,请输入1-8之间的数字\n");
}
} while(choice != 8);
return 0;
}
void displayMenu() {
printf("\n===== 钓鱼记录管理系统 =====\n");
printf("1. 添加钓鱼记录\n");
printf("2. 显示所有记录\n");
printf("3. 搜索记录\n");
printf("4. 编辑记录\n");
printf("5. 删除记录\n");
printf("6. 生成统计报表\n");
printf("7. 标记稀有鱼种\n");
printf("8. 保存并退出\n");
printf("============================\n");
}
void addRecord() {
if(recordCount >= MAX_RECORDS) {
printf("错误:记录已满,无法添加更多记录\n");
return;
}
FishingRecord newRecord;
char dateInput[DATE_LEN];
printf("\n--- 添加新钓鱼记录 ---\n");
while(true) {
printf("请输入钓鱼地点(1-%d字符): ", MAX_LOC_LEN-1);
if (fgets(newRecord.location, MAX_LOC_LEN, stdin) == NULL) {
printf("输入错误\n");
continue;
}
newRecord.location[strcspn(newRecord.location, "\n")] = '\0';
if (strlen(newRecord.location) > 0) break;
printf("地点不能为空\n");
}
while(true) {
printf("请输入鱼种(1-%d字符): ", MAX_NAME_LEN-1);
if (fgets(newRecord.fishSpecies, MAX_NAME_LEN, stdin) == NULL) {
printf("输入错误\n");
continue;
}
newRecord.fishSpecies[strcspn(newRecord.fishSpecies, "\n")] = '\0';
if (strlen(newRecord.fishSpecies) > 0) break;
printf("鱼种不能为空\n");
}
while(true) {
printf("请输入重量(kg): ");
if (scanf("%f", &newRecord.weight) != 1) {
printf("请输入有效的数字\n");
clearInputBuffer();
continue;
}
clearInputBuffer();
if (isValidWeight(newRecord.weight)) break;
printf("重量必须在0.01-500kg之间\n");
}
while(true) {
printf("请输入天气情况(1-%d字符): ", MAX_WEATHER_LEN-1);
if (fgets(newRecord.weather, MAX_WEATHER_LEN, stdin) == NULL) {
printf("输入错误\n");
continue;
}
newRecord.weather[strcspn(newRecord.weather, "\n")] = '\0';
if (strlen(newRecord.weather) > 0) break;
printf("天气不能为空\n");
}
while(true) {
printf("请输入日期(YYYY-MM-DD,留空使用今天): ");
if (fgets(dateInput, DATE_LEN, stdin) == NULL) {
printf("输入错误\n");
continue;
}
dateInput[strcspn(dateInput, "\n")] = '\0';
if (strlen(dateInput) == 0) {
time(&newRecord.date);
break;
} else if (isValidDate(dateInput)) {
struct tm tm = {0};
if (parseDate(dateInput, &tm)) {
newRecord.date = mktime(&tm);
break;
}
}
printf("日期格式无效,请使用YYYY-MM-DD格式\n");
}
newRecord.isRare = false;
records[recordCount++] = newRecord;
printf("\n记录添加成功!\n");
}
bool saveRecords() {
if(recordCount == 0) {
printf("没有记录需要保存\n");
return true;
}
FILE *fileList = fopen("fishing_files.txt", "w");
if(fileList == NULL) {
perror("无法创建文件列表");
return false;
}
bool success = true;
for(int i = 0; i < recordCount; i++) {
char filename[FILENAME_LEN];
snprintf(filename, FILENAME_LEN, "fishing_%s.txt", records[i].location);
bool alreadyProcessed = false;
for(int j = 0; j < i; j++) {
if(strcmp(records[i].location, records[j].location) == 0) {
alreadyProcessed = true;
break;
}
}
if(alreadyProcessed) continue;
fprintf(fileList, "%s\n", filename);
FILE *file = fopen(filename, "w");
if(file == NULL) {
perror("无法创建记录文件");
success = false;
continue;
}
fprintf(file, "地点,鱼种,重量(kg),天气,日期,是否稀有\n");
for(int j = 0; j < recordCount; j++) {
if(strcmp(records[i].location, records[j].location) == 0) {
char dateStr[DATE_LEN];
struct tm *timeinfo = localtime(&records[j].date);
strftime(dateStr, sizeof(dateStr), "%Y-%m-%d", timeinfo);
fprintf(file, "%s,%s,%.2f,%s,%s,%d\n",
records[j].location,
records[j].fishSpecies,
records[j].weight,
records[j].weather,
dateStr,
records[j].isRare ? 1 : 0);
}
}
if(fclose(file) != 0) {
perror("关闭文件失败");
success = false;
}
}
if(fclose(fileList) != 0) {
perror("关闭文件列表失败");
success = false;
}
return success;
}
bool loadRecords() {
FILE *fileList = fopen("fishing_files.txt", "r");
if(fileList == NULL) {
return false;
}
char filename[FILENAME_LEN];
while(fgets(filename, FILENAME_LEN, fileList) && recordCount < MAX_RECORDS) {
filename[strcspn(filename, "\n")] = '\0';
FILE *file = fopen(filename, "r");
if(file == NULL) {
printf("无法打开文件: %s\n", filename);
continue;
}
char line[256];
fgets(line, sizeof(line), file);
while(fgets(line, sizeof(line), file) && recordCount < MAX_RECORDS) {
FishingRecord record;
char dateStr[DATE_LEN];
if(sscanf(line, "%[^,],%[^,],%f,%[^,],%[^,],%d",
record.location,
record.fishSpecies,
&record.weight,
record.weather,
dateStr,
&record.isRare) == 6) {
struct tm tm = {0};
if(parseDate(dateStr, &tm)) {
record.date = mktime(&tm);
records[recordCount++] = record;
}
}
}
fclose(file);
}
fclose(fileList);
return true;
}
bool isValidWeight(float weight) {
return weight > 0.01 && weight <= 500.0;
}
bool isValidDate(const char *dateStr) {
if(strlen(dateStr) != 10) return false;
if(dateStr[4] != '-' || dateStr[7] != '-') return false;
for(int i = 0; i < 10; i++) {
if(i == 4 || i == 7) continue;
if(!isdigit(dateStr[i])) return false;
}
return true;
}
bool parseDate(const char *dateStr, struct tm *tm) {
if(sscanf(dateStr, "%d-%d-%d",
&tm->tm_year,
&tm->tm_mon,
&tm->tm_mday) != 3) {
return false;
}
tm->tm_year -= 1900;
tm->tm_mon -= 1;
tm->tm_hour = 0;
tm->tm_min = 0;
tm->tm_sec = 0;
tm->tm_isdst = -1;
return true;
}
void clearInputBuffer() {
int c;
while((c = getchar()) != '\n' && c != EOF);
}