file.h文件:
#ifndef FILE_H
#define FILE_H
#include "data.h"
void save_data();
void load_data();
void save_lovers();
void load_lovers();
#endif
recipe.c文件:
#ifndef RECIPE_H
#define RECIPE_H
#include "data.h"
// 菜谱管理
void add_recipe();
void delete_recipe();
void modify_recipe();
void search_recipes();
void random_recommendation();
// 辅助函数
void print_recipe(Recipe* recipe);
Recipe* find_recipe_by_id(int id);
Recipe* find_recipe_by_name(const char* name);
void get_multi_select_options(const char* prompt, int* flags, const char* options[], int count);
void get_meal_type(MealType* meal_type);
void get_cuisine(Cuisine* cuisine);
void get_lovers(char lovers[][MAX_NAME_LEN], int* count);
#endif
data.h文件:
#ifndef DATA_H
#define DATA_H
#include <stdbool.h>
// 常量定义
#define MAX_NAME_LEN 50
#define MAX_INGREDIENTS 20
#define MAX_STEPS 20
#define MAX_LOVERS 10
#define MAX_RECIPES 100
// 枚举定义
typedef enum
{
BREAKFAST,
MAIN_COURSE,
DESSERT,
SNACK,
DRINK
}
MealType;
typedef enum
{
SOUR = 1,
SWEET = 2,
BITTER = 4,
SPICY = 8,
SALTY = 16,
COLD = 32,
HOT = 64
}
Taste;
typedef enum
{
SOUP = 1,
DRY = 2,
WET = 4,
CRISPY = 8,
SOFT = 16,
HARD = 32
}
State;
typedef enum
{
LU,
CHUAN,
YUE,
SU,
MIN,
ZHE,
XIANG,
HUI,
DONGBEI,
HOME,
WESTERN
}
Cuisine;
// 菜谱结构体
typedef struct Recipe
{
int id;//自动生成的id
char name[MAX_NAME_LEN];//菜名
MealType meal_type;//餐型
int taste_flags;//口味
int state_flags;//状态
Cuisine cuisine;//菜系
//食材
char ingredients[MAX_INGREDIENTS][MAX_NAME_LEN];
int ingredient_count;
//步骤
char steps[MAX_STEPS][MAX_NAME_LEN * 2];
int step_count;
int cooking_time;//时间
//喜好者
char lovers[MAX_LOVERS][MAX_NAME_LEN];
int lover_count;
struct Recipe* next;
}
Recipe;
// 全局数据
extern Recipe* recipe_list;
extern int recipe_count;
extern char lovers_list[MAX_LOVERS][MAX_NAME_LEN];
extern int lover_count;
#endif
file.c文件:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "data.h"
void save_data()
{
FILE* file = fopen("recipes.dat", "wb");
if (!file)
{
perror("无法保存数据");
return;
}
Recipe* current = recipe_list;
while (current)
{
fwrite(current, sizeof(Recipe), 1, file);
current = current->next;
}
fclose(file);
printf("数据保存成功!\n");
}
void load_data()
{
FILE* file = fopen("recipes.dat", "rb");
if (!file) return;
Recipe* last = NULL;
while (!feof(file))
{
Recipe* new_recipe = (Recipe*)malloc(sizeof(Recipe));
if (fread(new_recipe, sizeof(Recipe), 1, file) != 1)
{
free(new_recipe);
break;
}
new_recipe->next = NULL;
if (!recipe_list)
{
recipe_list = new_recipe;
}
else
{
last->next = new_recipe;
}
last = new_recipe;
recipe_count++;
}
fclose(file);
}
void save_lovers()
{
FILE* file = fopen("lovers.dat", "w");
if (!file)
{
perror("无法保存喜好者数据");
return;
}
for (int i = 0; i < lover_count; i++)
{
fprintf(file, "%s\n", lovers_list[i]);
}
fclose(file);
}
void load_lovers()
{
FILE* file = fopen("lovers.dat", "r");
if (!file) return;
char line[MAX_NAME_LEN];
lover_count = 0;
while (fgets(line, sizeof(line), file) && lover_count < MAX_LOVERS)
{
line[strcspn(line, "\n")] = '\0';
strcpy(lovers_list[lover_count++], line);
}
fclose(file);
}
recipe.c文件:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "data.h"
#include "recipe.h"
// 辅助函数:获取多选选项
void get_multi_select_options(const char* prompt, int* flags, const char* options[], int count)
{
printf("%s (输入空行结束):\n", prompt);
for (int i = 0; i < count; i++)
{
printf("%d. %s\n", i+1, options[i]);
}
*flags = 0;
char input[10];
while (1)
{
fgets(input, sizeof(input), stdin);
if (input[0] == '\n') break;
int choice = atoi(input);
if (choice > 0 && choice <= count)
{
*flags |= (1 << (choice-1));
}
}
}
// 辅助函数:获取餐型
void get_meal_type(MealType* meal_type)
{
const char* meals[] = {"早餐", "正餐", "甜品", "零食", "饮品"};
printf("选择餐型:\n");
for (int i = 0; i < 5; i++)
{
printf("%d. %s\n", i+1, meals[i]);
}
printf("请选择: ");
int choice;
scanf("%d", &choice);
getchar();
*meal_type = (MealType)(choice-1);
}
// 辅助函数:获取菜系
void get_cuisine(Cuisine* cuisine)
{
const char* cuisines[] = {"鲁菜", "川菜", "粤菜", "苏菜", "闽菜", "浙菜", "湘菜", "徽菜", "东北菜", "家常菜", "西餐"};
printf("选择菜系:\n");
for (int i = 0; i < 11; i++)
{
printf("%d. %s\n", i+1, cuisines[i]);
}
printf("请选择: ");
int choice;
scanf("%d", &choice);
getchar();
*cuisine = (Cuisine)(choice-1);
}
// 辅助函数:获取喜好者
void get_lovers(char lovers[][MAX_NAME_LEN], int* count)
{
printf("当前喜好者:\n");
for (int i = 0; i < lover_count; i++)
{
printf("%d. %s\n", i+1, lovers_list[i]);
}
printf("选择喜好者 (输入空行结束):\n");
*count = 0;
char input[10];
while (*count < MAX_LOVERS)
{
fgets(input, sizeof(input), stdin);
if (input[0] == '\n') break;
int choice = atoi(input);
if (choice > 0 && choice <= lover_count)
{
strcpy(lovers[*count], lovers_list[choice-1]);
(*count)++;
}
}
}
// 打印菜谱详情
void print_recipe(Recipe* recipe)
{
if (!recipe) return;
const char* meals[] = {"早餐", "正餐", "甜品", "零食", "饮品"};
const char* cuisines[] = {"鲁菜", "川菜", "粤菜", "苏菜", "闽菜", "浙菜", "湘菜", "徽菜", "东北菜", "家常菜", "西餐"};
printf("\n菜谱ID: %d\n", recipe->id);
printf("菜名: %s\n", recipe->name);
printf("餐型: %s\n", meals[recipe->meal_type]);
printf("口味: ");
if (recipe->taste_flags & SOUR) printf("酸 ");
if (recipe->taste_flags & SWEET) printf("甜 ");
if (recipe->taste_flags & BITTER) printf("苦 ");
if (recipe->taste_flags & SPICY) printf("辣 ");
if (recipe->taste_flags & SALTY) printf("咸 ");
if (recipe->taste_flags & COLD) printf("凉 ");
if (recipe->taste_flags & HOT) printf("热 ");
printf("\n");
printf("状态: ");
if (recipe->state_flags & SOUP) printf("汤 ");
if (recipe->state_flags & DRY) printf("干 ");
if (recipe->state_flags & WET) printf("湿 ");
if (recipe->state_flags & CRISPY) printf("脆 ");
if (recipe->state_flags & SOFT) printf("软 ");
if (recipe->state_flags & HARD) printf("硬 ");
printf("\n");
printf("菜系: %s\n", cuisines[recipe->cuisine]);
printf("食材:\n");
for (int i = 0; i < recipe->ingredient_count; i++)
{
printf(" - %s\n", recipe->ingredients[i]);
}
printf("步骤:\n");
for (int i = 0; i < recipe->step_count; i++)
{
printf("%d. %s\n", i+1, recipe->steps[i]);
}
printf("烹饪时间: %d分钟\n", recipe->cooking_time);
printf("喜好者: ");
for (int i = 0; i < recipe->lover_count; i++)
{
printf("%s ", recipe->lovers[i]);
}
printf("\n");
}
// 通过ID查找菜谱
Recipe* find_recipe_by_id(int id)
{
Recipe* current = recipe_list;
while (current)
{
if (current->id == id) return current;
current = current->next;
}
return NULL;
}
// 通过名称查找菜谱
Recipe* find_recipe_by_name(const char* name)
{
Recipe* current = recipe_list;
while (current)
{
if (strcmp(current->name, name) == 0) return current;
current = current->next;
}
return NULL;
}
// 添加菜谱
void add_recipe()
{
Recipe* new_recipe = (Recipe*)malloc(sizeof(Recipe));
new_recipe->id = recipe_count + 1;
printf("输入菜名: ");
fgets(new_recipe->name, MAX_NAME_LEN, stdin);
new_recipe->name[strcspn(new_recipe->name, "\n")] = '\0';
get_meal_type(&new_recipe->meal_type);
// 获取口味
const char* tastes[] = {"酸", "甜", "苦", "辣", "咸", "凉", "热"};
get_multi_select_options("选择口味", &new_recipe->taste_flags, tastes, 7);
// 获取状态
const char* states[] = {"汤", "干", "湿", "脆", "软", "硬"};
get_multi_select_options("选择状态", &new_recipe->state_flags, states, 6);
get_cuisine(&new_recipe->cuisine);
// 获取食材
printf("输入食材 (每行一种,空行结束):\n");
new_recipe->ingredient_count = 0;
char ingredient[MAX_NAME_LEN];
while (new_recipe->ingredient_count < MAX_INGREDIENTS)
{
fgets(ingredient, MAX_NAME_LEN, stdin);
if (ingredient[0] == '\n') break;
ingredient[strcspn(ingredient, "\n")] = '\0';
strcpy(new_recipe->ingredients[new_recipe->ingredient_count], ingredient);
new_recipe->ingredient_count++;
}
// 获取步骤
printf("输入步骤 (每行一步,空行结束):\n");
new_recipe->step_count = 0;
char step[MAX_NAME_LEN * 2];
while (new_recipe->step_count < MAX_STEPS)
{
fgets(step, MAX_NAME_LEN * 2, stdin);
if (step[0] == '\n') break;
step[strcspn(step, "\n")] = '\0';
strcpy(new_recipe->steps[new_recipe->step_count], step);
new_recipe->step_count++;
}
printf("输入烹饪时间(分钟): ");
scanf("%d", &new_recipe->cooking_time);
getchar();
get_lovers(new_recipe->lovers, &new_recipe->lover_count);
// 添加到链表
new_recipe->next = recipe_list;
recipe_list = new_recipe;
recipe_count++;
printf("\n添加成功! 菜谱详情:\n");
print_recipe(new_recipe);
}
// 删除菜谱
void delete_recipe()
{
printf("1. 按ID查找\n2. 按名称查找\n选择查找方式: ");
int choice;
scanf("%d", &choice);
getchar();
Recipe* target = NULL;
if (choice == 1)
{
printf("输入菜谱ID: ");
int id;
scanf("%d", &id);
getchar();
target = find_recipe_by_id(id);
}
else if (choice == 2)
{
printf("输入菜名: ");
char name[MAX_NAME_LEN];
fgets(name, MAX_NAME_LEN, stdin);
name[strcspn(name, "\n")] = '\0';
target = find_recipe_by_name(name);
}
if (!target)
{
printf("未找到菜谱!\n");
return;
}
print_recipe(target);
printf("确认删除? (y/n): ");
char confirm;
scanf("%c", &confirm);
getchar();
if (confirm == 'y' || confirm == 'Y')
{
// 从链表中删除
if (target == recipe_list)
{
recipe_list = recipe_list->next;
}
else
{
Recipe* prev = recipe_list;
while (prev->next != target) prev = prev->next;
prev->next = target->next;
}
free(target);
recipe_count--;
printf("删除成功!\n");
}
else
{
printf("取消删除\n");
}
}
// 修改菜谱
void modify_recipe()
{
printf("1. 按ID查找\n2. 按名称查找\n选择查找方式: ");
int choice;
scanf("%d", &choice);
getchar();
Recipe* target = NULL;
if (choice == 1)
{
printf("输入菜谱ID: ");
int id;
scanf("%d", &id);
getchar();
target = find_recipe_by_id(id);
}
else if (choice == 2)
{
printf("输入菜名: ");
char name[MAX_NAME_LEN];
fgets(name, MAX_NAME_LEN, stdin);
name[strcspn(name, "\n")] = '\0';
target = find_recipe_by_name(name);
}
if (!target)
{
printf("未找到菜谱!\n");
return;
}
print_recipe(target);
printf("选择要修改的项:\n");
printf("1. 菜名\n2. 餐型\n3. 口味\n4. 状态\n5. 菜系\n");
printf("6. 食材\n7. 步骤\n8. 时间\n9. 喜好者\n");
printf("选择: ");
int mod_choice;
scanf("%d", &mod_choice);
getchar();
switch(mod_choice)
{
case 1:
printf("输入新菜名: ");
fgets(target->name, MAX_NAME_LEN, stdin);
target->name[strcspn(target->name, "\n")] = '\0';
break;
case 2:
get_meal_type(&target->meal_type);
break;
case 3:
{
const char* tastes[] = {"酸", "甜", "苦", "辣", "咸", "凉", "热"};
get_multi_select_options("选择新口味", &target->taste_flags, tastes, 7);
break;
}
case 4:
{
const char* states[] = {"汤", "干", "湿", "脆", "软", "硬"};
get_multi_select_options("选择新状态", &target->state_flags, states, 6);
break;
}
case 5:
get_cuisine(&target->cuisine);
break;
case 6:
printf("输入新食材 (每行一种,空行结束):\n");
target->ingredient_count = 0;
char ingredient[MAX_NAME_LEN];
while (target->ingredient_count < MAX_INGREDIENTS)
{
fgets(ingredient, MAX_NAME_LEN, stdin);
if (ingredient[0] == '\n') break;
ingredient[strcspn(ingredient, "\n")] = '\0';
strcpy(target->ingredients[target->ingredient_count], ingredient);
target->ingredient_count++;
}
break;
case 7:
printf("输入新步骤 (每行一步,空行结束):\n");
target->step_count = 0;
char step[MAX_NAME_LEN * 2];
while (target->step_count < MAX_STEPS)
{
fgets(step, MAX_NAME_LEN * 2, stdin);
if (step[0] == '\n') break;
step[strcspn(step, "\n")] = '\0';
strcpy(target->steps[target->step_count], step);
target->step_count++;
}
break;
case 8:
printf("输入新烹饪时间(分钟): ");
scanf("%d", &target->cooking_time);
getchar();
break;
case 9:
get_lovers(target->lovers, &target->lover_count);
break;
default:
printf("无效选择\n");
}
printf("\n修改后的菜谱:\n");
print_recipe(target);
}
// 查找菜谱
void search_recipes()
{
printf("1. 按ID查找\n2. 按名称查找\n3. 按餐型查找\n");
printf("4. 按口味查找\n5. 按状态查找\n6. 按菜系查找\n");
printf("7. 显示全部\n选择查找方式: ");
int choice;
scanf("%d", &choice);
getchar();
Recipe* current = recipe_list;
int found = 0;
switch(choice)
{
case 1:
{
printf("输入菜谱ID: ");
int id;
scanf("%d", &id);
getchar();
Recipe* target = find_recipe_by_id(id);
if (target)
{
print_recipe(target);
found = 1;
}
break;
}
case 2:
{
printf("输入菜名: ");
char name[MAX_NAME_LEN];
fgets(name, MAX_NAME_LEN, stdin);
name[strcspn(name, "\n")] = '\0';
Recipe* target = find_recipe_by_name(name);
if (target)
{
print_recipe(target);
found = 1;
}
break;
}
case 3:
{
MealType meal_type;
get_meal_type(&meal_type);
while (current)
{
if (current->meal_type == meal_type)
{
print_recipe(current);
found = 1;
}
current = current->next;
}
break;
}
case 4:
{
int taste_flags;
const char* tastes[] = {"酸", "甜", "苦", "辣", "咸", "凉", "热"};
get_multi_select_options("选择口味", &taste_flags, tastes, 7);
while (current)
{
if ((current->taste_flags & taste_flags) == taste_flags)
{
print_recipe(current);
found = 1;
}
current = current->next;
}
break;
}
case 5:
{
int state_flags;
const char* states[] = {"汤", "干", "湿", "脆", "软", "硬"};
get_multi_select_options("选择状态", &state_flags, states, 6);
while (current)
{
if ((current->state_flags & state_flags) == state_flags)
{
print_recipe(current);
found = 1;
}
current = current->next;
}
break;
}
case 6:
{
Cuisine cuisine;
get_cuisine(&cuisine);
while (current)
{
if (current->cuisine == cuisine)
{
print_recipe(current);
found = 1;
}
current = current->next;
}
break;
}
case 7:
while (current)
{
print_recipe(current);
current = current->next;
found = 1;
}
break;
}
if (!found)
{
printf("未找到匹配的菜谱!\n");
}
}
// 随机推荐
void random_recommendation()
{
printf("1. 推荐一餐\n2. 推荐多天餐食\n选择: ");
int choice;
scanf("%d", &choice);
getchar();
srand(time(NULL));
if (choice == 1)
{
MealType meal_type;
get_meal_type(&meal_type);
int count;
printf("输入推荐数量: ");
scanf("%d", &count);
getchar();
// 收集符合条件的菜谱
Recipe* candidates[MAX_RECIPES];
int candidate_count = 0;
Recipe* current = recipe_list;
while (current)
{
if (current->meal_type == meal_type)
{
candidates[candidate_count++] = current;
}
current = current->next;
}
if (candidate_count == 0)
{
printf("没有符合条件的菜谱!\n");
return;
}
printf("\n推荐菜谱:\n");
for (int i = 0; i < count && i < candidate_count; i++)
{
int idx = rand() % candidate_count;
print_recipe(candidates[idx]);
// 避免重复推荐
candidates[idx] = candidates[--candidate_count];
}
}
else if (choice == 2)
{
int days;
printf("输入天数: ");
scanf("%d", &days);
getchar();
// 每种餐型所需数量
int counts[5] = {0};
const char* meals[] = {"早餐", "正餐(午)", "正餐(晚)", "甜品", "零食", "饮品"};
for (int i = 0; i < 5; i++)
{
if (i == 1) // 正餐需要两次
{
printf("%s数量: ", meals[1]);
scanf("%d", &counts[1]);
printf("%s数量: ", meals[2]);
scanf("%d", &counts[2]);
}
else
{
printf("%s数量: ", meals[i + (i>1?1:0)]);
scanf("%d", &counts[i]);
}
}
getchar();
// 按天生成餐单
for (int day = 1; day <= days; day++)
{
printf("\n=== 第 %d 天 ===\n", day);
// 收集每种餐型的菜谱
Recipe* meal_candidates[5][MAX_RECIPES];
int meal_counts[5] = {0};
Recipe* current = recipe_list;
while (current)
{
if (current->meal_type == BREAKFAST)
{
meal_candidates[0][meal_counts[0]++] = current;
}
else if (current->meal_type == MAIN_COURSE)
{
meal_candidates[1][meal_counts[1]++] = current;
meal_candidates[2][meal_counts[2]++] = current;
}
else if (current->meal_type == DESSERT)
{
meal_candidates[3][meal_counts[3]++] = current;
}
else if (current->meal_type == SNACK)
{
meal_candidates[4][meal_counts[4]++] = current;
}
else if (current->meal_type == DRINK)
{
meal_candidates[5][meal_counts[5]++] = current;
}
current = current->next;
}
// 生成当天的每种餐型
for (int meal = 0; meal < 6; meal++)
{
int meal_idx = meal;
if (meal > 1) meal_idx--; // 调整索引
if (counts[meal_idx] == 0) continue;
printf("\n%s:\n", meals[meal]);
for (int i = 0; i < counts[meal_idx]; i++)
{
if (meal_counts[meal] == 0)
{
printf(" (无足够菜谱)\n");
break;
}
int idx = rand() % meal_counts[meal];
printf(" - %s\n", meal_candidates[meal][idx]->name);
// 避免重复
meal_candidates[meal][idx] = meal_candidates[meal][--meal_counts[meal]];
}
}
}
}
}
main.c文件:
#include <stdio.h>
#include <stdlib.h>
#include "data.h"
#include "recipe.h"
#include "file.h"
#include <windows.h> // 添加 Windows API 支持
// 全局变量
Recipe* recipe_list = NULL;
int recipe_count = 0;
char lovers_list[MAX_LOVERS][MAX_NAME_LEN];
int lover_count = 0;
void display_main_menu()
{
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("请选择操作: ");
}
void lover_management()
{
printf("\n喜好者管理\n");
printf("1. 添加喜好者\n");
printf("2. 删除喜好者\n");
printf("3. 查看所有喜好者\n");
printf("请选择操作: ");
int choice;
scanf("%d", &choice);
getchar(); // 消耗换行符
switch(choice)
{
case 1:
if (lover_count < MAX_LOVERS)
{
printf("输入喜好者姓名: ");
fgets(lovers_list[lover_count], MAX_NAME_LEN, stdin);
lovers_list[lover_count][strcspn(lovers_list[lover_count], "\n")] = '\0';
lover_count++;
save_lovers();
printf("添加成功!\n");
} else
{
printf("喜好者数量已达上限!\n");
}
break;
case 2:
printf("当前喜好者:\n");
for (int i = 0; i < lover_count; i++) {
printf("%d. %s\n", i+1, lovers_list[i]);
}
printf("选择要删除的编号: ");
int idx;
scanf("%d", &idx);
getchar();
if (idx > 0 && idx <= lover_count)
{
for (int i = idx-1; i < lover_count-1; i++)
{
strcpy(lovers_list[i], lovers_list[i+1]);
}
lover_count--;
save_lovers();
printf("删除成功!\n");
}
else
{
printf("无效选择!\n");
}
break;
case 3:
printf("所有喜好者:\n");
for (int i = 0; i < lover_count; i++)
{
printf("%d. %s\n", i+1, lovers_list[i]);
}
break;
}
}
int main()
{
// 设置控制台编码为 UTF-8
SetConsoleOutputCP(65001);
SetConsoleCP(65001);
load_data();
load_lovers();
int running = 1;
while (running)
{
display_main_menu();
int choice;
scanf("%d", &choice);
getchar(); // 消耗换行符
switch(choice)
{
case 1: add_recipe(); break;
case 2: delete_recipe(); break;
case 3: modify_recipe(); break;
case 4: search_recipes(); break;
case 5: random_recommendation(); break;
case 6: lover_management(); break;
case 7:
save_data();
running = 0;
break;
default:
printf("无效选择!\n");
}
}
return 0;
}
makefile文件
CC = g++
CFLAGS = -Wall -Wextra -std=c++11 -g
TARGET = wj
SOURCES = main.c recipe.c file.c
HEADERS = data.h recipe.h file.h
all: $(TARGET)
$(TARGET): $(SOURCES) $(HEADERS)
$(CC) $(CFLAGS) -o $(TARGET) $(SOURCES)
clean:
rm -f $(TARGET) *.dat
run: $(TARGET)
./$(TARGET)
.PHONY: all clean run
消化这些代码文件,稍后我会给出修改要求