Array of structs not updating in C project - c

I am currently trying to make a Student Database system for my introductory C class. I am working on the feature of adding new students to the database so that it can be displayed. However, whenever i try to print out each individual feature of a struct in the array, it does not return what I intended. Floats become 0 and strings are not visible.
For context, here is the code used to display each element of the array
void displayStudents() {
printf("\t\tList of Student Information\n");
printf("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n ");
printf("|No.| \t \t \t Name \t \t \t |\t Major \t\t| GPA |");
printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n");
int i;
for (i = 0; i < (currentEntries); i++) {
printf("%s",listOfStudents[currentEntries].name);
printf("%f",listOfStudents[currentEntries].gpa);
printf("%s",listOfStudents[currentEntries].major);
// these print statemnts above print "", 0, and "" respectively.
}
}
Here are the functions used to add new students into the array
typedef struct Student {
float gpa;
char major[100];
char name[100];
} student;
student createNewStudent(char sname[100], float gpa, char smajor[100]) {
student newstudent;
newstudent.gpa = gpa;
strcpy(newstudent.name,sname);
strcpy(newstudent.major,smajor);
return newstudent;
}
void addNewStudents() {
char name[100];
char major[100];
float gpa;
if (currentEntries > 20) {
currentEntries = 20;
printf("Database is full");
return;
}
printf("\t\t Insert Student Information \n");
printf("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \n ");
printf("Name: \t ");
scanf("%[^\n]s",name);
printf("\nMajor\t: ");
scanf(" %[^\n]s",major);
printf("\nGPA\t:");
scanf(" %f", &gpa);
listOfStudents[currentEntries] = createNewStudent(name,gpa,major);
currentEntries++;
}
and here is how theyre called in main()
scanf("%d", &selection);
switch(selection) {
case 1:
displayStudents();
promptKeyPress(&inMenu);
break;
case 2:
addNewStudents();
promptKeyPress(&inMenu);
break;
default:
programRunning = false;
break;
also, both currentEntries and listOfStudents are defined as global variables
int currentEntries = 0;
student listOfStudents[20];
So, my question is, how should I tackle this problem so that the displayStudents function would print the correct values of my input (the student name, major and gpa)?
Any help would be appreciated. Thanks!

I think the problem is here:
int i;
for (i = 0; i < (currentEntries); i++) {
printf("%s",listOfStudents[currentEntries].name);
printf("%f",listOfStudents[currentEntries].gpa);
printf("%s",listOfStudents[currentEntries].major);
// these print statemnts above print "", 0, and "" respectively.
}
The index is wrong. Replace currentEntries inside the loop with i:
int i;
for (i = 0; i < (currentEntries); i++) {
printf("%s",listOfStudents[i].name);
printf("%f",listOfStudents[i].gpa);
printf("%s",listOfStudents[i].major);
// these print statemnts above print "", 0, and "" respectively.
}
As well noted in the comments section, you should also fix the following block:
if (currentEntries > 20) {
currentEntries = 20;
printf("Database is full");
return;
}
To something like:
if (currentEntries == 20) {
printf("Database is full");
return;
}

Related

Beginner in C: Can't properly printf first and last element in double array?

I'm trying to display a Wish List on the command line. The user enters the cost of the item, the level of priority (1-3), and whether or not it has financing options (y/n). The inputted values are put in multiple arrays. After the user enters all their values, they're displayed in a table at the end.
Everything in my code works fine except when I try to printf the user inputed cost values (double itemCosts[numOfItems];) in the table. The first and last element don't print properly, even when I input the same price (6225.88) for all of them. The last element is just 0.000000. See included pic of table output.
I tried debugging the issue by separating the cost-related loops and compiling/running them as another file and the costs display correctly...so I'm thinking the bug is somewhere else, but I can't find it.
#define MAX_ITEMS 10
#include <stdio.h>
int main()
{
const double MIN_INCOME = 500, MAX_INCOME = 400000;
int numOfItems;
double netIncome, itemTotal;
double itemCosts[numOfItems];
int itemPriors[numOfItems];
char itemFinOps[numOfItems];
printf("+--------------------------+\n");
printf("+ Wish List Forecaster |\n");
printf("+--------------------------+\n\n");
// Prompt for net monthly income
do
{
printf("Enter your monthly NET income: $");
scanf("%lf", &netIncome);
if (netIncome < MIN_INCOME)
{
printf("ERROR: You must have a consistent monthly income of at least $500.00\n\n");
}
else if (netIncome > MAX_INCOME)
{
printf("ERROR: Liar! I'll believe you if you enter a value no more than $400000.00\n\n");
}
} while (!(netIncome >= MIN_INCOME && netIncome <= MAX_INCOME));
printf("\n");
// Prompt for # of wish list items
do
{
printf("How many wish list items do you want to forecast?: ");
scanf("%d", &numOfItems);
if (!(numOfItems > 0 && numOfItems <= MAX_ITEMS))
{
printf("ERROR: List is restricted to between 1 and 10 items.\n\n");
}
printf("\n");
} while (!(numOfItems > 0 && numOfItems <= MAX_ITEMS));
// Store wish list item details
for (int i = 0; i < numOfItems; i++)
{
printf("Item-%d Details:\n", i + 1);
do //////////////// ******** PROMPT COST ********** //////////
{
printf("Item cost: $");
scanf("%lf", &itemCosts[i]);
if (!(itemCosts[i] >= (double)100))
{
printf(" ERROR: Cost must be at least $100.00\n");
}
} while (!(itemCosts[i] >= (double)100));
do // prompt priority
{
printf("How important is it to you? [1=must have, 2=important, 3=want]: ");
scanf("%d", &itemPriors[i]);
if (!(itemPriors[i] >= 1 && itemPriors[i] <= 3))
{
printf(" ERROR: Value must be between 1 and 3\n");
}
} while (!(itemPriors[i] >= 1 && itemPriors[i] <= 3));
do // prompt finance options
{
printf("Does this item have financing options? [y/n]: ");
scanf(" %c", &itemFinOps[i]);
if (!(itemFinOps[i] == 'y' || itemFinOps[i] == 'n'))
{
printf(" ERROR: Must be a lowercase 'y' or 'n'\n");
}
} while (!(itemFinOps[i] == 'y' || itemFinOps[i] == 'n'));
printf("\n");
}
///////// display summary of item details in TABLE //////////
printf("Item Priority Financed Cost\n");
printf("---- -------- -------- -----------\n");
for (int j = 0; j < numOfItems; j++)
{
printf(" %d %d %c %lf\n", j + 1, itemPriors[j], itemFinOps[j], itemCosts[j]);
itemTotal += itemCosts[j];
}
return 0;
}
int numOfItems;
double netIncome, itemTotal;
double itemCosts[numOfItems];
int itemPriors[numOfItems];
char itemFinOps[numOfItems];
It is undefined behaviour as your numOfItems is not inilized. In C table will not grow or shrink to the size when you change this variable
Change to:
double itemCosts[MAX_ITEMS];
int itemPriors[MAX_ITEM];
char itemFinOps[MAX_ITEM];
Always check the result of scanf. Exmaple:
if(scanf("%lf", &netIncome) != 1){ /* handle error*/}
As Vlad from Moscow and 0___________ said, you cannot define an array using a not initialised variable for the number of its elements. You can define the variables as
double *itemCosts;
int *itemPriors;
char *itemFinOps;
and after the variable numOfItems is given a value, you dynamically allocate memory as follows:
itemCosts = (double*) malloc(numOfItems * sizeof(double));
itemPriors = (int*) malloc(numOfItems * sizeof(int));
itemFinOps = (char*) malloc(numOfItems * sizeof(char));
or
itemCosts = (double*) calloc(numOfItems, sizeof(double));
itemPriors = (int*) calloc(numOfItems, sizeof(int));
itemFinOps = (char*) calloc(numOfItems, sizeof(char));
calloc initialises all elements of array to 0
At the end you must free the allocated memory:
free(itemCosts);
free(itemPriors);
free(itemFinOps);

My variables changing after moving to the next function

I have a problem in my homework that i cannot seem to solve, The task it to create some sort of tool for a city to handle families information, after I add a family successfuly in the function "add_new_family" and move to "add_new_child" while working with the debugger i've noticed that just by moving up to first or second line of the function my original structure variables are changing randomly, the paretns name changes to garbage and if i move on with the function and actually try to add another child, it saves the information on the parents name and such, i cant seem to figure out the cause of this problem.
Please excuse my memory allocation casting if it bothers anyone, I've read before in stackoverflow that it might not be necessary but my professor insist.
There might be other crucial problems with my code, im a first year student, although it would be appreciated if you note it, but my main focus is just figuring out the cause of those random changes after I send my struct to the "add_new_child" function, I add an image of before and after to make clear of whats happening picture
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#define SIZE 10000;
typedef struct person {
char* name;
int gender;//1-female, 0-male
}Person;
typedef struct {
char* family_name;
Person* mother, *father; // parents' names
Person* *children_list;// list of the children in this family
unsigned child_list_size; // size of child_list array
unsigned current_listChild_size;
}Family;
typedef struct {
Family** list;
unsigned current_listFamily_size; // current size of family
}ListFamilys;
ListFamilys* new_city(ListFamilys* s);
void add_new_family(ListFamilys* s, char* fname);
void add_new_child(ListFamilys* s, char* surname);
void main()
{
ListFamilys* list = (ListFamilys*)malloc(1 * sizeof(ListFamilys));
assert(list);
list = new_city(list);
add_new_family(list, "james");
add_new_child(list, "james");
system("pause");
}
ListFamilys* new_city(ListFamilys* s)
{
assert(s->list = (Family**)calloc(1, sizeof(Family*)));
s->current_listFamily_size = 0;
return s;
}
void add_new_family(ListFamilys* s, char* fname)
{
unsigned int size = SIZE;
if (s->current_listFamily_size >= size)
{
printf("\nAccording to our database, it will not be possible to add another family in Angola, as the city reached its capacity");
return;
}
for (unsigned int i = 0; i < s->current_listFamily_size; i++)
{
if (strcmp(s->list[i]->family_name, fname) == 0)
{
printf("\nERROR 1: A family with the surname of %s already exist in the database", fname);
return;
}
}
s->current_listFamily_size += 1;
/*assert(s = (ListFamilys*)realloc(s, s->current_listFamily_size * sizeof(ListFamilys)));
assert(s->list = (Family**)calloc(1 , sizeof(Family*)));*/
assert(s->list[s->current_listFamily_size - 1] = (Family*)calloc(1, sizeof(Family)));
assert(s->list[s->current_listFamily_size - 1]->father = (Person*)malloc(1 * sizeof(Person)));
assert(s->list[s->current_listFamily_size - 1]->mother = (Person*)calloc(1, sizeof(Person)));
int numOfParents = 0;
printf("Creating new data for the [%s] family, please provide the number of parents (1/2): ", fname);
scanf("%d", &numOfParents);
s->list[s->current_listFamily_size - 1]->family_name = fname;
char tmpname[100];
char tmpname1[100];
int tmpgender = 0;
int tmpgender1 = 0;
switch (numOfParents)
{
case 0:
printf("\nERROR 2: A newly created family cannot contain no parents at all or more than 2 parents, please try again.");
return;
case 1:
printf("\nPlease provide the name of the parent No.1: ");
scanf("%s", tmpname);
printf("\nPlease provide the gender of parent No.1 [1 for female / 0 for male]: ");
scanf("%d", &tmpgender);
if (tmpgender == 0)
{
s->list[s->current_listFamily_size - 1]->father->gender = tmpgender;
s->list[s->current_listFamily_size - 1]->father->name = tmpname;
s->list[s->current_listFamily_size - 1]->mother = NULL;
}
else
{
s->list[s->current_listFamily_size - 1]->mother->gender = tmpgender;
s->list[s->current_listFamily_size - 1]->mother->name = tmpname;
s->list[s->current_listFamily_size - 1]->father = NULL;
}
break;
case 2:
printf("\nPlease provide the name of the parent No.1:");
scanf(" %s", tmpname);
printf("\nPlease provide the gender of parent No.1 [1 for female / 0 for male]: ");
scanf("%d", &tmpgender);
printf("\nPlease provide the name of the parent No.2:");
scanf(" %s", tmpname1);
printf("\nPlease provide the gender of parent No.2 [1 for female / 0 for male]: ");
scanf("%d", &tmpgender1);
if (tmpgender == 0)
{
s->list[s->current_listFamily_size - 1]->father->gender = tmpgender;
s->list[s->current_listFamily_size - 1]->father->name = tmpname;
s->list[s->current_listFamily_size - 1]->mother->gender = tmpgender1;
s->list[s->current_listFamily_size - 1]->mother->name = tmpname1;
}
else
{
s->list[s->current_listFamily_size - 1]->mother->gender = tmpgender;
s->list[s->current_listFamily_size - 1]->mother->name = tmpname;
s->list[s->current_listFamily_size - 1]->father->gender = tmpgender1;
s->list[s->current_listFamily_size - 1]->father->name = tmpname1;
}
break;
default:
printf("\nERROR 2: A newly created family cannot contain no parents at all or more than 2 parents, please try again.");
return;
}
int numOfChildren = 0;
printf("\nPlease provide the number of children in the [%s] family: ", fname);
scanf("%d", &numOfChildren);
if (numOfChildren == 0)
{
s->list[s->current_listFamily_size - 1]->children_list = NULL;
s->list[s->current_listFamily_size - 1]->child_list_size = 0;
s->list[s->current_listFamily_size - 1]->current_listChild_size = 0;
}
else
{
assert(s->list[s->current_listFamily_size - 1]->children_list = (Person**)malloc((numOfChildren + 2) * sizeof(Person*)));
s->list[s->current_listFamily_size - 1]->child_list_size = numOfChildren + 2;
for (int i = 0; i < numOfChildren; i++)
{
char tmpname2[100];
tmpgender = 0;
printf("\nPlease provide the name of the child No.%d:", i+1);
scanf(" %s", tmpname2);
printf("\nPlease provide the gender of child No.%d [1 for female / 0 for male]: ", i+1);
scanf("%d", &tmpgender);
assert(s->list[s->current_listFamily_size - 1]->children_list[i] = (Person*)malloc(1 * sizeof(Person)));
s->list[s->current_listFamily_size - 1]->children_list[i]->gender = tmpgender;
s->list[s->current_listFamily_size - 1]->children_list[i]->name = tmpname2;
}
for (int i = 0; i < 2; i++)
{
s->list[s->current_listFamily_size - 1]->children_list[numOfChildren + i] = NULL;
}
s->list[s->current_listFamily_size - 1]->current_listChild_size = numOfChildren;
}
printf("\nFamily was added to the database SUCCESSFULY.");
return;
}
void add_new_child(ListFamilys* s, char* surname)
{
int truth = 0;
unsigned int index = 0;
for (unsigned int i = 0; i < s->current_listFamily_size; i++)
{
if (strcmp(s->list[i]->family_name , surname) == 0)
{
index = i;
truth = 1;
}
}
if (truth == 0)
{
printf("\nERROR 3: Family wasnt found in the database, try again");
return;
}
char tmpname4[100];
int gender = 0;
if (s->list[index]->current_listChild_size < s->list[index]->child_list_size)
{
printf("\nPlease provide the name of the child: ");
scanf(" %s", tmpname4);
printf("\nPlease provide the gender of child [1 for female / 0 for male]: ");
scanf("%d", &gender);
assert(s->list[index]->children_list[s->list[index]->current_listChild_size] = (Person*)malloc(1 * sizeof(Person)));
s->list[index]->children_list[s->list[index]->current_listChild_size]->gender = gender;
s->list[index]->children_list[s->list[index]->current_listChild_size]->name = tmpname4;
}
else
{
s->list[index]->child_list_size += 1;
s->list[index]->current_listChild_size += 1;
assert(s->list[index]->children_list = (Person**)malloc(1 * sizeof(Person*)));
printf("\nPlease provide the name of the child: ");
scanf(" %s", tmpname4);
printf("\nPlease provide the gender of child [1 for female / 0 for male]: ");
scanf("%d", &gender);
s->list[index]->children_list[s->list[index]->current_listChild_size] = (Person*)malloc(1 * sizeof(Person));
s->list[index]->children_list[s->list[index]->current_listChild_size]->gender = gender;
s->list[index]->children_list[s->list[index]->current_listChild_size]->name = tmpname4;
}
printf("\nChildren information was updated SUCCESSFULY");
return;
}
You're setting the name member to a pointer to a local variable, which becomes invalid when the function returns. You need to make a dynamic copy of the string.
s->list[s->current_listFamily_size - 1]->father->name = strdup(tmpname);
The same thing for the family name, mother's name and all the children names.
As already pointed out in another answer, your string handling is full of bugs as you save pointers to variables instead actually creating a string copy (i.e. strcpy).
Another issue is s->list. It seems you want it to be a pointer to an array of pointers because you access it like: s->list[s->current_listFamily_size - 1]->...
But you never allocate more than one pointer. Here:
s->list = (Family**)calloc(1, sizeof(Family*))
In other words - the only valid index is zero.
s->list[0]->... // Is OK
s->list[1]->... // Is very bad
You need to add more pointers when you add a Family

Can't Print " * " in C

for some reason I am unable to print out "* " in my program. I want to print out * if the condition is met. the condition is if the rainfall that day is greater than the average.
under the mean column, i am getting weird symbols. i tried debugging to decimals and get -112 for ascii. i dont understand but i tried researching!
I am new to C so please be understanding. Just learned like 2 days ago!!.
Here is my code :
//Assignment one 9/20/2018
//Anthony Lomaistro and David Luong
//luongd5#student.lasalle.edu
//lomaistroa1#student.lasalle.edu
#include <stdio.h>
main() {
int n = 0; //counters for the loops
int x = 0; // counter for the loops
int counter = 0; // counter whenever i need to keep track of increments
int days_input = 0; // how many days we are keeping track of
int number_of_days = 0;
double rainfall_input = 0;
double rainfall_amount = 0; // how much rainfall per day
double rainfall_average = 0; // average of rainfall
double rainfall_total = 0;
double rainfall_counter = 0; // count how many days it rained above the average
int correct = 0;
double rainfall_array[50];//array that contains the user input
char rainfall_condition[50]; // array that contains the *
double sum = 0;
double average = 0;
double percent_days = 0; //rainfall % above average
double valid = 0;
double valid2 = 0;
printf("Welcome to Lomaistro and Luong's Rainfall Program \n");
printf("How many days would you like to keep track of? Please enter a value between 1 and 50: #%d:", n + 1);
//printf(number_of_days);
while (valid == 0) {
scanf_s("%d", &number_of_days);
if ((number_of_days > 50) || (number_of_days <= 0)) { // come back to this, this doesnt do anytihng
printf("Invalid value, please enter in a day that is between 1 and 50 \n");
}
else {
valid = 1;
}
}
//getting the user to enter in the rainfall
for (x = 0; x < number_of_days; x = x + 1) {
valid2 = 0;
while (valid2 == 0) {
printf("Enter rainfall (in inches): ");
scanf_s("%lf", &rainfall_amount);
if ((rainfall_amount >= 0) && (rainfall_amount <= 10)) {
valid2 = 1;
rainfall_array[x] = rainfall_amount;
}
else
printf("Please enter in a valid rainfall amount between 1 and 10");
}
}
//computing average
for (n = 0; n < number_of_days; n = n + 1) {
sum += rainfall_array[n];
average = sum / number_of_days;
}
printf("Mean daily rainfall(in inches): %lf", average);
//seeing if the * should be the array or not
for (n = 0; n < number_of_days; n = n + 1) {
if (rainfall_array[n] > average) {
rainfall_condition[n] = "*";
rainfall_counter = rainfall_counter + 1;
}
else
rainfall_condition[n] = "empty";
}
// print out the thing
printf("\n Days \t Amount \t >Mean \n");
printf("==============================\n");
for (n = 0; n < number_of_days; n = n + 1) {
printf("%d \t %f \t %c \n", n + 1, rainfall_array[n], rainfall_condition[n]);
}
percent_days = rainfall_counter / number_of_days;
percent_days = percent_days * 100;
printf("Number of days that rained above average : %f \n", rainfall_counter);
printf("Percentage of days that rained above average: %f%% \n", percent_days);
system("pause");
}
rainfall_condition is an array of char, but you're putting a pointer to a string literal in there when you use "*". Use '*' for a character literal instead. To be more specific, this line:
rainfall_condition[n] = "*";
Should be:
rainfall_condition[n] = '*';
Turn some warnings on in your compiler; the first line (what you have now) isn't valid C code and you should be seeing a diagnostic message to that effect.
Edit: now that I've read more of the code, it appears you want either a * or an empty in that column? In that case you want to change the variable declaration to:
char *rainfall_condition[50]; // array that contains the *
And then change the print statement to:
printf("%d \t %f \t %s \n", n + 1, rainfall_array[n], rainfall_condition[n]);

Code is not working (C)

I want to calculate the wages with struct and arrays but it is not working. You will understand the exercise better when you see the code. For some reason if in Wage and Days_Worked I enter a number(100 and 2)
Wagered[i].Gross_Wage = Wagered[i].Wage * Wagered[i].Days_Worked; Won't give me 200 but something else. Generally the programm won't work and I am trying to find the reason.
#include <stdio.h>
struct User
{
char First_Name[25];
char Last_Name[25];
int Wage, Days_Worked;
int Tax;
int Wage_Booking;
int Net_Wage;
int Gross_Wage;
};
int main()
{
int i;
int Wage_Summary = 0;
struct User Wagered[1];
for(i = 0; i < 1; i++)
{
/*printf("First Name: ");
scanf("%s", &Wagered[i].First_Name);
printf("\n");
printf("Last Name: ");
scanf("%s", &Wagered[i].Last_Name);
printf("\n");*/
printf("Wage: ");
scanf("%d", &Wagered[i].Wage);
printf("\n");
printf("Days He Worked: ");
scanf("%d", &Wagered[i].Days_Worked);
printf("\n");
Wagered[i].Gross_Wage = Wagered[i].Wage * Wagered[i].Days_Worked;
Wagered[i].Wage_Booking = Wagered[i].Gross_Wage * 0.2;
Wagered[i].Tax = (Wagered[i].Gross_Wage - Wagered[i].Wage_Booking) * 0.05;
Wagered[i].Net_Wage = Wagered[i].Gross_Wage - Wagered[i].Wage_Booking - Wagered[i].Tax;
Wage_Summary += Wagered[i].Net_Wage;
}
printf("The Summary of the Gross Wages is: %d\n", Wagered[i].Gross_Wage);
return 0;
}
This statement :
printf("The Summary of the Gross Wages is: %d\n", Wagered[i].Gross_Wage);
is outside your for loop. Therefore it will be executed when i has value 1, thus accessing Wagered[1].Gross_Wage, which does not exist Wagered[1] is out of your array's bounds. Move it inside your for loop, like this :
for(i = 0; i < 1; i++)
{
.
.
.
Wagered[i].Gross_Wage = Wagered[i].Wage * Wagered[i].Days_Worked;
Wagered[i].Wage_Booking = Wagered[i].Gross_Wage * 0.2;
Wagered[i].Tax = (Wagered[i].Gross_Wage - Wagered[i].Wage_Booking) * 0.05;
Wagered[i].Net_Wage = Wagered[i].Gross_Wage - Wagered[i].Wage_Booking - Wagered[i].Tax;
Wage_Summary += Wagered[i].Net_Wage;
printf("The Summary of the Gross Wages is: %d\n", Wagered[i].Gross_Wage);
}
and you will see the correct result printed.

Sort an array based on variable upon insertion

I have been writing a small program for a library database of book structures. An array is malloc allocated and initialized with 0's in each indexes ibsn long variable and a menu is prompted allowing choices. Upon adding a book it is placed into the first available position in the array (first position where the ISBN number is !=0).
My question is how can I add a book to the array whereby it places it sorted by the isbn number first checking if there is space in array?
Example: Book with ISBN 1234 entered into array; Second book added with ISBN 123 and is placed at first index moving the previous book to the next index.
void addbook(book_t* lib, int size)
{
int i;
//// Loop through the array until you find an empty element
for (i = 0; i < size; i++) {
/// Found an empty element
if ((lib + i)->isbn == 0) {
//// Ask for and store the book details
printf("Please enter the book name\n");
scanf("%s", (lib + i)->name);
printf("Please enter the book author\n");
scanf("%s", (lib + i)->author);
printf("Please enter the book number\n");
scanf("%ld", &(lib + i)->isbn);
printf("Please enter the book price\n");
scanf("%lf", &(lib + i)->price);
printf("We will now ask you for the release date of the book by day then month then year");
printf("\nPlease enter release date for this book (dd):"); //user able to change default
scanf("%d", &(lib + i)->releaseDate.date);
printf("\nPlease enter release month for this book (mm):"); //user able to change default
scanf("%d", &(lib + i)->releaseDate.month);
printf("\nPlease enter release year for this book (yyyy):"); //user able to change default
scanf("%d", &(lib + i)->releaseDate.year);
printf("\nDate entered is (%d / %d / %d)", (lib + i)->releaseDate.date, (lib + i)->releaseDate.month, (lib + i)->releaseDate.year); //user able to change default
/// Set i to size so that the loop finished
i = size;
}
//// If no empty element found and at the last element of the array
/// then library is not found
else if (i == size - 1)
{
printf("The array is full\n");
}
}
}
I have employed a similar method when deleting a book whereby if the book searched is found it is moved to the last space in the array and has its variables set to 0.
void deleteBook(book_t *lib, int size) {
int i, j, location = 0;
long searchISBN;
int found = 0;
printf("Enter ISBN to search\n");
scanf("%ld", &searchISBN);
for (i = 0; i < size; i++) {
if ((lib + i)->isbn == searchISBN) {
found++;
printf("Book Name %s\n", (lib + i)->name);
printf("Book Author %s\n", (lib + i)->author);
printf("Book ISBN %ld\n", (lib + i)->isbn);
printf("Book Price %lf\n", (lib + i)->price);
location = i;
i = size;
} else
if (i == size - 1) {
location++;
}//add to location and try again
}
if (found == 1) {
for (j = location; j < size; j++) {
strcpy(lib->name, (lib + j)->name);
strcpy(lib->author, (lib + j)->author);
(lib)->isbn = (lib + j)->isbn;
(lib)->price = (lib + j)->price; //user able to change default
(lib)->releaseDate.date = (lib + j)->releaseDate.date;
(lib)->releaseDate.month = (lib + j)->releaseDate.month;
(lib)->releaseDate.year = (lib + j)->releaseDate.year;
}//end swapping of elements
strcpy(lib->name, "0");
strcpy(lib->author, "0");
(lib)->isbn = 0;
(lib)->price = 0;
(lib)->releaseDate.date = 0;
(lib)->releaseDate.month = 0;
(lib)->releaseDate.year = 0;
} else {
printf("not found");
}
}//end deleteBook method
Your function deleteBook does not work correctly: it copies the fields of all entries after the found one over the first entry in the array. You should just copy the remaining entries as a block with memmove(). Use memmove() as opposed to memcpy() because the source and destination memory areas overlap.
Here is a corrected version:
#include <stdio.h>
#include <string.h>
void deleteBook(book_t *lib, int size) {
long searchISBN;
int found = 0;
printf("Enter ISBN to search\n");
if (scanf("%ld", &searchISBN) != 1)
return;
for (int i = 0; i < size;) {
if (lib[i].isbn == searchISBN) {
book_t book = { 0 }; // empty book record
found++;
// display book data before erasing it
printf("Book Name %s\n", lib[i].name);
printf("Book Author %s\n", lib[i].author);
printf("Book ISBN %ld\n", lib[i].isbn);
printf("Book Price %lf\n", lib[i].price);
// copy the remainder elements one position to the left
memmove(lib + i, lib + i + 1, sizeof(*lib) * (size - i - 1))
// reinitialize the last entry
memcpy(lib + size - 1, &book, sizeof(*lib));
// rescan the current entry in case of duplicates
// hence do not increment i
} else {
i++; // test the next entry
}
}
if (found == 0) {
printf("not found");
}
}
You can use a similar technique to insert a new entry at the appropriate position in the table:
void addbook(book_t *lib, int size) {
book_t book = { 0 }; // empty book record
int i, used;
// Loop through the array and pack empty elements
for (i = used = 0; i < size; i++) {
if (lib[i].isbn != 0) {
if (used < i) {
memcpy(lib + used, lib + i, sizeof(*lib));
}
used++;
}
}
// reset unused elements:
for (i = used; i < size; i++) {
if (lib[i].isbn != 0) {
memcpy(lib + i, &book, sizeof(*lib));
}
}
// check if the array is full:
if (used >= size) {
printf("The array is full\n");
return;
}
// Ask for and store the book details to local book structure
printf("Please enter the book name\n");
if (scanf("%s", book.name) != 1)
return;
printf("Please enter the book author\n");
if (scanf("%s", book.author) != 1)
return;
printf("Please enter the book number\n");
if (scanf("%ld", &book.isbn) != 1)
return;
printf("Please enter the book price\n");
if (scanf("%lf", &book.price) != 1)
return;
printf("We will now ask you for the release date of the book by day then month then year");
printf("\nPlease enter release date for this book (dd):");
if (scanf("%d", &book.releaseDate.date) != 1)
return;
printf("\nPlease enter release month for this book (mm):");
if (scanf("%d", &book.releaseDate.month) != 1)
return;
printf("\nPlease enter release year for this book (yyyy):");
if (scanf("%d", &book.releaseDate.year) != 1)
return;
printf("\nDate entered is (%d / %d / %d)",
book.releaseDate.date, book.releaseDate.month, book.releaseDate.year);
//// Loop through the array until you find location to insert book
for (i = 0; i < used; i++) {
if (lib[i].isbn > book.isbn)
break;
}
// book should be inserted at position i
// shift book with larger ISBNs
memmove(lib + i + 1, lib + i, sizeof(*lib) * (used - i));
used++;
// copy book into the array
memcpy(lib + i, &book, sizeof(*lib));
}
For production code, you would need to handle the scanf errors appropriately.
These insertion and deletion methods are not very efficient because on average half the database is copied for every operation. A more efficient implementation would use linked lists to avoid copying the data and make it easier to handle a variable number of books.

Resources