C: how sort and subsort values in a structure - c

After hours of thinking and tinkering I almost gave up but decided to turn to the community for their help. I'm new to C and I just learned bubble sort. For example the following code sorts by name, what I would like to implement is a sub sort where it also sorts by person ID, how would I do that or change the following code to do just that? (This is structure problem).
struct human {
char name;
char id;
}
function sorting(struct human person)
{
struct human temp
int i, unsorted;
do{
unsorted = 0;
for(i = o; i<count-1; i++)
{
if(strcmp(person[i].name, person.name) > 0)
{
temp = person[i];
person[i] = person[i+1];
person[i+1] = temp;
unsorted = 1;
}
}while(unsorted);
}

First, it would help to break out your comparison function into its own function:
int compare_people(struct human *person1, struct human *person2)
{
return strcmp(person1->name, person2->name);
}
Then, you can more easily change the logic to compare ID if the name is equal:
int compare_people(struct human *person1, struct human *person2)
{
int d = strcmp(person1->name, person2->name);
if (d == 0) {
return person2->id - person1->id;
} else {
return d;
}
}

Related

Searching for a string in a struct

The code below is a code that will track my product costs and remaining quantity.The problem I'm facing with is I can't search the code by
if(g[n].name == search[10])
The out put keep showing
"Item not found"
Im a beginner of c language and was hope to learn more. Please correct my code and send it here so that I can know why my code is wrong.
#include <stdio.h>
struct product
{
char name[10];
int quantity;
float costs;
};
void fn_search (struct product g[]);
int main ()
{
int n;
struct product g[4];
strcpy(g[0].name,"aa1");
g[0].quantity = 10;
g[0].costs = 1;
strcpy(g[1].name,"bb2");
g[1].quantity = 10;
g[1].costs = 2;
strcpy(g[2].name,"bb3");
g[2].quantity = 10;
g[2].costs = 3;
fn_search (g);
}
void fn_search (struct product g[10])
{
int n;
char search[10];
printf("Search>> ");
scanf("%s",&search[10]);
for (n=0;n<4;n++)
{
if(g[n].name == search[10])
{
printf ("\ncosts = NTD%.2f",g[n].costs);
printf ("\nquantity = %d\n",g[n].quantity);
}
else
{
printf("\nItem not found.");
break;
}
}
}
Two bugs:
Incorrect use of scanf :
scanf("%s",&search[10]); --> scanf("%9s", search);
Note: scanf("%9s", &search[0]); is also fine but the above is the common way.
Incorrect string compare :
if(g[n].name == search[10]) --> if(strcmp(g[n].name, search) == 0)
Also notice that you never initialized g[3] but fn_search checks it.
Then this part:
else
{
printf("\nItem not found.");
break;
}
means that you break the for loop as soon as an item doesn't match. In other words: Currently you only compare against g[0]
You don't want that! Check all items before printing "Item not found".
So the for loop should be more like:
for (n=0;n<4;n++)
{
if(strcmp(g[n].name, search) == 0)
{
printf ("\ncosts = NTD%.2f",g[n].costs);
printf ("\nquantity = %d\n",g[n].quantity);
return; // Exit function when match is found
}
}
// When execution arrives here, there was no matching element
printf("\nItem not found.");
Finally:
void fn_search (struct product g[10])
^^
why ??
Either do
void fn_search (struct product g[])
or
void fn_search (struct product *g)

Recursive function to represent binary tree in C

Problem
I want to print the nodes of a binary tree inorder and would like to have the nodes printed with as many dashes as the height they are in and then it's data.
Research done
I have found other posts like this one or this one but I'm still clueless on how I can represent my binary tree the way I want, as it differs to the ones stated on those questions.
Example
So lets say I insert nodes with data in this manner:
5,4,2,3,9,8
The output I would expect when representing the binary tree would be:
-9
--8
5
-4
---3
--2
Toy example code
So far I was able to print the nodes in the correct order. But after days I'm still clueless on how to implement a recursive function to get the correct representation. I also tried loops but found it's even messier and wasn't getting the correct result either.
The problem is that the amount of dashes is not the correct one and I'm unsure on where I need to append the dashes within the recursion. I'm thinking I may need to rewrite the whole printBinaryTreeRecurrsively code.
Below you can see the toy example code which can be compiled as a whole:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct repBinaryTree *BinaryTree;
struct repBinaryTree {
int data;
BinaryTree left;
BinaryTree right;
};
BinaryTree newNode() {
BinaryTree b = new repBinaryTree;
b->data = NULL;
b->left = b->right = NULL;
return b;
}
BinaryTree insertNode(int i, BinaryTree b) {
if (b==NULL) {
b = newNode();
b->data = i;
} else if ( i < b->data ) {
if (b->left == NULL) {
b->left = newNode();
b->left->data = i;
} else {
insertNode(i, b->left);
}
} else if ( i > b->data ) {
if (b->right == NULL) {
b->right = newNode();
b->right->data = i;
} else {
insertNode(i, b->right);
}
}
return b;
}
char* printBinaryTreeRecurrsively(BinaryTree b, char level[]) {
if (b == NULL) {
printf("\n");
return level;
} else {
level = printBinaryTreeRecurrsively(b->right, level);
printf("%s%d",level,b->data);
level = printBinaryTreeRecurrsively(b->left, level);
}
strcat(level,"-");
return level;
}
int main () {
BinaryTree b = insertNode(5,NULL);
b = insertNode(4, b);
b = insertNode(2, b);
b = insertNode(3, b);
b = insertNode(9, b);
b = insertNode(8, b);
printf("Recursive BinaryTree print:");
char level0[] = "";
printBinaryTreeRecurrsively(b, level0);
printf("Expected BinaryTree print:");
printf("\n-9\n--8\n5\n-4\n---3\n--2\n");
}
The output I get after compiling and running the program from command line is as follows:
cedric#multivac:~$ g++ printBinaryTree.cpp -o printBinaryTree
cedric#multivac:~$ ./printBinaryTree
Recursive BinaryTree print:
9
8
--5
--4
--3
---2
Expected BinaryTree print:
-9
--8
5
-4
---3
--2
Question
How should I rewrite my printBinaryTreeRecurrsively function code so as I get the correct output?
Modify the function to this instead
void printBinaryTreeRecurrsively(BinaryTree b, int level) {
if (b == NULL) {
printf("\n");
} else {
printBinaryTreeRecurrsively(b->right, level+1);
for (int i = 0; i < level; i++) {
printf("-");
}
printf("%d",b->data);
printBinaryTreeRecurrsively(b->left, level+1);
}
}
and call in main() as
printBinaryTreeRecurrsively(b, 0);
This method is much simpler than worrying about string concatenation etc. Just keep track of which level you're on with an int, print the correct number of -, and tell the levels below to print with one more -.

Exit code 11 on extractMin() in PriorityQueue in C'99

I'm new in C programming. I'm developing a priority queue in C'99 with the heap data structure.
I'm using heapifyDown() in combination with swapValues() to sort the heap array for extracting the first element (min-heap) pqueue_extractMin() function. My structure looks like this:
typedef struct ProrityQueue_s PriorityQueue;
typedef struct PriorityQueue_Entry_s *PriorityQueue_Entry;
struct ProrityQueue_s {
int size, last;
char error;
PriorityQueue_Entry *entries;
};
struct PriorityQueue_Entry_s {
char *value;
float priority;
};
For information – Full code for information on gist: https://gist.github.com/it4need/ddf9014bfda9fe6a64bb01a7417422bc
Questions:
Insertion into the Priority queue ("minheap") looks good. Everything is fine. But when I'm extract more than one element at once, I will get this error: "Process finished with exit code 11".
Is this line allowed to copy the whole contents of the last element to the first of the heap? priorityqueue->entries[0] = priorityqueue->entries[priorityqueue->last];
swapValues(priorityqueue, currentPositionIndex, smallestChild); Can I swap values of whole Structure elements? -> implementation (bottom).
HeapifyDown():
void heapifyDown(PriorityQueue *priorityqueue)
{
int currentPositionIndex = 0;
while(currentPositionIndex < priorityqueue->last)
{
int smallestChild = currentPositionIndex;
int leftChildIndex = (2 * currentPositionIndex) + 1;
int rightChildIndex = (2 * currentPositionIndex) + 2;
smallestChild = (priorityqueue->entries[leftChildIndex]->priority < priorityqueue->entries[smallestChild]->priority && priorityqueue->last > leftChildIndex)
? leftChildIndex : smallestChild;
smallestChild = (priorityqueue->entries[rightChildIndex]->priority < priorityqueue->entries[smallestChild]->priority && priorityqueue->last > rightChildIndex)
? rightChildIndex : smallestChild;
if(smallestChild == currentPositionIndex)
{
break;
}
swapValues(priorityqueue, currentPositionIndex, smallestChild); // #todo: Why does this line break the function on two function calls by negative values
currentPositionIndex = smallestChild;
}
}
SwapValues():
void swapValues(PriorityQueue *priorityqueue, int firstIndex, int secondIndex)
{
// #todo: Does this work properly?
PriorityQueue_Entry tmp_entry = priorityqueue->entries[firstIndex];
priorityqueue->entries[firstIndex] = priorityqueue->entries[secondIndex];
priorityqueue->entries[secondIndex] = tmp_entry;
}
extractMin():
char *pqueue_extractMin(PriorityQueue *priorityqueue)
{
if(isEmpty(priorityqueue))
{
priorityqueue->error = ERROR_PRIORITY_QUEUE_EMPTY;
}
priorityqueue->last--;
char *tmp = priorityqueue->entries[0]->value;
priorityqueue->entries[0] = priorityqueue->entries[priorityqueue->last]; // #todo: Is this allowed?
heapifyDown(priorityqueue); // #todo: Why does this line break the extractMin() function on two function calls -> check swapValues() in heapifyDown()
return tmp;
}
Full code for information on gist: https://gist.github.com/it4need/ddf9014bfda9fe6a64bb01a7417422bc

C: Make generic iteration function?

I have an struct which defines an array of structs, each of which contain a couple more arrays. These inner arrays define my 'datasets'.
In numerous places, I wish to iterate over all the datasets. To avoid 3 nested loops, I loop over the total number of datasets and have a few if statements to keep track of which array I need to access. It looks like this:
int datasetCount = 0;
int defendedDatasetCount = 0;
int i;
Dataset *ds;
for (i = 0 ; i < totalDatasets ; i++)
{
// If we have passed the number of datasets in this group, move to the next group
if (datasetCount == (dg->nDatasets + dg->nDefDatasets))
{
dg++;
datasetCount = 0;
defendedDatasetCount = 0;
}
// If we have gone through all the (undefended) datasets, read from thte defended datasets
if (datasetCount >= dg->nDatasets)
{
ds = &(dg->defDatasets[defendedDatasetCount]);
defendedDatasetCount++;
}
else
{
ds = &(dg->datasets[datasetCount]);
}
where dg is the pointer to a struct which is simply an array of structs and a size counter.
I find myself repeating this boilerplate code for iterating through the datasets in a few functions which do different things.
I'm struggling to be able to come up with something like this:
while (give_me_next_dataset(dg) == TRUE)
{
...
}
is it possible?
It's possible, but the proposed API isn't very nice. You're going to have to put iteration state somewhere, and you're not leaving any room for that.
I would propose something like:
struct DgIter {
struct Dg *dg;
size_t index;
size_t dataSet;
};
Then you can have functions like:
struct DgIter iter_start(struct Dg *dg)
{
const struct DgIter iter = { dg, 0, 0 };
return iter;
}
void * iter_next_dataset(struct DgIter *iter)
{
// check if there is a current dataset, else return NULL
// update fields in iter as necessary
}

pointers with structs in structs c

I have tried to create a CD struct like :
typedef struct
{
char* nameCD;
int yearOfpublication;
song* listOfSongs;
int priceCD;
int numberOfSongs;
} CD;
and I have a song struct :
typedef struct
{
char* nameSong;
char* nameSinger;
int lenghtOfSong;
} song;
void SongInput(song *psong, CD *pcd)
{
pcd->numberOfSongs++;
pcd->listOfSongs = (song*)malloc(pmcd->numberOfSongs*sizeof(song));
// here all the code that update one song..
but what should I write to update the next song?
how do I change it into an array which update the number of the songs and how can I save all the songs?
I tried this :
printf("Enter lenght Of Song:");
scanf("%d", &psong->lenghtOfSong);
but I don't understand the pointers..
and how to update the next song?
}
void CDInput(CD *pcd)
{
int numberOfSongs = 0;
//here all the other update of cd.
//songs!!!!!!!!!!!!!!!!!!!!!!!!!!!!
pcd->numberOfSongs = 0;
pcd->listOfSongs = (song*)malloc(numberOfSongs*sizeof(song));
}
Do I need to write anything else?
void CDInput(CD *pcd)
{
int i;
//...
printf("Enter number Of Song:");
scanf("%d", &pcd->numberOfSongs);
pcd->listOfSongs = (song*)malloc(pcd->numberOfSongs*sizeof(song));
for(i = 0; i < pcd->numberOfSongs; ++i){
SongInput(&pcd->listOfSongs[i]);
}
//...
}
It depends on if you want to write the structure once completely or you really want to add one item.
For the first case, please refer to BLUEPIXY's answer, for the second one, thigs are slightly more complicated.
bool add_song(song *psong, CD *pcd)
{
song* newone = realloc(pcd->listOfSongs, (pmcd->numberOfSongs+1)*sizeof(song));
if (!newone) {
// return and complain; the old remains intact.
return false; // indicating failure.
}
// now we can assign back.
pcd->listOfSongs = newone;
newone[pcd->numberOfSongs++] = *psong;
return true; // indicating success.
}

Resources