Limit items in a shopping list using malloc()? - c

I am struggling with the function that should add items to a shopping list. I wrote code that works, but I am wondering if there is another way to limit items to 5 by using malloc()?
The length field should always be containing the index to the last position of the array, so this is where the item should be placed. For instance, length is zero when the list is empty,
So the first time this function is called, the item should be placed at index zero in list->itemArray.
This function is also responsible for increasing the length of the list.
Since we just added one item, the list is now one item longer.
Just remember that it should not be possible to add more than 5 items to the list.
#ifndef SHOPPING_LIST_H
#define SHOPPING_LIST_H
// Struct definitions
struct GroceryItem
{
char productName[20];
float amount;
char unit[10];
};
struct ShoppingList
{
int length;
struct GroceryItem itemList[5];
};
// Function declarations
void addItem(struct ShoppingList *list);
void printList(struct ShoppingList *list);
void editItem(struct ShoppingList *list);
void removeItem(struct ShoppingList *list);
void saveList(struct ShoppingList *list);
void loadList(struct ShoppingList* list);
#endif
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include "ShoppingList.h"
int main(void)
{
struct ShoppingList shoppingList;
shoppingList.length = 0; // The shopping list is empty at the start
int option;
do
{
printf("\n\nWelcome to the shopping list manager!\n");
printf("=====================================\n\n");
printf("1. Add an item\n");
printf("2. Display the shopping list\n");
printf("3. Remove an item\n");
printf("4. Change an item\n");
printf("5. Save list\n");
printf("6. Load list\n");
printf("7. Exit\n");
printf("What do you want to do? ");
scanf("%d", &option);
switch (option)
{
case 1: addItem(&shoppingList); break;
case 2: printList(&shoppingList); break;
case 3: removeItem(&shoppingList); break;
case 4: editItem(&shoppingList); break;
case 5: saveList(&shoppingList); break;
case 6: loadList(&shoppingList); break;
case 7: break;
default:
printf("Please enter a number between 1 and 7");
}
} while (option != 7);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS
#include"ShoppingList.h"
#include<stdio.h>
#include<stdlib.h> // For malloc() and free()
/*
The “length” field should always be containing the index to the last position of the array,
so this is where the item should be placed. For instance, length is zero when the list is empty,
so the first time this function is called, the item should be placed at index zero in list->itemArray.
This function is also responsible for increasing the length of the list.
Since we just added one item, the list is now one item longer.
Just remember that it should not be possible to add more than 5 items to the list.
*/
void addItem(struct ShoppingList* list)
{
if (list->length > 4)
{
return 0;
}
printf("Name for product: ");
scanf("%s", list->itemList[list->length].productName);
do
{
printf("Enter the amount: ");
scanf("%f", &list->itemList[list->length].amount);
if (list->itemList[list->length].amount <= 0.0)
{
printf("Input is invalid.\n");
}
} while (list->itemList[list->length].amount <= 0.0);
printf("Enter unit of item: ");
scanf("%s", list->itemList[list->length].unit);
printf("%s was added to the shoppinglist.", list->itemList[list->length].productName);
list->length++;
}

Related

Shoppinglist program, structs, malloc() and functions

I started with an assignment which should include a program that can add remove print, edit, save list.
I am stuck on the first function that should add an item to my grocery list. As you can see, this function (and all other functions) receives a pointer to a shopping list. This is a pointer to the shopping list defined in main(), and my functions should make changes directly to the shopping list that the argument list is pointing to.
The function should ask the user for a name, amount and unit of an item. It should then place it last in the shopping list. The “length” field should always be containing the index to the last position of the array, so this is where the item should be placed. For instance, length is zero when the list is empty, so the first time this function is called, the item should be placed at index zero in list->itemArray.
This function is also responsible for increasing the length of the list. Since we just added one item, the list is now one item longer. Just remember that it should not be possible to add more than 5 items to the list.
If the user enters a non-positive number for amount, the program should tell the user that the input is invalid and repeat the question until a correct answer has been given.
How should I limit the size list to just 5 products?
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include "ShoppingList.h"
int main(void)
{
struct ShoppingList shoppingList;
shoppingList.length = 0; // The shopping list is empty at the start
int option;
do
{
printf("\n\nWelcome to the shopping list manager!\n");
printf("=====================================\n\n");
printf("1. Add an item\n");
printf("2. Display the shopping list\n");
printf("3. Remove an item\n");
printf("4. Change an item\n");
printf("5. Save list\n");
printf("6. Load list\n");
printf("7. Exit\n");
printf("What do you want to do? ");
scanf("%d", &option);
switch (option)
{
case 1: addItem(&shoppingList); break;
case 2: printList(&shoppingList); break;
case 3: removeItem(&shoppingList); break;
case 4: editItem(&shoppingList); break;
case 5: saveList(&shoppingList); break;
case 6: loadList(&shoppingList); break;
case 7: break;
default:
printf("Please enter a number between 1 and 7");
}
} while (option != 7);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS
#include"ShoppingList.h"
#include<stdio.h>
#include<stdlib.h> // For malloc() and free()
void addItem(struct ShoppingList* list)
{
list = (struct ShoppingList*)malloc(sizeof(struct ShoppingList) * 5);
printf("Name for product: ");
scanf("%s", list->itemList[list->length].productName);
do
{
printf("Enter the amount: ");
scanf("%f", &list->itemList[list->length].amount);
if (list->itemList[list->length].amount <= 0.0)
{
printf("Input is invalid.\n");
}
} while (list->itemList[list->length].amount <= 0.0);
printf("Enter unit of item: ");
scanf("%s", list->itemList[list->length].unit);
list->length++;
}
void printList(struct ShoppingList *list)
{
int i;
printf("\nName:\tAmount:\tUnit:\n\n");
for (i = 0; i < list->length; i++) {
printf("%s\t%d\t%s\n", list->itemList[i].productName, list->itemList[i].amount, list->itemList[i].unit);
}
printf("\n\n");
}
void editItem(struct ShoppingList *list)
{
}
void removeItem(struct ShoppingList *list)
{
}
void saveList(struct ShoppingList *list)
{
}
void loadList(struct ShoppingList* list)
{
}
#ifndef SHOPPING_LIST_H
#define SHOPPING_LIST_H
// Struct definitions
struct GroceryItem
{
char productName[20];
float amount;
char unit[10];
};
struct ShoppingList
{
int length;
struct GroceryItem itemList[5];
};
// Function declarations
void addItem(struct ShoppingList *list);
void printList(struct ShoppingList *list);
void editItem(struct ShoppingList *list);
void removeItem(struct ShoppingList *list);
void saveList(struct ShoppingList *list);
void loadList(struct ShoppingList* list);
#endif

root node automatically resets to null while insertion

I'm trying to add new nodes to the tree but whenever one insertion is completed, root node automatically resets to null and at the end my tree is empty. I'm trying to construct BST.
My main function:
int main()
{
char c;
int item;
struct BSTNode *root=NULL;
while(1)
{
printf("\n1 Insert an element ");
printf("\n2 Delete an element");
printf("\n3 InOrder Traversal");
printf("\nEnter your choice: ");
scanf("%d", &c);
switch(c)
{
case 1:
printf("\nEnter the item:");
scanf("%d", &item);
if(root){printf("Root data before: %d",root->data); } //Print statement -1
root = insert(root,item);
printf("Root data after: %d",root->data); //Print statement-2
break;
case 2:
printf("\nEnter the info to be deleted:");
scanf("%d", &item);
root = delete(root, item);
break;
case 3:
InOrder(root);
break;
default:
printf("Enter a valid choice: ");
}
}
return 0;
}
and my insert function looks like:
struct BSTNode* insert(struct BSTNode *root, int data)
{
if(root==NULL)
{
root=create(data);
}
if(data<root->data)
root->left=insert(root->left,data);
if(data>root->data)
root->right=insert(root->right,data);
return root;
}
Here in my main function, two print statements are there. In that, statement 2 is printing the data of root node but when again I want to add new node, statement 1 doesn't print the data of root node. And after that new value of root node is shown in statement 2 also.
Why its char c? when your cases are integer, try using int c instead. Also you are taking input using %d so it should be integer

Segmentation Fault with Pointers and Structures

This program is supposed to manipulate a student list. Every time I try to add more than one student I get a segmentation fault error. Also, when I try to print the list recursively I get a segmentation fault error. I think it has to do with how I am saving to the structure and/or calling it. I am very new to programming so I'm sure it is something simple. Any ideas?
//Header file declarations.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//Structure defintion.
struct student {
int ID;
char name[40];
struct student *next;
};
//Type definition.
typedef struct student Student;
//Function prototypes.
int getChoice();
Student *addToList(Student *List);
void printList(Student *List);
void printListRR(Student *List);
void searchList(Student *List);
/*main function
Objective: This function provides runs a function call based on an option selected the user in another function.
Input: This function recieves no input from the user directly but it is passed their menu selection.
Output: The function outputs error messages and a closing salutation to the user. It returns 0.
*/
int main(void) {
int choice = 0;
Student *SLIST = NULL;
//Call getChoice to get user's selection
choice = getChoice();
//Switch-case for the possible menu selections
while(choice >= 0) {
switch(choice) {
case 0 : printf("Bye...\n"); exit(0);
case 1 : SLIST = addToList(SLIST); break;
case 2 : printList(SLIST); break;
case 3 : printListRR(SLIST); break;
case 4 : searchList(SLIST); break;
default: printf("That is not a valid choice\n");
}
choice = getChoice();
}
if(SLIST) free(SLIST);
return 0;
}
int getChoice() {
int choice = 0;
printf("\n****** MENU ******\n");
printf("1. Add new student to list.\n");
printf("2. Print the student list, beginning to end.\n");
printf("3. Recursively print the student list from the end.\n");
printf("4. Search the list for a student.\n");
printf("0. Quit.\n");
printf("\nEnter your choice: ");
scanf("%d", &choice);
return choice;
}
Student *addToList(Student *List){
Student *studentPtr = (Student *) malloc(sizeof(Student));
printf("Student ID: ");
scanf("%d", &(studentPtr->ID));
printf("Student Name: ");
scanf(" %[^\n]", studentPtr->name);
if(List == NULL){
return studentPtr;
}
Student *nextStudent = List;
while (nextStudent->next != NULL){
nextStudent = nextStudent->next;
}
nextStudent->next = studentPtr;
return List;
}
void printList(Student *List){
while(List != NULL){
printf("%d %s\n", List->ID, List->name);
List = List->next;
}
}
void printListRR(Student *List){
if(List == NULL){
return;
}
printListRR(List->next);
}
void searchList(Student *List){
int idSearch;
printf("Enter student ID to search for: ");
scanf("%d", &idSearch);
while(List != NULL){
if(List->ID == idSearch){
printf("%d %s\n", List->ID, List->name);
return;
}
List = List->next;
}
printf("ID %d not found", idSearch);
}
Try initialising studentPtr->next to NULL in addToList()?

My function doesn't memorize the head of linked list

I have to do a program of a linked list with many function like delete, add and modify number.
In my code when I put a number in my function with the choice 1, after that when I want to display all the numbers I put the head in parameter but I see in visual studio that the parameter of the function don't have anything. What can I do in order to pass the head of the linked list in parameter in my function Displaynbr
#include <stdio.h>
#include <stdlib.h>
struct Mynbr
{
int nbr;
struct Mynbr* next;
} typedef Mynbr;
void Menu();
void choiceMenu(int choice, Mynbr* first);
Mynbr* Addnumber(Mynbr* first);
void Displaynbr(Mynbr* first);
int main(void)
{
Mynbr* head = NULL;
int choice = 0;
while (choice!=5)
{
Menu();
printf("Your choice : "); scanf("%d", &choice);
choiceMenu(choice, head);
}
system("PAUSE");
return 0;
}
void Menu()
{
printf("\n1.Add number to the list\n");
printf("2.Delete number from the list\n");
printf("3.Search number in the list\n");
printf("4.Display all the numbers from the list\n");
printf("5.Exit\n");
}
void choiceMenu(int choice, Mynbr* first)
{
switch (choice)
{
case 1:
Addnumber(first);
break;
case 2:
break;
case 3:
break;
case 4:
Displaynbr(first);
break;
case 5:
break;
}
}
Mynbr* Addnumber(Mynbr* first)
{
printf("\n===Function to add a number===\n");
Mynbr* head_nbr = first;
if (!head_nbr)
{
head_nbr = (Mynbr*)malloc(sizeof(Mynbr));
printf("Enter a number :"); scanf("%d", &(head_nbr->nbr));
head_nbr->next = NULL;
}
return head_nbr;
}
void Displaynbr(Mynbr* first)
{
printf("\n===Function to display number===\n");
Mynbr* curr = first;
if (curr->next)
{
printf("The number is : %d", curr->nbr);
Displaynbr(first->next);
}
}
You were not very far from it, but forgot one essential rule:
when you change the value of a parameter in a function, the caller's value remains unchanged.
So AddNumber (almost) correctly returns the new value of the list head address, but choiceMenu immediately discards it.
So here are some fixes:
AddNumber should be able to add a number to an empty or non empty list (NB: it currently leads to a LIFO):
Mynbr* Addnumber(Mynbr* first){
printf("\n===Function to add a number===\n");
Mynbr* head_nbr = first;
head_nbr = (Mynbr*)malloc(sizeof(Mynbr));
printf("Enter a number :"); scanf("%d", &(head_nbr->nbr));
head_nbr->next = first; // just link to initial head, be it null or not
return head_nbr;
}
choiceMenu should not discard the new head - you can either return it to the caller like you do for AddNumber or use a double indirection:
void choiceMenu(int choice, Mynbr** first){
switch (choice){
case 1:
*first = Addnumber(*first);
break;
case 2:
break;
case 3:
break;
case 4:
Displaynbr(*first);
break;
case 5:
break;
}
}
(do not forget to change the initial declaration and call it: choiceMenu(choice, &head))
Last but not least, DisplayNumber incorrectly tests for curr->next instead of curr:
void Displaynbr(Mynbr* first){
printf("\n===Function to display number===\n");
Mynbr* curr = first;
if (curr) {
printf("The number is : %d", curr->nbr);
Displaynbr(first->next);
}
}
but this still displays ===Function to display number=== for each and every value in list. It is better here to use simple iteration instead of recursion:
void Displaynbr(Mynbr* first){
printf("\n===Function to display number===\n");
Mynbr* curr = first;
while (curr) {
printf("The number is : %d\n", curr->nbr);
curr = curr->next;
}
}
or using a for loop:
void Displaynbr(Mynbr* first){
printf("\n===Function to display number===\n");
Mynbr* curr;
for (curr=first; curr != NULL; curr=curr->next) {
printf("The number is : %d\n", curr->nbr);
}
}
Recursive version could even be more concise by removing a useless local variable (thanks to #sokkyoku for the hint):
void Displaynbr(Mynbr* first){
printf("\n===Function to display number===\n");
if (first) {
printf("The number is : %d", first->nbr);
Displaynbr(first->next);
}
}
If you want to change AddNumber to have a FIFO list, you need to add the new element at the end of the list. The code becomes:
Mynbr* Addnumber(Mynbr* first){
printf("\n===Function to add a number===\n");
Mynbr* head_nbr = malloc(sizeof(Mynbr));
printf("Enter a number :"); scanf("%d", &(head_nbr->nbr));
head_nbr->next = NULL;
if (first == NULL) first = head_nbr;
else {
Mynbr* last = first;
while (last->next != NULL) last = last->next;
last->next = head_nbr;
}
return first;
}
But it would be more efficient in that case to keep a pointer to last element of the list instead of browsing the list to find it.
The function has a prototype of
Mynbr* Addnumber(Mynbr* first)
It is called by Addnumber(first) in main. In main, the value pointed by the first pointer will be updated due to changes in the function. However, the first pointer itself will not be updated. i.e. the pointer will remain NULL. if it was NULL before.
To fix this you need to call the function in main like this
first = Addnumber(first);
Also, your AddNumber function needs to be fixed. You are not adding a number when for the second or larger element of the list.
Mynbr* Addnumber(Mynbr* first){
printf("\n===Function to add a number===\n");
Mynbr* head_nbr;
head_nbr = malloc(sizeof(Mynbr));
printf("Enter a number :"); scanf("%d", &(head_nbr->nbr));
if (!first)
{
head_nbr->next = NULL;
}
else
{
head_nbr->next = first;
}
return head_nbr;
}
This function adds at the start of the list as suggested by the variable head_nbr. To add at the end, you will have to make appropriate modifications.

Why my doubly linked list's C implementation creating duplicate values?

I coded for doubly linked list implementation in C. In that, after making insertion of values, i am getting duplication of values. i.e. the last value given by me duplicated in all list items.
My code is as follows
header.h
#include<stdio.h>
#include<stdlib.h>
typedef struct doubly_list
{
int id;
char *name;
struct doubly_list *next;
struct doubly_list *prev;
}node;
void insertfirst(node **,int ,char *);
void insertlast(node **,int ,char *);
doubly_list_insert.c
#include"header.h"
void insertfirst(node **head,int id,char *name)
{
node *tmp=(node *)malloc(sizeof(node));
if(NULL == tmp)
{
printf("\nMemory allocation failed\n");
exit(1);
}
tmp->id=id;
tmp->name=name;
tmp->prev=NULL;
if(*head== NULL)
{
tmp->next=NULL;
*head=tmp;
}
else
{
tmp->next=*head;
(*head)->prev=tmp;
*head=tmp;
}
}
void insertlast(node **head,int id,char *name)
{
if(*head==NULL)
{
insertfirst(head,id,name);
return;
}
node *last=*head;
node *tmp=(node *)malloc(sizeof(node));
if(NULL == tmp)
{
printf("\nMemory allocation failed\n");
exit(1);
}
tmp->id=id;
tmp->name=name;
tmp->next=NULL;
while(last->next!=NULL)
{
last=last->next;
}
last->next=tmp;
tmp->prev=last;
}
doubly_list_traverse.c
#include"header.h"
void traverse(node *head)
{
node *tmp=head;
if(head==NULL)
{
printf("\nList is empty\n");
exit(1);
}
while(tmp!=NULL)
{
printf("%d --> %s\n",tmp->id,tmp->name);
tmp=tmp->next;
}
}
And, here comes the main file,
main.c
#include"header.h"
int main()
{
int choice;
int id;
char name[15];
node *root=NULL;
system("clear");
while(1)
{
printf("\n1.Insert First\n");
printf("\n2.Insert Last\n");
printf("\n3.Traverse\n");
printf("\n4.Exit\n");
printf("\nEnter your choice : ");
scanf("%d",&choice);
switch(choice)
{
case 1:
printf("\nEnter the employee id : ");
scanf("%d",&id);
printf("\nEnter the employee name : ");
scanf("%s",name);
insertfirst(&root,id,name);
break;
case 2:
printf("\nEnter the employee id : ");
scanf("%d",&id);
printf("\nEnter the employee name : ");
scanf("%s",name);
insertlast(&root,id,name);
break;
case 3:
traverse(root);
break;
case 4:
return 0;
break;
default:
printf("\nPlease enter valid choices\n");
}
}
}
During execution its getting input from me properly,if i insert only one data either first or last.
But if i insert a second one, there comes the problem.
In my case, the id value remains the same. But the 2nd input's name value is duplicated in 1st value.
Why this is happening? Is it anything wrong in passing arguments?
When you create a new node, you set the node name by just copying the pointer to the name. You have to copy the string not the pointer. The strdup function is perfect for this:
tmp->name=strdup(name);
Remember to free the name when you free the nodes.
Edit
What happens when you call insertfirst the first time, is that the name field of the first node points to the name array in main. When you fetch the name for the second node, the contents of the array in main is updated with the new name, and since the pointer in the first node points to that array it seems like the name is duplicated.

Resources