0

The program is to create an inventory of items, view inventory, and allow the user to delete items via item number. Everything is through a struct array and I am having difficulty in freeing the array element after deleting the inventory item by shifting everything else above it in the array via a function. Any help is appreciated.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_INVENTORY_SIZE 100

typedef struct {
    char item_Number[4];
    char item_Name[20];
    float item_Profit;
    float latest_Price;
    float selling_Price;
    unsigned int stock;
    unsigned int total_Sold;
}InventoryItemType;

void MainMenu();
void displayInventory(InventoryItemType *, int);
void displaySales(InventoryItemType *, int);
InventoryItemType *addItem(void);
InventoryItemType deleteItem(InventoryItemType *, int);

int main()
{
    int i=0, item_count=0;
    char selection, code[4];
    InventoryItemType inventoryItems[MAX_INVENTORY_SIZE];
    while(1)
    {
        MainMenu();

        scanf(" %c", &selection);
        switch(selection) 
        {
        case 'A' :
            displayInventory(inventoryItems, item_count);
            system("pause");
            system("cls");
            continue;
        case 'B' :
            displaySales(inventoryItems, item_count);
            system("pause");
            system("cls");
            continue;
        case 'C' :
            if(item_count == MAX_INVENTORY_SIZE - 1)
            {
                printf("Array is full\n");
                system("pause");
                continue;
            }
            inventoryItems[item_count] = *addItem();
            item_count++;
            continue;
        case 'D' :
            *inventoryItems=deleteItem(inventoryItems, item_count);
            free(&inventoryItems[item_count]);
            item_count--;
            continue;
        case 'E' :
        case 'F' :
        case 'G' :
        case 'H' :
        default :
            printf("Invalid Entry\n" );
            system("pause");
        }
        system("cls");
    }
}
void MainMenu()
{
    printf("A. Display Inventory\n");
    printf("B. Display Sales\n");
    printf("C. Add Item\n");
    printf("D. Remove Item\n");
    printf("E. Enter Shipment\n");
    printf("F. Update Sales\n");
    printf("G. Sort\n");
    printf("H. Exit\n");
    printf("Make a selection\n");
}
void displayInventory(InventoryItemType *display, int key)
{
    system("cls");
    {
        int i;
        for(i=0; i<key; i++)
        {
            printf("Item No.:%s\n", display[i].item_Number);
            printf("Item Name:%s\n", display[i].item_Name);
            printf("Item Stock:%d\n",display[i].stock);
            printf("Item Purchased Price:%.2f\n", display[i].latest_Price);
            printf("Total Value of Items:%.2f\n", (display[i].stock)*(display[i].latest_Price));
            printf("\n");
        }
    }
}
void displaySales(InventoryItemType *display, int key)
{

    int i;
    float total_profit=0;
    system("cls");
    for(i=0; i<key; i++)
    {
        printf("Item No.:%s\n", display[i].item_Number);
        printf("Item Name:%s\n", display[i].item_Name);
        printf("Number of Item Sold:%d\n", display[i].total_Sold);
        printf("Item Selling Price:%.2f\n", display[i].selling_Price);
        printf("Total Profit from Item:%.2f\n", (display[i].selling_Price-display[i].latest_Price)*display[i].total_Sold);
        total_profit=total_profit+((display[i].selling_Price-display[i].latest_Price)*display[i].total_Sold);
        if(i==key-1)
        printf("\nTotal Over-all Profit:%.2f", total_profit);
        printf("\n\n");
    }
}
InventoryItemType *addItem(void)
{
    InventoryItemType *current = (InventoryItemType*) malloc (sizeof *current);
    system("cls");
    if(current == NULL)
        return NULL;
    printf("\nEnter details of item \n\n");
    printf("Enter Item no: \n");
    scanf("%s", current->item_Number);
    printf("Enter Item Name: \n");
    scanf("%s", current->item_Name);
    printf("Enter Stock: \n");
    scanf("%d", &current->stock);
    printf("Enter Purchase Price: \n");
    scanf("%f", &current->latest_Price);
    current->selling_Price=(current->latest_Price)*1.5;
    current->total_Sold=0;
    system("cls");
    return current;
}
InventoryItemType deleteItem (InventoryItemType *deleted, int item_count)
{
    char code[4];
    int i;
    printf("Enter Item Number to be Deleted\n");
    scanf("%3s", code);
    for(i=0;i<item_count;i++)
    {
        if(strcmp(code,deleted[i].item_Number)==0)
                break;
    }
    for(;i<item_count; i++)
        deleted[i]=deleted[i+1];
    return *deleted;
}  

EDIT with help of @Barmar:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_INVENTORY_SIZE 100

typedef struct {
    char item_Number[4];
    char item_Name[20];
    float item_Profit;
    float latest_Price;
    float selling_Price;
    unsigned int stock;
    unsigned int total_Sold;
}InventoryItemType;
void MainMenu();
void displayInventory(InventoryItemType *[], int);
void displaySales(InventoryItemType *[], int);
InventoryItemType *addItem(void);
InventoryItemType deleteItem(InventoryItemType *, int);

int main()
{
    int i=0, item_count=0;
    char selection, code[4];
    InventoryItemType *inventoryItems[MAX_INVENTORY_SIZE];
    while(1)
    {
        MainMenu();

        scanf(" %c", &selection);
        switch(selection) 
        {
        case 'A' :
            displayInventory(inventoryItems, item_count);
            system("pause");
            system("cls");
            continue;
        case 'B' :
            displaySales(inventoryItems, item_count);
            system("pause");
            system("cls");
            continue;
        case 'C' :
            if(item_count == MAX_INVENTORY_SIZE - 1)
            {
                printf("Array is full\n");
                system("pause");
                continue;
            }
            inventoryItems[item_count] = addItem();
            item_count++;
            continue;
        case 'D' :
            **inventoryItems=deleteItem(*inventoryItems, item_count);
            item_count--;
            continue;
        case 'E' :
        case 'F' :
        case 'G' :
        case 'H' :
        default :
            printf("Invalid Entry\n" );
            system("pause");
        }
        system("cls");
    }
}
void MainMenu()
{
    printf("A. Display Inventory\n");
    printf("B. Display Sales\n");
    printf("C. Add Item\n");
    printf("D. Remove Item\n");
    printf("E. Enter Shipment\n");
    printf("F. Update Sales\n");
    printf("G. Sort\n");
    printf("H. Exit\n");
    printf("Make a selection\n");
}
void displayInventory(InventoryItemType *display[], int key)
{
    system("cls");
    {
        int i;
        for(i=0; i<key; i++)
        {
            printf("Item No.:%s\n", display[i]->item_Number);
            printf("Item Name:%s\n", display[i]->item_Name);
            printf("Item Stock:%d\n",display[i]->stock);
            printf("Item Purchased Price:%.2f\n", display[i]->latest_Price);
            printf("Total Value of Items:%.2f\n", (display[i]->stock)*(display[i]->latest_Price));
            printf("\n");
        }
    }
}
void displaySales(InventoryItemType *display[], int key)
{

    int i;
    float total_profit=0;
    system("cls");
    for(i=0; i<key; i++)
    {
        printf("Item No.:%s\n", display[i]->item_Number);
        printf("Item Name:%s\n", display[i]->item_Name);
        printf("Number of Item Sold:%d\n", display[i]->total_Sold);
        printf("Item Selling Price:%.2f\n", display[i]->selling_Price);
        printf("Total Profit from Item:%.2f\n", (display[i]->selling_Price-display[i]->latest_Price)*display[i]->total_Sold);
        total_profit=total_profit+((display[i]->selling_Price-display[i]->latest_Price)*display[i]->total_Sold);
        if(i==key-1)
        printf("\nTotal Over-all Profit:%.2f", total_profit);
        printf("\n\n");
    }
}
InventoryItemType *addItem(void)
{
    InventoryItemType *current = (InventoryItemType*) malloc (sizeof *current);
    system("cls");
    if(current == NULL)
        return NULL;
    printf("\nEnter details of item \n\n");
    printf("Enter Item no: \n");
    scanf("%s", current->item_Number);
    printf("Enter Item Name: \n");
    scanf("%s", current->item_Name);
    printf("Enter Stock: \n");
    scanf("%d", &current->stock);
    printf("Enter Purchase Price: \n");
    scanf("%f", &current->latest_Price);
    current->selling_Price=(current->latest_Price)*1.5;
    current->total_Sold=0;
    system("cls");
    return current;
}
InventoryItemType deleteItem (InventoryItemType *deleted, int item_count)
{
    char code[4];
    int i;
    printf("Enter Item Number to be Deleted\n");
    scanf("%3s", code);
    for(i=0;i<item_count;i++)
    {
        if(strcmp(code,deleted[i].item_Number)==0)
                break;
    }
    free(deleted[i]);
    for(;i<item_count; i++)
        deleted[i]=deleted[i+1];
    return *deleted;
}
4
  • 3
    You can only free() something if you allocated it with malloc(). You can't free elements of an array, they didn't come from malloc(). Commented Mar 30, 2018 at 17:00
  • @Barmar, I have allocated with malloc() in the additem function. This should be possible with a struct array. Commented Mar 30, 2018 at 17:05
  • 2
    But you didn't store that pointer in inventoryItems, you dereferenced it and copied the structure. You have a memory leak of all those pointers. Commented Mar 30, 2018 at 17:07
  • Yes, and then you copy the allocated structure and leak the allocated memory. You cannot deallocate an element of an array. (You can overwrite its value with something else, for example by shifting later elements into it.) Commented Mar 30, 2018 at 17:08

2 Answers 2

1

The elements of inventoryItems aren't dynamically-allocated, so you can't free them. They're directly contained in the array. When you do:

inventoryItems[item_count] = *add_item();

you're dereferencing the pointer, not storing the pointer in the array. This makes a copy of the dynamically-allocated structure, and discards its pointer (so you get a memory leak).

You should change the type of this array to contain pointers:

InventoryItemType * inventoryItems[MAX_INVENTORY_SIZE];

Then you shouldn't dereference the pointer returned by addItem, you should just assign it directly:

inventoryItems[item_count] = add_item();

and you free it with:

free(inventoryItems[item_count]);

And in displayInventory() you change all display[i].xxx to display[i]->xxx.

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

7 Comments

Thanks for your help. I implemented all the changes(pretty sure) however I still get an error when trying to free. I am relatively new programming so please pardon my obvious mistakes. I edited my original post.
Add the updated code as an addition to your question (NOTE do not remove the original code) so I can see what you did wrong.
Done, Thanks for the help
After you call deleteItem(inventoryItems, item_count) you do free(inventoryItems[item_count])? Why do you free that item? It's not the one that was deleted. The right thing would be to call free(deleted[i]) before the second loop in deleteItem().
Added the change, but get the error 10 IntelliSense: no suitable conversion function from "InventoryItemType" to "void *" exists updated the code above
|
1

The reason you're having trouble freeing is because you didn't actually allocate what you're trying to free.

In your addItem function, you dynamically allocate an object, populate it, and return it. In the calling function however, you never save the pointer you got back. You instead dereference it directly and copy the contents via assignment to an instance in the array. This results in a memory leak.

Later, when you go do delete an element, you return a pointer to an array element, which was not dynamically allocated, so you can't free it. Actually, you're not even returning a pointer to the element you deleted but to the first element of the array instead, so you're not even attempting to free what you expected to.

Rather than dynamically allocating memory in addItem, just pass in the address of the current array element and populate that instead. Also, no need to return anything in deleteItem.

So addItem should now look like this:

void addItem(InventoryItemType *current)
{
    system("cls");
    if(current == NULL)
        return NULL;
    ...
    return;
}

And you would call it like this:

addItem(&inventoryItems[item_count]);

For deleteItem, change the return type to void, then get rid of the call to free after calling it.

1 Comment

Unfortunately, I am bound to the concept of dynamic allocation.

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.