我刚刚学习了 C,我试图在代码运行时保存用户的输入,但似乎我无法存储输入,特别是在再次重新运行文件时保存输入。即使代码再次运行,我希望能够存储输入。非常感谢您的帮助!
#include <stdio.h>
#include <string.h>
#define MAX_ITEMS 100
typedef struct
{
char itemName[50];
float price;
int stock;
char keyword[20];
} InventoryItem;
void addItem(InventoryItem items[], int *count);
void editItem(InventoryItem items[], int count);
void deleteItem(InventoryItem items[], int *count);
void displayItems(const InventoryItem items[], int count);
void searchItems(const InventoryItem items[], int count);
void saveToFile(const InventoryItem items[], int count);
void loadFromFile(InventoryItem items[], int *count);
int main()
{
InventoryItem items[MAX_ITEMS];
int count = 0;
int choice;
loadFromFile(items, &count);
while (1)
{
printf("Menu:\n");
printf("1. Add Item\n");
printf("2. Edit Item\n");
printf("3. Delete Item\n");
printf("4. Display Items\n");
printf("5. Search Items\n");
printf("6. Exit\n");
printf("Enter your choice: ");
scanf("%d", &choice);
switch (choice)
{
case 1:
addItem(items, &count);
break;
case 2:
editItem(items, count);
break;
case 3:
deleteItem(items, &count);
break;
case 4:
displayItems(items, count);
break;
case 5:
searchItems(items, count);
break;
case 6:
saveToFile(items, count);
return 0;
default:
printf("Invalid choice!\n");
}
}
return 0;
}
void addItem(InventoryItem items[], int *count)
{
if (*count >= MAX_ITEMS)
{
printf("Inventory is full!\n");
return;
}
printf("Enter item name: ");
getchar(); // Clear newline from buffer
fgets(items[*count].itemName, sizeof(items[*count].itemName), stdin);
items[*count].itemName[strcspn(items[*count].itemName, "\n")] = '\0';
printf("Enter price: ");
scanf("%f", &items[*count].price);
printf("Enter stock: ");
scanf("%d", &items[*count].stock);
printf("Enter keyword: ");
getchar(); // Clear newline from buffer
fgets(items[*count].keyword, sizeof(items[*count].keyword), stdin);
items[*count].keyword[strcspn(items[*count].keyword, "\n")] = '\0';
(*count)++;
printf("Item added successfully!\n");
saveToFile(items, *count);
}
void editItem(InventoryItem items[], int count)
{
if (count == 0)
{
printf("No items to edit.\n");
return;
}
int index;
printf("Enter item number to edit (1 to %d): ", count);
scanf("%d", &index);
if (index < 1 || index > count)
{
printf("Invalid item number.\n");
return;
}
index--; // Convert to zero-based index
printf("Editing item #%d\n", index + 1);
printf("Enter new item name: ");
getchar(); // Clear newline from buffer
fgets(items[index].itemName, sizeof(items[index].itemName), stdin);
items[index].itemName[strcspn(items[index].itemName, "\n")] = '\0';
printf("Enter new price: ");
scanf("%f", &items[index].price);
printf("Enter new stock: ");
scanf("%d", &items[index].stock);
printf("Enter new keyword: ");
getchar(); // Clear newline from buffer
fgets(items[index].keyword, sizeof(items[index].keyword), stdin);
items[index].keyword[strcspn(items[index].keyword, "\n")] = '\0';
printf("Item updated successfully!\n");
saveToFile(items, count);
}
void deleteItem(InventoryItem items[], int *count)
{
if (*count == 0)
{
printf("No items to delete.\n");
return;
}
int index;
printf("Enter item number to delete (1 to %d): ", *count);
scanf("%d", &index);
if (index < 1 || index > *count)
{
printf("Invalid item number.\n");
return;
}
index--; // Convert to zero-based index
for (int i = index; i < *count - 1; i++)
{
items[i] = items[i + 1];
}
(*count)--;
printf("Item deleted successfully!\n");
saveToFile(items, *count);
}
void displayItems(const InventoryItem items[], int count)
{
if (count == 0)
{
printf("No items to display.\n");
return;
}
printf("Inventory Items:\n");
for (int i = 0; i < count; i++)
{
printf("Item #%d\n", i + 1);
printf("Name: %s\n", items[i].itemName);
printf("Price: %.2f\n", items[i].price);
printf("Stock: %d\n", items[i].stock);
printf("Keyword: %s\n\n", items[i].keyword);
}
}
void searchItems(const InventoryItem items[], int count)
{
if (count == 0)
{
printf("No items to search.\n");
return;
}
char keyword[20];
printf("Enter keyword to search: ");
getchar(); // Clear newline from buffer
fgets(keyword, sizeof(keyword), stdin);
keyword[strcspn(keyword, "\n")] = '\0';
printf("Search Results:\n");
int found = 0;
for (int i = 0; i < count; i++)
{
if (strstr(items[i].keyword, keyword) != NULL)
{
printf("Item #%d\n", i + 1);
printf("Name: %s\n", items[i].itemName);
printf("Price: %.2f\n", items[i].price);
printf("Stock: %d\n", items[i].stock);
printf("Keyword: %s\n\n", items[i].keyword);
found = 1;
}
}
if (!found)
{
printf("No items found with the keyword \"%s\".\n", keyword);
}
}
void saveToFile(const InventoryItem items[], int count)
{
FILE *file = fopen("inventory.txt", "w");
if (file == NULL)
{
printf("Error opening file for saving.\n");
return;
}
for (int i = 0; i < count; i++)
{
fprintf(file, "%s\n", items[i].itemName);
fprintf(file, "%.2f\n", items[i].price);
fprintf(file, "%d\n", items[i].stock);
fprintf(file, "%s\n", items[i].keyword);
}
fclose(file);
printf("Items saved to file successfully!\n");
}
// file opening
void loadFromFile(InventoryItem items[], int *count)
{
FILE *file = fopen("inventory.txt", "w");
if (file == NULL)
{
printf("No existing inventory file found. Starting fresh.\n");
return;
}
while (!feof(file) && *count < MAX_ITEMS)
{
if (fgets(items[*count].itemName, sizeof(items[*count].itemName), file) == NULL)
break;
items[*count].itemName[strcspn(items[*count].itemName, "\n")] = '\0';
fscanf(file, "%f\n", &items[*count].price);
fscanf(file, "%d\n", &items[*count].stock);
fgets(items[*count].keyword, sizeof(items[*count].keyword), file);
items[*count].keyword[strcspn(items[*count].keyword, "\n")] = '\0';
(*count)++;
}
fclose(file);
printf("Items loaded from file successfully! %d items found.\n", *count);
}
我尝试将文件模式更改为“a”以附加输入,但是当我再次运行代码时,不存在以前的文件,它说:
“未找到现有库存文件。重新开始。”
而且,当我尝试将输入保存到文件中时,它显示:
“打开文件进行保存时出错。”
你写
void loadFromFile(InventoryItem items[], int *count)
{
FILE *file = fopen("inventory.txt", "w");
/* =================================^^^ */
在
"w"
中使用 fopen()
将删除文件 inventory.txt
中的所有数据,并准备写入新数据,而不是读取。 手册说:
w Truncate file to zero length or create text file for writing. The stream is positioned at the beginning of the file.
这就是您从文件重新加载数据时什么也没有得到的原因。
上面回答了您的问题,但这并不是代码中唯一的错误。 你可以停在这里继续调试或者继续阅读并看到你犯的许多其他错误(如果你不先阅读系统功能的手册页,其中一些将很难识别)
if (file == NULL)
{
printf("No existing inventory file found. Starting fresh.\n");
return;
}
while (!feof(file) && *count < MAX_ITEMS)
上面这段代码是错误的,你应该这样写:
while (*count < MAX_ITEMS
&& fgets(items[*count].itemName,
sizeof items[*count].itemName))
这是因为
feof()
仅检查您在上一次读取中是否获得 EOF
,而不是检查您是否位于文件末尾。 事实上,您已到达文件末尾,因为您已将文件截断至零大小,但只有先按 fread()
、fscanf()
或 fgets()
才能得到该文件。 当没有更多数据可用时,您将进入循环,并且您将得到垃圾作为输入(缓冲区内容)。
{
if (fgets(items[*count].itemName, sizeof(items[*count].itemName), file) == NULL)
break;
there's no reason to exit the loop here (you will, of course, because you are at EOF, but there's no reason to check if `fgets()` resulted in `NULL` (this indicates EOF, so you should have not entered the loop anyway)
items[*count].itemName[strcspn(items[*count].itemName, "\n")] = '\0';
上面的代码是不需要的,因为
fgets()
总是返回一个 '\0'
终止的字符串。 仅当您向其传递零大小的变量时,fgets()
始终会放置最终的 '\0'
。
fscanf(file, "%f\n", &items[*count].price);
fscanf(file, "%d\n", &items[*count].stock);
上面的代码是正确的,但不会达到您的期望。 如果您不提供两个
'\n'
结尾的数字(例如,如果您在同一行中提供空格分隔的数字),它将失败,并且如果您不同步,它将不会同步。 这是一个比较微妙的事情。 当然如果你输入正确的话它会起作用,但如果你输入错误则无法恢复。
fgets(items[*count].keyword, sizeof(items[*count].keyword), file);
如果将 fgets()
和
fscan()
混合在一起,更多。 我建议您阅读整行文本(使用
fgets()
),然后使用 sscanf()
代替,不要在输入中散布 '\n'
。 这将允许您在固定位置(行尾)重新同步数据输入
items[*count].keyword[strcspn(items[*count].keyword, "\n")] = '\0';
再次强调,上面的代码是不必要的,就像您传递一个非零大小的缓冲区一样,
fgets()
将始终在其上放置一个'\0'
。 您可以使用 '\n'
检查末尾是否有 strlen()
,因为 fgets()
始终读取到 '\n'
字符,并包含它以指示异常结果。
(*count)++;
}
fclose(file);
printf("Items loaded from file successfully! %d items found.\n", *count);
}
最后,没有理由将
count
作为引用指针传递。 您的函数返回 void
(这是什么),因此更好的接口应该是传递数组大小(可以为 size_t count
)并返回 size_t
指示已读取多少个寄存器(或 ssize_t
允许 -1
指示读取错误。
loadFromFile 函数内的行更改为
FILE *file = fopen("inventory.txt", "r");