My variables changing after moving to the next function - c

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

Related

How to delete a value in a struct?

I am trying to delete a "user" from the struct on my code.
For example, this is the struct I have:
struct clients {
char name[30];
int year;
float amount;
};
And this is the two outputs I have:
Name: Victor
Birth Year: 1998
Amount: 1000.00
Name: John
Birth Year: 1996
Amount: 1500.00
What I want to do is to delete John and all his information from my struct.
I am trying to learn dynamic memmory allocation, so I used this command:
clt = (struct clients*) malloc(n * sizeof(struct clients));
In my case I wish to write a command on case 3 that delete john from the struct, but I really can't figure out how to do that, I guess maybe using realloc? But I didn't even get close to write something it would work.
Here is my entire code so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct clients {
char name[30];
int year;
float amount;
};
int main() {
struct clients *clt;
int option, n, d = 0;
char name[30];
printf("Welcome, Choose an option to begin:");
do {
printf("\n1 - Create a new list;\n");
printf("2 - Find a person in the list;\n");
printf("3 - Delete a person from the list.\n");
printf("4 - End the program.\n");
scanf("%d", &option);
switch (option) {
case 1:
printf("\nType how many clients you want to register:");
scanf("%d", &n);
// allocating memory for n numbers of struct person
clt = (struct clients*) malloc(n * sizeof(struct clients));
for (int i = 0; i < n; i++) {
printf("Type the name and the birth year:");
// To access members of 1st struct person,
scanf("%s %d", (clt + i)->name, &(clt + i)->year);
printf("\nType the amount:");
scanf("%f", &(clt + i)->amount);
}
break;
case 2:
printf("Type the name you want to find:");
scanf("%s", name);
for (int i = 0; i < n; i++) {
if (strcmp(&clt[i].name, name) == 0) {
printf("\nThats the name:");
printf("\nName: %s\n", (clt + i)->name);
printf("Birth Year: %d\n", (clt + i)->year);
printf("Amount: %.2f\n", (clt + i)->amount);
d++;
}
}
if (d == 0)
printf("This name doesn't exist\n");
break;
case 3:
break;
case 4:
break;
}
} while (option != 4);
return 0;
}
You need to discard the element from its location in the list by moving the contents in the remainder of the list up , and overwriting the target element.
for(int i = 0; i < n; i++) {
if (strcmp(&clt[i].name, name)==0)
{
printf("\nThats the name:");
printf("\nName: %s\n", (clt+i)->name);
printf("Birth Year: %d\n", (clt+i)->year);
printf("Amount: %.2f\n", (clt+i)->amount);
d++; // This seems to be your sentinel value?
}
if ( 1 == d && i+1 != n ) // if the sentinel is set, but we're not off the end of the list yet
{
memcpy(clt+i, clt+i+1, sizeof( struct clients ));
}
}
n--; // reduce the list length
You could do this in one memmove call if you prefer. As #Neil says in the comments, memmove is tolerant of overlapping source and destination.
if ( 1 == d && i != n-1 ) // if the sentinel is set, but we're not off the end of the list yet
{
memmove(clt+i, clt+i+1, (n-i-1) * sizeof( struct clients ));
break; // break for i
}
You are describing almost a dynamic array such as C++'s std::vector. It is static, but it could be a dynamic array without that much extra work. You could create a container, and split n into the container's capacity and size.
struct clients_array {
size_t size, capacity;
struct clients *data;
};
Instead of having multiple pointers, one could create a struct clients_array for each list. Sample code to deal with the struct clients_array.
#include <inttypes.h>
#include <assert.h>
#include <errno.h>
/** `a` constructor with `n` spots. Returns true or false depending on whether
it could be constructed. */
static int clients_array_reserve(struct clients_array *const a,
const size_t n) {
assert(a && n);
if(n > SIZE_MAX / sizeof *a->data) return errno = ERANGE, 0;
if(!(a->data = malloc(sizeof *a->data * n))) return 0;
a->capacity = n;
a->size = 0;
return 1;
}
/** `a` destructor; call this when `a` has been successfully constructed. */
static void clients_array_(struct clients_array *const a)
{ if(a) { free(a->data); a->data = 0; a->capacity = a->size = 0; } }
/** Extract a new uninitialized entry out of constructed `a`. Returns null if
there is no more space. */
static struct clients *clients_array_new(struct clients_array *const a) {
assert(a);
return a->capacity > a->size ? a->data + a->size++ : 0;
}
/** Remove index `rm` from `a`. */
static void clients_array_delete(struct clients_array *const a,
const size_t rm) {
assert(a && rm < a->size);
memmove(a->data + rm, a->data + rm + 1,
sizeof *a->data * (a->size - rm - 1));
a->size--;
}
Then one can have different, independent arrays at once. If you want to update the code, say to allow realloc to increase the size of the object, you only need to modify the container.

Realloc to structure in c

i have a problem with my realloc in the func add order its crash every time
someone can help me here
typedef struct
{
char carname[30]; //car names
int price; //the price of the car
}Vehicle;
typedef struct {
int number; // מספר הזמנה
char *name; // שם המזמין
char ID[10]; // מספר זהות שלו
int number_vehicles; // מספר הרכבים בהזמנה
Vehicle * list;
int sum_order;
}Order;
Order * add_orders(Order * firma, int * ordersize)// adding one more order
{
int i, j;
char temp[80];
int newstart; // because we need to add one more order we need new start and it will be the old size of the number of orders
newstart = *ordersize; //we just did it
(*ordersize)++; // now we have new size +1 for the one more order
for (i = newstart; i < *ordersize; i++) //same as the input function but this one start and finish from the new start and finish
{
printf("enter the ID of order number: %d\n", i + 1);
scanf("%d", &firma[i].number);
while (getchar() != '\n');
printf("enter the name of the client:\n");
gets(temp);
firma[i].name = (char*)malloc(strlen(temp) + 1 * sizeof(char));
if (!firma[i].name)
{
printf("error\n");
return 0;
}
strcpy(firma[i].name, temp);
printf("enter the ID of client (length can only be 10):\n");
gets(firma[i].ID);
printf("enter how many vehicles you want in this order\n");
scanf("%d", &firma[i].number_vehicles);
firma[i].list = (Vehicle*)malloc(firma[i].number_vehicles * sizeof(Vehicle));
if (!firma[i].list)
{
printf("error\n");
return 0;
}
for (j = 0; j < firma[i].number_vehicles; j++)
{
while (getchar() != '\n');
printf("enter the name of the vehicle number %d (only 30 chars):\n", j + 1);
gets(firma[i].list[j].carname);
printf("enter the price of the vehicle\n");
scanf("%d", &firma[i].list[j].price);
}
}
firma = (Order*)realloc(firma, (*ordersize * sizeof(Order))); //after we added the new order we do realloce for the new size for the struct
if (!firma)//if failed
{
printf("error\n");
return 0;
}
}
int main()
{
int i, j;
char temp[80];
char *str = NULL;
int num, x, y;
int number;
int ordersize;
int exit1 = 0;
int exit2 = 0;
int exit3 = 0;
int flag = 0;
int choose;
Order *data = NULL; //pointer to the struct Order
printf("\nenter how many orders you want\n");
scanf("%d", &ordersize); //enter size of orders
data = (Order*)malloc(ordersize * sizeof(Order));//we allocte memory for the struct Order with pointer data
add_orders(data, &ordersize); //send it
return 0;
}
i have a problem with my realloc in the func add order its crash every time
someone can help me here
i have a problem with my realloc in the func add order its crash every time
someone can help me here
i have a problem with my realloc in the func add order its crash every time
someone can help me here
You access out of bound for firma.
data = (Order*)malloc(ordersize * sizeof(Order));//we allocte memory for the struct Order with pointer data
add_orders(data, &ordersize); //send it
As you allocated memory of size orderSize and you access firma[newstart].
newstart = *ordersize; //we just did it
(*ordersize)++; // now we have new size +1 for the one more order
for (i = newstart; i < *ordersize; i++) //same as the input function but this one start and finish from the new start and finish
{
printf("enter the ID of order number: %d\n", i + 1);
scanf("%d", &firma[i].number);
while (getchar() != '\n');
.....
}
Thus first allocate more memory and access.
newstart = *ordersize; //we just did it
(*ordersize)++; // now we have new size +1 for the one more order
firma = (Order*)realloc(firma, (*ordersize * sizeof(Order))); //after we added the new order we do realloce for the new size for the struct
if (!firma)//if failed
{
printf("error\n");
return 0;
}
for (i = newstart; i < *ordersize; i++) //same as the input function but this one start and finish from the new start and finish
{
printf("enter the ID of order number: %d\n", i + 1);
scanf("%d", &firma[i].number);
while (getchar() != '\n');
.....
}
Note:: firma is local variable and allocating memory using realloc
in addOrder function has no effect on data variable in main
function. You may need to pass data using reference or return
updated value from function and assign it to data.

Can't initialize my array counter in C despite trying everything

I've been working on this school assignment which creates a restaurant menu, and I have an array to store everything that a person orders. The array that stores the orders ordered is array OrderedItems [30]. This array is basically a counter. When a person orders order number 1 as an example OrderItems[1] increases by 1.
I've tried to initialize by using OrderedItems [30] = {0}, and using a for loop to initialize every spot individually, However, that didn't work. Please help me initialize this array. I've also tried memset(OrderedItems, 0, 30); and this didn't work too so I really have no clue what to do.
I also want to add that I've tried to globally declare the OrderedItems array since I've heard that all global declarations are automatically initialized to 0, but that also didn't work.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>
FILE *fPointer1; //for food//
FILE *fPointer2; //for invoice//
int count;
char name[50];
float price;
void FunctionToPrintFoodItems (void)
{
fPointer1 = fopen ("Food.txt", "a+");
float price;
printf("ITEMCODE\tDESCIPTION\tPRICE (RM)\n");
while (!feof (fPointer1))
{
fscanf(fPointer1, "%d %s %f", &count, name, &price);
printf("%d\t\t%s\t\t%.2f\n", count, name, price);
}
fclose (fPointer1);
}
void clrscr()
{
system("#cls||clear"); //might not need. Will delete it not needed//
}
void debug (void)
{
printf("THIS IS PRINTED");
}
#define clear clrscr ();
#define printfood FunctionToPrintFoodItems();
#define de debug();
int main ()
{
fPointer1 = fopen("Food.txt", "w");
fprintf(fPointer1, "1 BigM 10.40\n");
fprintf(fPointer1, "2 Cheeseburger 9.45");
fclose (fPointer1);
int i;
int MainMenuCode;
int additems = 0;
int orderitems;
int item;
int ordered;
int OrderedItems[30] = {0};
memset(OrderedItems, 0, 30);
for (i=0 ; i < 30 ; i++)
{
OrderedItems[i] = NULL;
printf("%d: %d\n", i, OrderedItems);
}
do
{
printf("WELCOME TO RESTOURANT MAC C - Main Menu\n\n");
printf("[1] Add new food items\n\n");
printf("[2] Take order\n\n");
printf("Enter ITEM CODE (0 to Quit) : ");
scanf("%d", &MainMenuCode);
if (MainMenuCode == 1)
{
clear;
additems = 1;
printf("WELCOME TO RESTAURANT MAC C - Add Menu\n\n");
printfood;
printf("\n");
while ( additems == 1 )
{
printf("Enter description (0 to Main Menu) : ");
scanf("%s", name);
if (strcmp (name, "0") == 0)
{
additems = 0;
clear;
break;
}
printf("Enter price (RM) : ");
scanf("%f", &price);
count ++;
fPointer1 = fopen ("Food.txt", "a");
printf("\n%d\t\t%s\t\t%.2f\n\n", count, name, price);
fprintf(fPointer1, "\n%d %s %.2f", count, name, price);
fclose (fPointer1);
}
}
else if (MainMenuCode == 2)
{
clear;
orderitems = 1;
printf("WELCOME TO RESTAURANT MAC C- Take Order\n\n");
printfood;
while (orderitems == 1)
{
fPointer1 = fopen ("Food.txt", "a+");
printf("Enter ITEM CODE (0 to Quit, 100 for Main Menu) : ");
scanf("%d", &item);
if (item == 100) break;
else if (item == 0) //final approach//
{
fPointer2 = fopen ("Invoice.txt", "a+");
de;
fclose (fPointer2);
return 0;
}
else if (item == 900)
{
for (i=0 ; i < 30 ; i++)
printf("%d: %d\n", i, OrderedItems);
}
else if (item > count || item < 1)
{
printf("\n\nITEM CODE not available. Try again\n\n");
}
else
{
OrderedItems[item]++;
printf("%d %d", item, OrderedItems);
}
fclose (fPointer1);
}
}
else printf("Please enter a valid Menu Code\n");
} while (MainMenuCode != 0);
return 0;
}
- printf("%d: %d\n", i, OrderedItems);
+ printf("%d: %d\n", i, OrderedItems[i]);
OrderedItems is an address of the array's first element.
OrderedItems[0] is a value of the array's first element.
OrderedItems[i] is a value of the array's i-th element.
The call to memset should specify how many bytes to set. You need to tell it the size of the type to initialise.
memset(OrderedItems, 0, 30 * sizeof(int))

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