2

I just learned C and I'm trying to save the inputs from the user when the code runs, but then it seems that I cannot store the inputs especially for saving the inputs when I rerun the file again. I would like to be able to store the inputs even if the code is runs again. Your help is greatly appreciated!

#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);
}

I tried changing the file mode to "a" to append the inputs, but still, when I run the code again, no previous file is present, it says:

"No existing inventory file found. Starting afresh."

And, when I try to save the input to the file, it says:

"Error opening file for saving."

5
  • 5
    Please extract a minimal reproducible example from your code and provide that here, not your full program. Commented Jun 23, 2024 at 9:14
  • 3
    There are at least two problems with your code. (1) You are trying to read from a file opened in write mode. (2) while(!feof(file)) is almost always wrong, see why. Other than that, there doesn't seem to be a problem that specifically leads to the error message you show. Perhaps you are running the program in a directory where you do not have permission to write. Commented Jun 23, 2024 at 9:40
  • 2
    open file just for reading mode ="r" , mode="w" creates a new file every time!, to add data - open for append "a" or "a+" if you want to read from it Commented Jun 23, 2024 at 9:51
  • 2
    Note that FILE is a type, not a function (so the title is confused). You could ask "… using the standard I/O functions?" or "… using the fopen() function?" or "… using the file functions?" Commented Jun 23, 2024 at 14:10
  • Thank you for your help, everyone! I'm sorry for the long code and the format of my question. I'll ask better next time, hopefully. :) Commented Jun 24, 2024 at 0:31

1 Answer 1

2

You write

void loadFromFile(InventoryItem items[], int *count)
{
    FILE *file = fopen("inventory.txt", "w");
    /* =================================^^^ */

using "w" in fopen() will delete all data in the file inventory.txt and will prepare it for writing new data, not for reading. the manual says:

   w      Truncate  file  to  zero length or create text file for writing.  The stream is positioned at the beginning of the file.

This was the reason you got nothing when reloading the data from the file.


The above answers your question but that is not the only error you have in your code. You can stop here and continue debugging or continue reading and see many other mistakes you have made (some of them will be difficult to identify if you don't read the manual pages of the system functions first)

    if (file == NULL)
    {
        printf("No existing inventory file found. Starting fresh.\n");
        return;
    }

    while (!feof(file) && *count < MAX_ITEMS)

this code above is wrong, you should write:

    while (*count < MAX_ITEMS 
         && fgets(items[*count].itemName, 
                  sizeof items[*count].itemName))

This is because feof() only checks if you got EOF in the previous read, not if you are at the end of file. Indeed you are at the end of file because you have truncated the file to zero size, but you will not get that until you fread(), fscanf() or fgets() first. You will enter the loop when no more data is available and you will get trash as input (the buffer contents).

    {
        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';

the code above is unneeded, as fgets() always returns a '\0' terminated string. Only if you pass to it a zero sized variable, fgets() always puts the final '\0'.


        fscanf(file, "%f\n", &items[*count].price);
        fscanf(file, "%d\n", &items[*count].stock);

The above code is correct, but will not do what you expect. It will fail if you don't provide two '\n' ended numbers (e.g. if you provide to space separated numbers in the same row.) and it will not synchornize if you get unsynch. This is a more delicate thing. Of course it will work if your input is correct, but will not recover if you make a mistake on input.


        fgets(items[*count].keyword, sizeof(items[*count].keyword), file);

more if you mix fgets() and fscan() together. I'd suggest you to read full lines of text (with fgets()) then use sscanf() instead, with no '\n's interspersed on input. This will allow you to resynch your data input at fixed places (at end of lines)

        items[*count].keyword[strcspn(items[*count].keyword, "\n")] = '\0';

Again, the code above is unnecessary, as if you pass a non-zero sized buffer, fgets() will always put a '\0' on it. You can check if there's a '\n' at the end with strlen() because fgets() always reads upto a '\n' char, and includes it to indicate anomalous result.


        (*count)++;
    }

    fclose(file);
    printf("Items loaded from file successfully! %d items found.\n", *count);
}

Finally, there's no reason to pass count as a reference pointer. Your function returns void (this is, nothing) so a better interface should have been to pass the array size (can be as size_t count) and return back a size_t indicating how many registers have been read (or a ssize_t to allow for -1 indicating an error on reading.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.