Sort an array based on variable upon insertion - c

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.

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

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");

Trouble storing the size of each array I have in C

I'm having trouble storing the size of each array the user inputs. I need to do this so that I can run different calculations on each set. This is what I'm trying to do now, but it keeps throwing a segmentation fault, and I don't know what I'm doing wrong. The other thing I thought of doing was essentially make one more memory spot with malloc and just store the sizes in another array at the end of the data set arrays. Anyway, here's the code that is giving me a segmentation fault.
int construct_data_sets(int *sets[], int count) {
int set_size;
int j;
j = 0;
printf("Enter the number of elements in data set %d: ", count+1);
scanf(" %d", &set_size);
sets[count] = (int*)malloc((sizeof(int) * set_size));
if (sets[count] == NULL){
printf("Malloc failed!\n");
}
printf("Enter the data for set %d: ", count+1);
while ((j + 1) <= set_size)
{
scanf(" %d", &sets[count][j]);
j++;
}
return set_size;
}
And here's the main, I think the segmentation fault gets thrown when I call construct_data_sets().
int main() {
int command = 0, data_set, set_desired, array_size;
int number = prompt_num_sets();
int *sets[number], i = 0, *sizes[number];
while (i < number)
{
array_size = construct_data_sets(sets, i);
*sizes[i] = array_size;
i++;
}
//printf("The size of the 3rd data set is %d", *sizes[3]);
printf("Data at [data_set][1] = %d\n", sets[data_set-1][1]);
set_desired = select_data_set(number);
while (command != 7) {
printf("Choose what you would like to do:\n");
printf("1. Find the minimum value.\n");
printf("2. Find the maximum value.\n");
printf("3. Calculate the sum of all the values.\n");
printf("4. Calculate the average of all the values.\n");
printf("5. Sort the values in ascending order.\n");
printf("6. Select a different data set.\n");
printf("7. Exit the program.\n");
scanf(" %d", &command);
if (command == 7) {
exit_program();
} else if (command == 6) {
change_term(number, sets);
}
printf("====================================\n");
}
}
Any weird printf statements you may see are just me trying to make sure things are doing what they're supposed to. Let me know if you need more information from me. Thanks.
You have multiple bugs in your code and several stylistic issues. Have you tried running the code in the debugger to see exactly where things are crashing? Have you tried narrowing the code down to a smaller problem?
Your sizes array should have an element type of int instead of int *. You are dereferencing uninitialized memory since you have not allocated anything for the pointers. Your data_set variable is also uninitialized so the array access into sets is also undefined.
You should initialize all of your variables immediately upon definition. Also I would change your code to declare only one variable per statement. The current code is quite difficult to read.
I would also change your initial while loop into a for loop.
Here's a working version that doesn't crash; although, since you haven't included all of the code, I don't know if there are other parts that are broken. I've also had to remove the references to the undefined functions:
#include <stdio.h>
#include <stdlib.h>
int construct_data_sets(int *sets[], int count) {
int set_size;
int j;
printf("Enter the number of elements in data set %d: ", count+1);
scanf(" %d", &set_size);
sets[count] = (int *) malloc((sizeof(int) * set_size));
if (sets[count] == NULL) {
fprintf(stderr, "Malloc failed!\n");
exit(-1);
}
printf("Enter the data for set %d: ", count+1);
for (j = 0; j < set_size; ++j) {
scanf(" %d", &sets[count][j]);
}
return set_size;
}
int main(int argc, char *argv[]) {
int command = 0;
int number = 1;
int *sets[number], i, sizes[number];
for (i = 0; i < number; ++i) {
sizes[i] = construct_data_sets(sets, i);
}
printf("Data at [0][1] = %d\n", sets[0][1]);
while (command != 7) {
printf("Choose what you would like to do:\n");
printf("1. Find the minimum value.\n");
printf("2. Find the maximum value.\n");
printf("3. Calculate the sum of all the values.\n");
printf("4. Calculate the average of all the values.\n");
printf("5. Sort the values in ascending order.\n");
printf("6. Select a different data set.\n");
printf("7. Exit the program.\n");
scanf(" %d", &command);
if (command == 7) {
return 0;
} else if (command == 6) {
return 0;
}
printf("====================================\n");
}
return 0;
}

C - Alphabetically sorting arrays error

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;
}
}
}

Resources