Deleting an element from an array of structures - c

I am tasked to create an inventory management program where a user can add an item, edit an item, or delete an item. I am almost done with the code, I am just having a problem in deleting an item, particularly deleting an element from an array of structures.
I already looked for similar problems and tried the solutions suggested. The method I tried in my code was deleting an element in an array by shifting the elements next to it down by 1. The program runs and hypothetically the code should work but every time I run the program and enter the "delete an item" option, the program stops (it doesn't just exit, it says "the program stopped working" meaning I broke a rule or something). I am thinking I might be exceeding the array size or something but I can't point what exactly the problem is. Is it forbidden to shift the elements in an array of structure, or is it just my code? Please help.
This is the code for my structure.
struct details {
char name[30];
double price;
int code;
int qty;
};
details item[SIZE];
This is the main function:
int main (){
int choice; //gets the choice of user from the menu
bool condition = 1; //loops the menu
int count=0; //counts the number of items in the inventory
do{
printheader(); //prints the title of the program
printmenu(); //prints the menu (list of commands)
scanf("%d", &choice);
switch(choice){
case 1: system("cls");
AddItem(count); //function in adding record
count++; //increments every time a new item is added
system("PAUSE");
system("cls");
break;
case 2: system("cls");
EditItem(count); //function in editing a record
system("PAUSE");
system("cls");
break;
case 3: system("cls");
count = DeleteItem(count); //function in deleting a record
system("PAUSE");
system("cls");
break;
case 4: system("cls");
//ViewItem(); //function in viewing a record
system("PAUSE");
system("cls");
break;
case 5: system("cls");
DisplayInventory(count); //function in displaying inventory
system("PAUSE");
system("cls");
break;
case 6: system("cls");
SaveFile(count); //function in saving the records to a file
system("PAUSE");
system("cls");
break;
case 7: system("cls");
count = LoadFile(); //function in loading the records from a saved file
system("PAUSE");
system("cls");
break;
case 8: printf("\nThank you!");
exit(0); //ends the program
break;
default: printf("\nInvalid Input!\n");
getch();
system("cls");
}
}while(condition = 1);
return 0;
}
This is the DeleteItem() function. It accepts n which is the number of items/records.
int DeleteItem (int n){
printheader();
int i=0, code, pos;
bool cont = true;
printf("\nEnter the code of the item you want to delete: ");
scanf("%d", code);
do{
if(code==item[i].code){
for (pos=i; pos<(n-1); pos++){
// item[pos].name = item[pos+1].name; //this basically deletes the i'th element and shifts the remaining ones
item[pos].price = item[pos+1].price;
item[pos].code = item[pos+1].code;
item[pos].qty = item[pos+1].qty;
}
printf("\nItem deleted!");
cont = false; //loop ends once the input of the user matches the data in the inventory
}
if(i==n){
printf("\nCode not found!\n\n");
cont = false; //loop ends when there are no matches
}
i++;
}while(cont);
}
When the delete an item option is entered in the program, the program asks the user for the code of the item. The program then scans the array of structures for an an element (item[i].code) that matches the code. Ideally, the program should delete the element and shift the other elements if the code matches. However, what happens is the program crashes and stops. I need help to spot where the problem is. Thank you very much!
EDIT
DeleteItem function:
int DeleteItem (int n){
printheader();
int i=0, code, pos;
//bool cont = true;
printf("\nEnter the code of the item you want to delete: ");
scanf("%d", code);
while(i<n){
if(code==item[i].code){
for (pos=i; pos<(n-1); pos++){
item[pos] = item[pos+1];
}
printf("\nItem deleted!");
break;; //loop ends once the input of the user matches the data in the inventory
}
i++;
if(i==(n-1)){
printf("\nCode not found!\n\n");
break;; //loop ends when there are no matches
}
}
return (n-1);
}
I'm a total newbie with C so I'm really sorry if you see some problematic codes. I'm working on it.

One problem is that your check for i == n is done after you have indexed the array using i. To fix that you should increment i before the check. Like:
i++; // Increment first
if(i==n){ // then check
printf("\nCode not found!\n\n");
cont = false; //loop ends when there are no matches
}
Another problem is that you don't handle the case where n is zero. In general I think that a while(i < n) { ... }; is a better approach than a do { ...} while(...);.
Also notice this code (currently commented out) is wrong:
// item[pos].name = item[pos+1].name;
You can't copy a string using assignment (i.e. =). You'll need to use strcpy
Also I can't see any update of count when an item is deleted. I guess that's bug... I would assume that count has to be decremented.
Finally, I don't see the function returning any value. That's also a bug since you define the function to return an int.
A note...
Using a flag like cont to terminate the while loop will work fine and is therefore not a bug. However, you don't really need a flag. You could do using either a break like:
do{
...
...
if(i==n){
printf("\nCode not found!\n\n");
break; //loop ends when there are no matches
}
i++;
}while(1);
or simply do a return as the function has nothing more to do.
EDIT
OP has posted a second revision of the code. This edit address that second revision.
One problem with the second revision is that the code always return n-1. That is done even when the "code" wasn't found. That's a bug.
The if(i==(n-1)){ is also wrong as it means item number n-i will never be tested.
Try something like this instead:
int DeleteItem (int n){
printheader();
int i=0, code, pos;
printf("\nEnter the code of the item you want to delete: ");
scanf("%d", code);
while(i<n){
if(code==item[i].code){
for (pos=i; pos<(n-1); pos++){
item[pos] = item[pos+1];
}
printf("\nItem deleted!");
return n-1; // End the function and return n-1 as an item was deleted
}
i++;
}
printf("\nCode not found!\n\n");
return n; // End the function and return n as no item was deleted
}
BTW: You should always check the value returned by scanf

Related

C Loop until the condition is met problem

I want to write a loop that runs until the user enters a number greater than 10, but I have to do something wrong because it creates an infinite loop.
int main()
{
int a;
printf("Enter 'a' value (min 10): ");
scanf("%d",&a);
for(int i=0;a<10;i++){
printf("Enter value>10");
i++;
printf("%d",&a);
}
printf("Result:%d",a+a-2+a-4+a-6+a-8+a-10);
return 0;
}
You mix an index that does not make sense. Also you print the memory address of variable instead of its value, not sure it is what you wanted?
Code partially corrected (because I don't know what is your ultimate goal):
#include <stdio.h>
int main()
{
int a;
do {
printf("Enter 'a' value (min 10): ");
scanf("%d",&a);
printf("\na: %d\n",a);
} while (a <= 10);
printf("Result:%d\n",a+a-2+a-4+a-6+a-8+a-10);
return 0;
}
ps: \n is line return and added do while which is what you want when you want to execute a loop at least once.
Have a look at your for-loop: you let i start at zero, you continue until a is not smaller than ten anymore, but it's not the value of a you need to check, it's the one of i.
In top of that, you are doing a i++ within your for-loop, while this is already covered in the definition of the for-loop.
I think this is the code that you are looking for: See comments
#include <stdio.h>
int main()
{
int a, ok = 0, end_of_input = 0;
do {
printf("Please input an integer value (min. 10): ");
fflush(stdout); // So the user can see the above line!
switch(scanf("%d",&a)) {
case EOF: // End of input - Give up!
end_of_input = 1;
break;
case 1: // Got a number - Check it!
if (a < 10)
{
ok = 1;
} else {
printf("%d - Not appropriate input. Please try again.\n\n",a);
}
break;
default: // Summat else - "eat" the input to the next line
scanf("%*[^\n]\n"); // "eats" the rest of the line in the buffer w/o assignment
break;
}
} while (end_of_input == 0 || ok == 0);
if (ok) { // User entered a valid number
printf("Got a that is smaller than ten %d\n", d);
} else { // We have ran out of input
printf("See you want to leave us :-(\n");
}
return 0;
}
I am not sure what you are trying to achieve but one problem that I found in your logic is you prompting user for input outside the loop. So whenever you enter number less than 10 it always goes in infinite iteration.
Try following code, with scanf inside loop
int main()
{
int a;
printf("Enter 'a' value (min 10): ");
scanf("%d",&a);
int i=0;
for(;a<10;){
printf("Enter value>10");
scanf("%d",&a);
printf("%d",a);
i++;
}
printf("Result:%d",a+a-2+a-4+a-6+a-8+a-10);
return 0;
}

Basic addition loop c

I'm trying to write a code which adds a value - say X - to a user entered int, and continues to allow the user to add further int values to 'X+all previously entered int values' until a value of 21 or greater is reached - where the code exits the loop. I thought it would be a simple case of value=value+X but I'm going wrong somewhere...
void additionFunction()
{
int j=0;
int tot;
//tot=cat.firstCard+cat.secondCard; is the actual tot value but for simplicity;
tot=5;
for(j=0; j+tot<22; j=j+tot)
{
printf("Enter next card\n");
scanf("%d",&j);
}
}
I know this is a very simple question but I'm stuck as to what else to try. It was originally implemented in a if,do,switch loop in the shortened form;
if(cat.firstCard!=11 && cat.secondCard!=11)
{
do
{
switch(tot+j>=4 && tot+j<=8)
{
printf("Hit\nEnter next card\n");
scanf("%d",&j);
break;
}
switch(tot+j==9 && (cat.dealersCard==2 || (cat.dealersCard>=7 && cat.dealersCard<=11)))
{
printf("Hit\nEnter next card\n");
scanf("%d",&j);
break;
}
...
switch(tot+j>=17 && tot+j<=21)
{
printf("Stand\n");
j=50;
break;
}
switch(tot+j>21)
{
printf("Bust\n");
j=50;
break;
}
}while(j!=50);
}
else //etc.
This method didn't work either. I know this is simple but I can't find the answer anywhere. It would be great if you could answer for the second case but any answer is appreciated!
only use stdio.h, no global variables
You need to increment tot rather than j. I think it could be clearer like this:
void additionFunction(void)
{
int tot = 5;
while (tot < 22)
{
int j;
printf("Enter next card\n");
if (scanf("%d", &j) != 1)
break;
tot += j;
printf("Read: %d - total = %d\n", j, tot);
}
}
I've kept your variable names, but they could be improved (tot ⟶ total; j ⟶ value, perhaps). I added the second printf() to identify what's going on better (but there's room to improve that, too, though a debugger could also be used to see the information). I suspect you will need to do more work in the loop, or return a value from the function, but this is OK as an MCVE (Minimal, Complete, Verifiable Example).
The problem is you are resetting j every time in the loop with user's input with this line - scanf("%d",&j);
This should fix it, by assigning input into another variable and add it to j.
int j=0,input,tot=5;
for(j=0; j+tot<22; j=j+input)
{
printf("j=%d tot=%d\n",j,tot);
printf("Enter next card\n");
scanf("%d",&input);
}

free() loop, is triggering a break point and seems to not free the element

I have been working on an assignment which is pretty much done, and all I need to do is free the the double pointer allocated memory, but with the loop when I go through the loop it triggers a break point and seems to not clear it all I'm not sure whats triggering it.
Context: the Create Data function is basically a function that returns a malloc.
int main(void){
int i;
static STUDENT** records;
static float averageTotal[SIZE];
createData();
records = calloc(3, sizeof(STUDENT*));
for (i = 0; i < 3; i++){
records[i] = createData();
}
menu(records, userinput, &averageTotal[0]);
int c;
for (c = 0; c < 3; c++){
free(records[c]);
}
free(records);
return 0;
}
STUDENT* createData()
{
STUDENT* result;
result = malloc(3*sizeof(STUDENT*));
return result;
}
EDIT: added Menu for Context
void menu(STUDENT* records, int user_size, float* averageTotal[]){
int menuV = 0;
do{
int userinput;
int i;
static int counter = 0;
printf(" **********************************\n");
printf(" * MENU *\n");
printf(" * 1. Add Student *\n");
printf(" * 2. Display all student records*\n");
printf(" * 3. Quit *\n");
printf(" **********************************\n");
scanf_s("%d%*[^\n]", &userinput); '\n' == getchar();
switch (userinput){
// switch statement with loops.
case 1:do
{
addStudent(records, &counter, user_size);
printf("Add another record? 1(y) 2(n)\n");
scanf_s("%d%*[^\n]", &userinput); '\n' == getchar();
} while (userinput == 1);
break;
case 2:
do{
displayStudent(records, user_size);
printf("Display again? 1(y) 2(n)\n");
scanf_s("%d%*[^\n]", &userinput); '\n' == getchar();
} while (userinput == 1);
break;
case 3:
menuV++;
break;
}
} while (menuV == 0);
}
Edit: added addStudent Function for Context
void addStudent(STUDENT* records[], int* counter, int user_size)
{ // A simple function that lets the user add values to the struct. The counter keeps track and changes the element.
printf("Student: %d", (*counter+1));
printf(" of 3\n");
printf("Enter name:\n");
fgets(records[*counter]->name, 40, stdin);
printf("Enter Exam 1 Score: \n");
scanf_s("%f", &records[*counter]->exam1);
printf("Enter Exam 2 Score: \n");
scanf_s("%f", &records[*counter]->exam2);
printf("Name:%s",records[*counter]->name);
printf("Exam 1:%0.2f\n", records[*counter]->exam1);
printf("Exam 2:%0.2f\n", records[*counter]->exam2);
(*counter)++;
}
There's lots of things wrong here. You seem to have a weak grasp of pointers and dereference.
This line:
static STUDENT** records;
Creates a variable that's a pointer to a pointer to a datatype.
Ideally you should change the declaration to something that's idiomatic and easier to understand without thinking. Something like:
records = calloc(3, sizeof(*records));
In the function CreateData() you're assigning the members of records to a pointer to 3 pointers.
This line:
result = malloc(3 * sizeof(*STUDENT));
Should read:
result = malloc(3 * sizeof(STUDENT));
. The seconds allocates memory for three times the length of the datatype STUDENT. (What you want).
Moving on --
Here is the declaration/definition of the function menu.
void menu(STUDENT* records, int user_size, float* averageTotal[])
And here's how you've used it in your code:
menu(records, userinput, &averageTotal[0]);
the first parameter, records, was defined as a pointer-to-pointer-to-STUDENT. But the definition of menu expects only a pointer-to-STUDENT.
Looking at the rest of the code, it's the definition that's incorrect and not the function call.
Same function:
void menu(STUDENT* records, int user_size, float* averageTotal[])
menu expects a pointer-to-pointer-to-float for its third parameter. But you provided a pointer-to-index in the call here:
menu(records, userinput, &averageTotal[0]);
Without reading much further, it's clear you need to understand pointers better(or stop typing so fast and understand what you're writing!).
Finally, an actual nit-pick. The function CreateData() should be removed and its use should be replaced by function calls to calloc/malloc() directly.

remembering the value of a counter

#include <stdio.h>
int main()
{
int input, counter,value;
int ABC[3];
counter = 0;
scanf("%d", &input);
switch (input)
{
case 1:
if (counter >=4)
{
printf("Error\n");
}
scanf("%d", &value);
ABC[counter]= value;
printf("ABC[%d] is %d \n", counter, ABC[counter]);
counter++;
main();
break;
case 2: //do anything
main();
break;
default:
printf("a is anything\n");
break;
}
return 0;
}
I want to put in array ABC every time i choose case 1 a value, until array ABC is full. My problem is, that i can only enter in this programm values into ABC[0] . Is there any way, to remember the value of counter, so it's not always 0? Maybe using if-statement? But how to formulate an if-statement in this programm, which is only once in the beginning true?
But ABC should also be allowed to have empty space
After "counter++" you are re-calling your "main" function, that reinitializes your counter to 0. You should use a loop:
int counter = 0;
do
{
// Your scanf goes here
switch(scanf_result)
{
// Add your case labels here
default: // Incorrect input? Let's start again!
continue;
};
counter++;
}
while(counter < 3);
i think that declaring counter outside the main function, would make it global scope.
in this way everytime you call main(); you reset the value to 0.
so write int counter = 0 before the main declaration, at row number 2.

Using getNum(); Properly and Infinite Loop Problems

Just having a few kinks in this assignment I'm trying to do. Basically I need to have a menu, 4 options, two of them accept input from user as the form of a base number and an exponent. The third one outputs the answer of the base raise to the power and then the fourth just exits the program.
I'm having trouble obtaining the users input via getNum(); I'm not too sure how to use it properly. Just looking on some tips on how to make my code work a little better.
Looking for Help:
Accepting user input from two different functions and using it to
output an answer
Working out the infinite loop problem when selecting menu option
Loop back program to main menu after each function is done and only
exit program when menu option 4 is selected
int main(void)
{
int option = 0;
do
{
loadMenu();
while (option<1 || option>4)
{
printf("\nChoose an option between 1 and 4:");
option = getNum();
while (getNum() != '\n');
}
switch (option)
{
case 1:
baseChange(); //Gets base number
break;
case 2:
powerChange(); //Gets exponent
break;
case 3:
calcMath(); //Calculates the answer
break;
default:
break;
}
}
while (option != 4);
printf("Goodbye!\n");
}
void loadMenu() //Menu choices
{
printf("Power Menu:\n" );
printf(" 1. Change base\n");
printf(" 2. Change exponent\n");
printf(" 3. Calculate\n");
printf(" 4. Exit\n");
printf("Option?\n");
}
int baseChange(int base)
{
printf("What is your base?: ");
base = getNum();
while (getNum() != '\n');
return base;
}
int powerChange(int power)
{
printf("What is the power?: ");
power = getNum();
while (getNum() != '\n');
return power;
}
int calcMath(int base, int power)
{
int index = 0;
long answer = 1.00;
for(index = 1; index <= power; index++) answer = answer * base;
{
printf("%d raised to the power of %d is %ld.\n\n", base, power, answer);
}
return answer;
}
I'm having trouble obtaining the users input via getNum(); I'm not too
sure how to use it properly.
You haven't told us anything about this function; it's not part of the C standard.
Just looking on some tips on how to make my code work a little better. Looking for Help:
I think it's a little early for that. Put more effort into solving your problems, and then come back if you have specific questions. More like this one:
Working out the infinite loop problem when selecting menu option
Look at what your program does with option the second time through the loop.
Please Declare the getnum() function before main() like below;
/* declare getnum() prior to its first use */
float getnum(void)
{
float x;
printf("Enter a number: ");
scanf("%f", &x);
return x;
}

Resources