C - Alphabetically sorting arrays error - c

I'm working on a phone book assignment for my CECS class and I ran into a problem with alphabetically sorting the contacts. The program will allow me to sort up to 3 contacts, however when I try to sort more than 3, the program starts spitting out garbage variables and possibly crashing.
void Sort(phone *phonebook, int *num_entries)
{
int tracker = *num_entries;
if (tracker >= 0)
{
phone *temp = (phone*) calloc(tracker, sizeof(phone));
if (temp== NULL)
printf("\n\nOut of memory\n\n");
else
{
int i, j;
for (i = 0; i < tracker; i++)
{
for (j = i+1; j < tracker; j++)
{
//Combines first and last names into 1 name for easy comparison
strcpy(phonebook[i].totalname, phonebook[i].fName);
strcpy(phonebook[j].totalname, phonebook[j].fName);
strcat(phonebook[i].totalname, phonebook[i].lName);
strcat(phonebook[j].totalname, phonebook[j].lName);
printf("\nTotal name = %s\nTotal name = %s", phonebook[i].totalname, phonebook[j].totalname); //Done so I can verify it worked correctly
if (strcmp(phonebook[i].totalname, phonebook[j].totalname) > 0)
{
strcpy(temp[i].fName, phonebook[i].fName);
strcpy(temp[i].lName, phonebook[i].lName);
temp[i].number = phonebook[i].number;
temp[i].area = phonebook[i].area;
strcpy(phonebook[i].fName, phonebook[j].fName);
strcpy(phonebook[i].lName, phonebook[j].lName);
phonebook[i].number = phonebook[j].number;
phonebook[i].area = phonebook[j].area;
strcpy(phonebook[j].fName, temp[i].fName);
strcpy(phonebook[j].lName, temp[i].lName);
phonebook[j].number = temp[i].number;
phonebook[j].area = temp[i].area;
}
}
}
printf("\n\nSuccessfully sorted!\n\n");
}
}
else
printf("\n\nYou need people in the phone book before you can sort it.\n\n");
}
-------------------------
typedef struct PhoneBook
{
char fName[20];
char lName[20];
char totalname[40];
float number;
int area;
} phone;
Edited to add the structure. And I don't use qsort because we haven't learned about it in class and the TA's are rather strict about not using stuff we haven't learned.
void Add(phone *phonebook, int *num_entries)
{
int tracker = *num_entries;
if (tracker == 0)
{
printf("\n\nSomething's wrong here\n\n");
}
else
{
const int newSize = tracker + 1;
phone *temp = (phone*) realloc(phonebook, (newSize * sizeof(phone)));
if (temp!=NULL)
{
phonebook = temp;
}
else
phonebook = NULL;
}
if (phonebook == NULL)
printf("\n\nOut of memory, can't add more to your phonebook\n\n");
else
{
printf("\n\nEnter the first name: ");
scanf("%s", phonebook[tracker].fName);
printf("\nPlease enter the last name: ");
scanf("%s", phonebook[tracker].lName);
printf("\nPlease enter the area code: ");
scanf("%d", &phonebook[tracker].area);
printf("\nPlease enter the phone number (no dashes allowed): ");
scanf("%f", &phonebook[tracker].number);
*num_entries += 1;
printf("\nContact Added.\n\n");
}
}
Edited again to show the code to add people to the phone book (also broken). After 3-4 entries, it starts placing garbage values for entries.
int main()
{
int userInput = 8; //means exit
int num_entries = 1;
phone *phonebook = (phone*) calloc(1 , sizeof(phone));
if (phonebook == NULL)
printf("\n\nOut of memory\n\n");
else
{
do
{
system("cls");
printf("Menu: \n");
printf("1) Add a Contact\n");
printf("2) Delete a Contact\n");
printf("3) Display Phone Book\n");
printf("4) Alphabetically Sort\n");
printf("5) Find a Contact\n");
printf("6) Random Contact\n");
printf("7) Delete All\n");
printf("8) Exit\n\n");
scanf(" %d", &userInput);
switch (userInput)
{
case 1: //Add a Friend
Add(phonebook, &num_entries);
break;
case 2: //Delete a Friend
Delete(phonebook, &num_entries);
break;
case 3: //List all contacts
Display(phonebook, &num_entries);
break;
case 4:
Sort(phonebook, &num_entries);
break;
case 5:
Find(phonebook, &num_entries);
break;
case 6:
Random(phonebook, &num_entries);
break;
case 7:
DeleteAll(phonebook, &num_entries);
break;
case 8:
free(phonebook);
break;
}
system("PAUSE");
}while(userInput != 8);
}
return 0;
}
Edited to show the calls for each function
Well I can't post photos without more reputation so here's the links:
Photo 1 - Adding 3 contacts works fine: http://s980.photobucket.com/user/valondon/media/C%20Realloc%20Errors/Erroronerealloc_zpsc8228131.png.html?sort=3&o=0
Photo 2 - The phone book after the fourth contact was added: http://s980.photobucket.com/user/valondon/media/C%20Realloc%20Errors/Errorthreerealloc_zps246b76e3.png.html?sort=3&o=2

Problem is with the outer loop.
If you have say 'n' entries in the array to sort, then you have to compare the first entry of the array with remaining 'n-1' entries. After first entry is compared with all 'n-1' entries that means first entry is properly located at its location in sorted array. Now you have left with 'n-1' entries to sort. Now if you want to compare 2nd entry of the array then you have to compare that 2nd entry with remaining 'n-1-1' (only 'n-1' entries left to sort and you have taken 2nd entry to compare with rest of the entries). this goes on till the end.
In your code you can change the code like below (the loop part):
Note: I have created a temp variable of temp of structure phone.
phone temp;
for (i = 0; i < tracker - 1; i++)
{
for (j = i+1; j <= tracker - 1; j++)
{
//Combines first and last names into 1 name for easy comparison
strcpy(phonebook[i].totalname, phonebook[i].fName);
strcpy(phonebook[j].totalname, phonebook[j].fName);
strcat(phonebook[i].totalname, phonebook[i].lName);
strcat(phonebook[j].totalname, phonebook[j].lName);
printf("\nTotal name = %s\nTotal name = %s", phonebook[i].totalname, phonebook[j].totalname); //Done so I can verify it worked correctly
if (strcmp(phonebook[i].totalname, phonebook[j].totalname) > 0)
{
strcpy(temp.fName, phonebook[i].fName);
strcpy(temp.lName, phonebook[i].lName);
temp.number = phonebook[i].number;
temp.area = phonebook[i].area;
strcpy(phonebook[i].fName, phonebook[j].fName);
strcpy(phonebook[i].lName, phonebook[j].lName);
phonebook[i].number = phonebook[j].number;
phonebook[i].area = phonebook[j].area;
strcpy(phonebook[j].fName, temp.fName);
strcpy(phonebook[j].lName, temp.lName);
phonebook[j].number = temp.number;
phonebook[j].area = temp.area;
}
}
}
printf("\n\nSuccessfully sorted!\n\n");
}

The problem is with your for loops.
In your example, j is equal to i+1 in the second loop. i has a maximum value of tracker - 1, so j can be equal to tracker. This will cause you to overshoot the array, which can trash memory.
Try changing them to:
for (i = 0; i < tracker - 1; i++)
{
for (j = 0; j < tracker - i - 1; j++)
The other issue is that in your inner loop, you are using [i] and [j] to index your swaps. If you change every [i] in that loop to [j+1], you'll have a working bubble sort.
Your inner loop ends up as:
phone temp; /* I created a stack variable called temp - saves the need for allocation */
for (i = 0; i < tracker - 1; i++)
{
for (j = 0; j < tracker - i - 1; j++)
{
//Combines first and last names into 1 name for easy comparison
strcpy(phonebook[j+1].totalname, phonebook[j+1].fName);
strcpy(phonebook[j].totalname, phonebook[j].fName);
strcat(phonebook[j+1].totalname, phonebook[j+1].lName);
strcat(phonebook[j].totalname, phonebook[j].lName);
printf("\nTotal name = %s\nTotal name = %s", phonebook[j+1].totalname, phonebook[j].totalname); //Done so I can verify it worked correctly
if (strcmp(phonebook[j+1].totalname, phonebook[j].totalname) > 0)
{
strcpy(temp.fName, phonebook[j+1].fName);
strcpy(temp.lName, phonebook[j+1].lName);
temp.number = phonebook[j+1].number;
temp.area = phonebook[j+1].area;
strcpy(phonebook[j+1].fName, phonebook[j].fName);
strcpy(phonebook[j+1].lName, phonebook[j].lName);
phonebook[j+1].number = phonebook[j].number;
phonebook[j+1].area = phonebook[j].area;
strcpy(phonebook[j].fName, temp.fName);
strcpy(phonebook[j].lName, temp.lName);
phonebook[j].number = temp.number;
phonebook[j].area = temp.area;
}
}
}

Related

No matching two dimensional string arrays for a login

I was resolving an example I see in a book about C programming. This particular problem I saw in this book was about matching a kind of 'customer code'(integer) which was okay for me. But I have troubles applying the same logic for a two dimensional string where I want to prove my login.
This is from the book, which goes fine.
/*
This program searches a sorted list of customer IDs in order to get credit totals
*/
#include <stdio.h>
int main()
{
int ctr; // Loop counter
int idSearch; // Customer to look for (the key)
int found = 0; // 1 (true) if customer is found
/* Defines the 10 elements in each of the parallel arrays */
int custID[10] = {313, 453, 502, 101, 892, 475, 792, 912, 343, 633};
float custBal[10]={0.00, 45.43, 71.23, 301.56, 9.08, 192.41, 389.00, 229.67, 18.31, 59.54};
int tempID, inner, outer, didSwap, i; // For sorting
float tempBal;
// First, sort the arrays by customer ID
for (outer=0; outer<9; outer++)
{
didSwap=0; // Becomes 1 (true) if list is not yet ordered
for (inner=outer; inner<10; inner++)
{
if (custID[inner] < custID[outer])
{
tempID = custID[inner]; // Must switch both arrays of they
tempBal = custBal[inner]; // are no longer linked
custID[inner] = custID[outer];
custBal[inner] = custBal[outer];
custID[outer] = tempID;
custBal[outer]=tempBal;
didSwap = 1; // True because a swap took place
}
}
if (didSwap == 0)
{
break;
}
}
/* Interact with the user looking to find a balance */
printf("\n\n*** Customer Balance Lookup ***\n");
printf("What is the customer number? ");
scanf(" %d", &idSearch);
// Now, look for the ID in the array
for (ctr=0; ctr<10; ctr++)
{
if (idSearch == custID[ctr]) // Do they match?
{
found = 1; // Yes, match flag is set to TRUE
break; // No need to keep looping
}
if (custID[ctr] >idSearch) // No need to keep searching
{
break;
}
}
// Once the loop has completed, the ID was either found
// (found = 1) of not
if (found)
{
if (custBal[ctr]>100)
{
printf("\n** That customer's balance is $%.2f.\n", custBal[ctr]);
printf("No additional credit.\n");
}
else // Balance is less than $100.00
{
printf("\n**The customer's credit is good!\n");
}
}
else // The ID was not found
{
printf("** You have entered an incorrect customer ID.");
printf("\n ID %3d was not found in the list.\n", idSearch);
}
return(0);
}
This is what I tried to create in order to do a login.
#include <stdio.h>
#include <string.h>
int main()
{
int ctr; // Loop counter
char userSearch[20], passSearch[10]; // to look for (the key)
int found = 0; // 1 (true) if it is found
/* Defines the 5 elements in each of the parallel arrays */
char user[5][20] = {"John", "Ivan", "Paul", "Robert", "Leo"};
char pass[5][10]={"1111", "2222", "3333", "4444", "5555"};
int inner, outer, didSwap, i; // For sorting
char tempUser, tempPass;
for (outer=0; outer<4; outer++)
{
didSwap=0; // Becomes 1 (true) if list is not yet ordered
for (inner=outer; inner<5; inner++)
{
if (user[inner] != user[outer])
{
strcpy(tempUser, user[inner]);
strcpy(tempPass, pass[inner]);
strcpy(user[inner], user[outer]);
strcpy(pass[inner], pass[outer]);
strcpy(user[outer], tempUser);
strcpy(pass[outer], tempPass);
didSwap = 1;
}
}
if (didSwap == 0)
{
break;
}
}
printf("User: ");
scanf(" %s", userSearch);
printf("Password: ");
scanf(" %s", passSearch);
for (ctr=0; ctr<5; ctr++)
{
if ((strcmp(userSearch, user[ctr])==0) && (strcmp(passSearch, pass[ctr])==0)) // Do they match?
{
found = 1;
break;
}
}
if (found)
{
printf("You entered sucessfully.");
}
else
{
printf("** You have entered an incorrect data.");
printf("\n %s was not found.\n", userSearch);
}
return(0);
}
What exactly is wrong with my last code? How can I get to make a proper login with two-dimensional string arrays? I want to put like 100 users for example, and pointing each user is not an option so I thought this way would be a good idea, with this algorithm. But not sure what is my mistake.

C seg fault - where/what?

I have this program that is supposed to handle assigning seats to passengers.
I cannot figure out what is causing my seg fault. I am using an array of structs and that may be where the problem is coming from.
I think its probably a problem with dereferencing some struct members, but I can't find where.
Here is my code:
struct seat
{
// Max Name of 32 chars
char name[32];
// Seat Number
int sNum;
// Seat taken = 1, open = 0
int taken;
};
// Function headers
void seat(struct seat plane[][10]);
void mani(struct seat plane[][10]);
void pass(int seat, char name[], int class);
int main()
{
// My airline plane is 6 seats per row, 10 rows
// Row 1/2 are First Class
// Row 3/4 are Business Class
// Init counter variables to keep track of the number
// of First Class/Business seats already taken
// also the user input var
int input, ticketin, class1 = 0, class2 = 0, class3=0, sNum, i;
char namein[32];
// Vars for pass function
char passname[32];
int passclass;
int passseat;
// Init a 2d array 6 colums 10 rows
struct seat plane[6][10];
for (i=0; i<sizeof(plane); i++)
{
plane[i]->sNum = i+1;
plane[i]->taken = 0;
}
// Begin user input loop
// Menu with 3 options:
// Display the seating chart, indicating taken seats
// Display the manifest
// Display a boarding pass - seat number, name, class
do
{
do
{
// Prompt user for ticket selection
printf("Please type 1 for \"First Class\"\n");
printf("Please type 2 for \"Business Class\"\n");
printf("Please type 3 for \"Economy Class\"\n");
scanf(" %d", &ticketin);
// Check for valid input
if (ticketin == 1)
{
// Check to make sure first class is not full
if (class1 < 12)
{
class1 += 1;
printf("First class is open!\n");
} else {
printf("First class is full, please choose another class\n");
}
} else if (ticketin == 2)
{
// Check to make sure business class is not full
if (class2 < 12)
{
class2 += 1;
printf("Business class is open!\n");
} else {
printf("Business class is full, please choose another class\n");
if (class1 < 12)
{
printf("Upgrade to First Class by entering 1");
}
}
} else if (ticketin == 3)
{
// Check to make sure business class is not full
if (class3 < 12)
{
class3 += 1;
printf("Economy class is open!\n");
} else
{
printf("Economy class is full, please choose another class\n");
if (class1 < 12)
{
printf("Upgrade to First Class by entering 1");
}
if (class2 < 12)
{
printf("Upgrade to Business Class by entering 2");
}
}
} else
{
ticketin = 4;
}
// Prompt the user for their name
printf("Please input your name:\n");
scanf(" %s", namein);
} while (ticketin == 4);
// Handle loading the new passenger into plane array
switch (ticketin)
{
case 1:
for (i=0; i<12; i)
{
if (plane[i]->taken == 0)
{
plane[i]->taken = 1;
strcpy(plane[i]->name, namein);
sNum = plane[i]->sNum;
} else
{
i++;
}
}
case 2:
for (i=12; i<24; i)
{
if (plane[i]->taken == 0)
{
plane[i]->taken = 1;
strcpy(plane[i]->name, namein);
sNum = plane[i]->sNum;
} else
{
i++;
}
}
case 3:
for (i=24; i<60; i)
{
if (plane[i]->taken == 0)
{
plane[i]->taken = 1;
strcpy(plane[i]->name, namein);
sNum = plane[i]->sNum;
} else
{
i++;
}
}
}
printf("Menu Options: \n");
printf("(1) Display the seating chart\n");
printf("(2) Display the passenger manifest\n");
printf("(3) Display a boarding pass\n");
printf("(4) Quit\n");
// Prompt user for their selection
printf("Please enter your menu selection:\n");
scanf(" %d", &input);
// Switch case handling function calls
switch (input)
{
case 1:
seat(plane);
break;
case 2:
mani(plane);
break;
case 3:
printf("Please input a seat number\n");
scanf(" %d", &passseat);
if (passseat < 12)
{
passclass = 1;
} else if (passseat < 24)
{
passclass = 2;
} else
{
passclass = 3;
}
pass(passseat, plane[passseat-1]->name, passclass);
break;
default:
printf("invalid menu option or quitting\n");
break;
}
} while (input != 4);
}
// Display seating chart function
void seat(struct seat plane[][10])
{
int i, sNum;
for (i=0; i<sizeof(plane); i++)
{
if (plane[i]->taken == 1)
{
printf("Seat %d is taken\n", i++);
} else
{
printf("Seat %d is not taken\n", i++);
}
}
}
// Display Manifest function
void mani(struct seat plane[][10])
{
int i;
for (i=0; i<sizeof(plane); i++)
{
if (plane[i]->taken == 1)
{
printf("Passenger %s in seat %d\n", plane[i]->name, i++);
}
}
}
// Display boarding pass function
void pass(int seat, char name[], int class)
{
printf("Boarding pass for %s\n", name);
printf("Seat Number: %d\n", seat);
switch (class)
{
case 1:
printf("First Class");
break;
case 2:
printf("Business Class");
break;
case 3:
printf("Economy Class");
break;
}
}
There are probably other errors, but this is the most obvious one:
for (i=0; i<sizeof(plane); i++)
{
plane[i]->sNum = i+1;
plane[i]->taken = 0;
}
sizeof(plane) is the number of bytes in the plane array. This is 10 * 6 * sizeof(struct seat), so you're writing way outside the array. If you want to know the number of elements in an array, you have to divide the size of the array by the size of an array element:
for (i=0; i<sizeof(plane)/sizeof(*plane); i++)
{
plane[i]->sNum = i+1;
plane[i]->taken = 0;
}
But your code is only initializing the first element in each row of the array.
Since it's a 2-dimensional array, you need nested loops. And you should use normal member access with . rather than pointer indirection.
for (i=0; i<sizeof(plane)/sizeof(plane[0]); i++)
{
for (int j = 0; j < sizeof(plane[i])/sizeof(plane[i][0]); j++)
{
plane[i][j].sNum = i+1;
plane[i][j].taken = 0;
}
}
You could simplify all the sizeof stuff by defining macros:
#define ROWS 6
#define COLS 10
and then using these macros in the array declaration and the for loop limits.
Similar changes need to be made in other code that loops over the plane array.

re-prompt user after invalid input in c

I'm writing this program in c where I need to re-prompt the user after an invalid input. I came to a solution only to discover that if the user enters another invalid input after the re-prompt then it continues. Can someone please show me a better solution to this? I'll show you what I had anyway:
#include <stdio.h>
#include <ctype.h>
main()
{
int ctr; // loop counter
int custID[10] = {1, 3, 5, 9, 10, // ID array
6, 4, 7, 8, 2};
double custBal[10] = {153.56, 1300.45, 684.45, 990.45, 45.54, // Balance array
1100.34, 594.45, 1340.45, 1000.00, 1134.00};
int IDsearch; // For interaction
int found = 0; // Search criteria
int inner, outer, tempID, didSwap; // For sorting the arrays
double tempBal;
char ans;
/* Firs step: Sort the arrays for efficiency */
for(outer = 0; outer < 9; outer++) // <9 and not <10, because 9 numbers will be bubble sorted
{ // the highest (10th) will remain at the bottom
didSwap = 0; // Turns one after the arrays sort
for(inner = outer; inner < 10; inner++)
{
if(custID[inner] < custID[outer]) // Ascending sort
{
tempID = custID[inner]; // Must include both,
tempBal = custBal[inner]; // otherwise the arrays wont be linked
custID[inner] = custID[outer];
custBal[inner] = custBal[outer];
custID[outer] = tempID;
custBal[outer] = tempBal;
didSwap = 1; // Flag that a swap took place
}
}
if(didSwap == 0)
{
break;
}
}
/* Second step: Interacting with the program */
printf("***Customer Balance Search***\n");
do
{
printf("Which ID number do you want to check?\n");
scanf(" %d", &IDsearch);
for(ctr = 0; ctr < 10; ctr++)
{
if(IDsearch == custID[ctr])
{
found = 1;
break;
}
}
if(found)
{
if(custBal[ctr] < 1000)
{
printf("\nCustomer #%d has a balance of $%.2f.\n", custID[ctr], custBal[ctr]);
printf("Credit is good!\n");
}
else
{
printf("\nCustomer #%d has a balance of %.2f.\n", custID[ctr], custBal[ctr]);
printf("Credit is bad! No more credit!\n");
}
}
else
{
printf("\nCustomer #%d was not found!\n", IDsearch);
printf("Please enter a correct ID number!\n\n");
continue;
}
printf("\nDo you want to search another ID number?\n");
printf("Enter (Y)es or (N)o\n");
scanf(" %c", &ans);
ans = toupper(ans);
}
while((found != 1) || (ans == 'Y' && ans != 'N'));
printf("\nExiting...\n\n");
return (0);
}
Please reset found
do {
found = 0;
// ...
at the start of the do-while loop. It is not enough to initialise it when defined.

Compare date read form file with input date

i'm having serious problems with a project in C language. I've created a function that takes in input some data about an entry in a sport center, but now i've to modify this function so that this function:
asks in input the last name who's entering
by last name inserted, it must go to the file of registrations, search and read the last date of registration for that last name.
Once found, save this date somewhere and compare it with the expiration date of membership for the member with that last name. If the entry date is less or equal to the expiration date, must allow the inserting of data, otherwise, terminate the program with a message like this: "Your membership has expired".
My difficulties are in the point 2 and 3 of this request. Can someone please help me, i'm in serious trouble
I post the basic code on which i've to do this:
void add_entry()
Date_entry de;
Entry e;
Entry eTemp;
FILE *fEnt; //file corso
FILE *fInd; //file indice del corso
printf("Number: ");
scanf("%d", &e.number);
printf("Name: ");
scanf("%s", &e.name);
printf("Surname: ");
scanf("%s", &e.surname);
printf("Date (DD/MM/YYYY): ");
scanf("%d/%d/%d", &de.day3, &de.month3, &de.year3);
printf("Entry time(HH:MM): ");
scanf("%s", &e.entry_time);
printf("Exit time(HH:MM): ");
scanf("%s", &e.exit_time);
e.deleted = 0;
int cont = 0;
fEnt = fopen(EntryOpen,"r+b");
fread(&eTemp,sizeof(Entry),1,fEnt);
while(eTemp.deleted != 1)
{
fread(&eTemp,sizeof(Entrance),1,fEnt);
cont++;
}
int posInEntry = cont;
fseek(fEnt,cont * sizeof(Entrance),0);
fwrite(&e,sizeof(Entrance),1,fEnt);
fclose(fEnt);
Index x;
Index xTemp;
strcpy(x.key,e.surname);
x.value = e.number;
fInd = fopen(indexOpen,"r+b");
cont = 0;
fread(&xTemp,sizeof(Index),1,fInd);
while(strcmp(xTemp.key,"EMPTY") != 0)
{
fread(&xTemp,sizeof(Index),1,fInd);
cont++;
}
fseek(fInd,cont * sizeof(Index),0);
fwrite(&x,sizeof(Index),1,fInd);
fclose(fInd);
IndexCode y;
IndexCode yTemp;
y.kye = e.number;
y.value = posInEntry;
fInd = fopen(indexCodeOpen,"r+b");
cont = 0;
fread(&yTemp,sizeof(IndexCode),1,fInd);
while(yTemp.key != -1)
{
fread(&yTemp,sizeof(IndexCode),1,fInd);
cont++;
}
fseek(fInd,cont * sizeof(IndexCode),0);
fwrite(&y,sizeof(IndexCode),1,fInd);
fclose(fInd);
IndexCode ind[max];
fInd = fopen(indexCodeOpen,"rb");
int i;
for(i = 0; i < max; i++)
{
fread(&ind[i],sizeof(IndexCode),1,fInd);
}
fclose(fInd);
OrderIndexCode(ind,max);
fInd = fopen(indexCodeOpen,"wb");
for(i = 0; i < max; i++)
{
fwrite(&ind[i],sizeof(IndexCode),1,fInd);
}
fclose(fInd);
printf("Index Update completed.\n");

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