How to sort a group of structures in C - c

I made a 4 variables structures and assigned values just to age.
struct database {
int id_number;
int age;
float salary;
};
main()
{
struct database employee[4];
struct database current; // Used later in my attempted sorting
employee[1].age = 12;
employee[2].age = 112;
employee[3].age = 2;
employee[4].age = 22;
I tried various ways to attempt to sort these but all failed,
for example:
for(i = 0; i < 4; i++)
{
current = employee[i];//"current" was previously assigned to the same type of struct
j = i;
while(employee[j-1].age > current.age)
{
employee[j] = employee[j-1];
j = j-1;
}
employee[j] = current;
}

Many errors, as pointed by others in comments.
(Out of bound array access, sorting algorithm is not correct, etc. )
For sorting array of struct, simplest way would be to use qsort
where you need to define a custom comparator, something like following :
typedef struct database db;
int sort_by_age(void *a, void *b)
{
db *_a = (db *)a;
db *_b = (db *)b;
if( _a->age > _b->age ) return -1;
if( _a->age == _b->age ) return 0;
return 1;
}
And then use it like,
int no_of_employee = 4;
qsort( employee, no_of_employee, sizeof(db), sort_by_age );

Related

creating a variable name during runtime in C

I wonder if anyone could kindly help me out? I have the following basic struct that holds subject scores for students:
typedef struct student{
char name[25];
int maths,
science,
english,
age;
} student;
I've created an array of this type and populated with data. I wrote 3 functions that work out the highest and lowest scores per subject. These functions are almost identical, but the only difference is the subjects they're working on, for example to work out min/max scores for maths
void highestAndLowestMaths(student s1[]){
int highest = s1[0].maths, highestPos = 0,
lowest = s1[0].maths, lowestPos = 0;
for( int x = 1; x < MAX_RECS; x++ ){
if( s1[x].maths > highest ){
highest = s1[x].maths;
highestPos = x;
}
if( s1[x].maths < lowest ){
lowest = s1[x].maths;
lowestPos = x;
}
}
// then display details of highest/lowest in maths etc..
The other 2 functions for science and english are identical and the only part of the code that needs to change is s1[x].maths to s1[x].science and s1[x].english respectively.
So rather than write 3 separate and almost identical functions, could this not be achieved by altering the s1[x].maths/science/english section of code, that would update depending on another parameter passed?
The nearest I got to solving this involved sending a char array:
void allHighestLowest(student s1[], char subject[]){
int highest = -1, highestPos = 0,
lowest = 101, lowestPos = 0,
option;
if(strcmp(subject, "MATHS") == 0){
option = 0;
} else if(strcmp(subject, "SCIENCE") == 0){
option = 1;
} else if( strcmp(subject, "ENGLISH" ) == 0){
option = 2;
} else {
printf("Invalid subject:\t[%s]\nExiting...\n", subject);
exit(1);
}
int member[3];
for(int x = 0; x < MAX_RECS; x++){
member[0] = s1[x].maths;
member[1] = s1[x].science;
member[2] = s1[x].english;
if(member[option] > highest){
highest = member[option];
highestPos = x;
}
if(member[option] < lowest){
lowest = member[option];
lowestPos = x;
}
}
// then display details of highest/lowest in chosen subject etc..
Although it works, I'm sure there has to be a better way to dynamically create the line of code to s1[x].maths/science/english during runtime, rather than using a temp array to grab the values as shown above? The struct itself could change and have many more members added, so I'm looking for the best solution, rather than duplicating functions and code.
Can anyone point me in the right directions? Thanks in advance!
One way of doing this is to provide an accessor function as a parameter to allHighestLowest:
typedef int (*fn_getter)(student *s);
int get_maths(student *s) { return s->maths; }
int get_science(student *s) { return s->science; }
int get_english(student *s) { return s->english; }
void highestAndLowest(student s1[], fn_getter getter)
{
// code here
}
Now, instead of accessing maths, science, and english directly you do:
if (getter(&s1[x]) > highest) {
highest = getter(&s1[x]);
highestPos = x;
}
if (getter(&s1[x]) < lowest) {
lowest = getter(&s1[x]);
lowestPos = x;
}
So instead of calling highestAndLowestMaths(students_list) you now do highestAndLowest(students_list, get_maths).
Note: I wrote the example code without having access to a compiler so it might contain some small errors or typos.
For details about function pointers see this question.
This is the kind of thing that simply doesn't work well in C. The C language is intended for low level programming, and not high level data abstractions.
You could do something like this:
enum subject { MATH, SCIENCE, ENGLISH };
typedef struct student{
char name[25];
int subject[3];
int age;
} student;
and then something like this:
void highestAndLowest(student s1[], enum subject s){
int highest = s1[0].subject[s],
lowest = highest, // Removed code duplication
highestPos = 0,
lowestPos = 0;
for( int x = 1; x < MAX_RECS; x++ ){
if( s1[x].subject[s] > highest ){
highest = s1[x].subject[s];
highestPos = x;
}
if( s1[x].subject[s] < lowest ){
lowest = s1[x].subject[s];
lowestPos = x;
}
}
...
If you want to do this as neatly as in Python, then code Python.

Problem organizing a data set chronologically

I'm here asking for your help, not because I have an error, but simply because of this solution that in my head seemed quite credible despite not working.
I basically have a structure to make an appointment and I created a variable of this temporary structure to change the values ​​so that they are in ascending order, however when I show the query table in this case, but the queries appear in the order I registered them in the program.
My Struct:
typedef struct Consulta {
char nomeUtente[70];
int numSNS;
int dia;
int mes;
int ano;
int horasInicio;
int minutosInicio;
int horasFim;
int minutosFim;
} consulta;
My function that should order the values:
void organizarAgenda(int membroEscolhido, consulta agenda[][50][50], int clinicaSelecionada, int *nFuncionarios, int *nAgendas)
{
int i, j;
boolean substituir;
consulta temp;
for (i = 0; i < nAgendas[membroEscolhido]; i++)
{
for (j = 0; j < nAgendas[membroEscolhido]; j++)
if (agenda[j][membroEscolhido][clinicaSelecionada].ano > agenda[i][membroEscolhido][clinicaSelecionada].ano)
substituir = true;
if (agenda[j][membroEscolhido][clinicaSelecionada].ano == agenda[i][membroEscolhido][clinicaSelecionada].ano
&& (agenda[j][membroEscolhido][clinicaSelecionada].mes > agenda[i][membroEscolhido][clinicaSelecionada].mes))
substituir = true;
if (agenda[j][membroEscolhido][clinicaSelecionada].ano == agenda[i][membroEscolhido][clinicaSelecionada].ano
&& (agenda[j][membroEscolhido][clinicaSelecionada].mes == agenda[i][membroEscolhido][clinicaSelecionada].mes)
&& (agenda[j][membroEscolhido][clinicaSelecionada].dia > agenda[i][membroEscolhido][clinicaSelecionada].dia))
substituir = true;
if (agenda[j][membroEscolhido][clinicaSelecionada].ano == agenda[i][membroEscolhido][clinicaSelecionada].ano
&& (agenda[j][membroEscolhido][clinicaSelecionada].mes == agenda[i][membroEscolhido][clinicaSelecionada].mes)
&& (agenda[j][membroEscolhido][clinicaSelecionada].dia == agenda[i][membroEscolhido][clinicaSelecionada].dia
&& agenda[j][membroEscolhido][clinicaSelecionada].horasInicio >= agenda[i][membroEscolhido][clinicaSelecionada].horasInicio))
substituir = true;
if (substituir == true)
{
//Igualar a variavel temporario á variável agenda em i
temp.ano = agenda[i][membroEscolhido][clinicaSelecionada].ano;
temp.mes = agenda[i][membroEscolhido][clinicaSelecionada].mes;
temp.dia = agenda[i][membroEscolhido][clinicaSelecionada].dia;
temp.horasInicio = agenda[i][membroEscolhido][clinicaSelecionada].horasInicio;
temp.minutosInicio = agenda[i][membroEscolhido][clinicaSelecionada].minutosInicio;
temp.horasFim = agenda[i][membroEscolhido][clinicaSelecionada].horasFim;
temp.minutosFim = agenda[i][membroEscolhido][clinicaSelecionada].minutosFim;
//Igualar a variável agenda em i á variável agenda em j
agenda[i][membroEscolhido][clinicaSelecionada].ano = agenda[j][membroEscolhido][clinicaSelecionada].ano;
agenda[i][membroEscolhido][clinicaSelecionada].mes = agenda[j][membroEscolhido][clinicaSelecionada].mes;
agenda[i][membroEscolhido][clinicaSelecionada].dia = agenda[j][membroEscolhido][clinicaSelecionada].dia;
agenda[i][membroEscolhido][clinicaSelecionada].horasInicio = agenda[j][membroEscolhido][clinicaSelecionada].horasInicio;
agenda[i][membroEscolhido][clinicaSelecionada].minutosInicio = agenda[j][membroEscolhido][clinicaSelecionada].minutosInicio;
agenda[i][membroEscolhido][clinicaSelecionada].horasFim = agenda[j][membroEscolhido][clinicaSelecionada].horasFim;
agenda[i][membroEscolhido][clinicaSelecionada].minutosFim = agenda[j][membroEscolhido][clinicaSelecionada].minutosFim;
//Igualar a variável agenda em j á variavel temporaria
agenda[j][membroEscolhido][clinicaSelecionada].ano = temp.ano;
agenda[j][membroEscolhido][clinicaSelecionada].mes = temp.mes;
agenda[j][membroEscolhido][clinicaSelecionada].dia = temp.dia;
agenda[j][membroEscolhido][clinicaSelecionada].horasInicio = temp.horasInicio;
agenda[j][membroEscolhido][clinicaSelecionada].minutosInicio = temp.minutosInicio;
agenda[j][membroEscolhido][clinicaSelecionada].horasFim = temp.horasFim;
agenda[j][membroEscolhido][clinicaSelecionada].minutosFim = temp.minutosFim;
}
}
Thank you all in advance!
substituir is unitialized. You need to set it to false immediately after the for statement for j.
Your for loop for j is missing a trailing { so it will only iterate over the first if and not the others [as you would probably like]
As I mentioned in my comment, simplify [please ;-)]. Use pointers to simplify the code.
Your indexing is quite complex, so I can only guess at things.
I changed the comparison logic to something I understand.
Here's a simplified version. I just coded it, so it may not compile. But, it should give you some ideas how to proceed:
typedef struct Consulta {
char nomeUtente[70];
int numSNS;
int dia;
int mes;
int ano;
int horasInicio;
int minutosInicio;
int horasFim;
int minutosFim;
} consulta;
void
organizarAgenda(int membroEscolhido, consulta agenda[][50][50],
int clinicaSelecionada, int *nFuncionarios, int *nAgendas)
{
int i;
int j;
int lim = nAgendas[membroEscolhido];
int dif;
consulta temp;
for (i = 0; i < lim; i++) {
consulta *iptr = &agenda[i][membroEscolhido][clinicaSelecionada];
for (j = 0; j < lim; j++) {
consulta *jptr = &agenda[j][membroEscolhido][clinicaSelecionada];
do {
dif = iptr->ano - jptr->ano;
if (dif)
break;
dif = iptr->mes - jptr->mes;
if (dif)
break;
dif = iptr->dia - jptr->dia;
if (dif)
break;
} while (0);
if (dif <= 0)
continue;
temp = *iptr;
*iptr = *jptr;
*jptr = temp;
}
}
}
I'm [still] guessing but I think you can get a [significant] speedup by changing the for loop for j.
And, I think the for loop for i goes one too far.
So, consider:
for (i = 0; i < (lim - 1); i++) {
consulta *iptr = &agenda[i][membroEscolhido][clinicaSelecionada];
for (j = i + 1; j < lim; j++) {
consulta *jptr = &agenda[j][membroEscolhido][clinicaSelecionada];
UPDATE:
I didn't understand how a 3d array with only a 2d array assignment works int lim = nAgendas[membroEscolhido];
The value of nAgendas[membroEscolhido] is invariant across the function, so it can be "cached". I did this to simplify the code [mostly] but it also can help the compiler generate more efficient code.
I didn't notice the (-) in the middle of this line, and the -> works because it is a pointer pointing to the struct, right?
Right. The arrow operator (->) is a very powerful way to access individual struct members if you have a pointer to the given struct instance.
Note that the compiler's optimizer might be able to see that all the variables of the form: array[x][y][z].whatever could be reduced.
But, when we use intermediate pointers we're giving it a [better] clue as to what we want. And, the code is more readable by humans, so it has two good reasons to do it.
I don't understand why you put while (0)
This is a bit of a trick [of mine] to replace an if/else ladder with something that is cleaner.
It forms a "once through" loop. It would be the equivalent of:
while (1) {
if (something)
break;
if (something_else)
break;
break; // make the loop execute _only_ once
}
For a more detailed explanation, see my answer: About the exclusiveness of the cases of an if block

How do I sort an array of structs in C by name, age and id?

I don't know how to make a function to sort an array of structs by the values. Any tips are helpful.
I am confused how to pass the values into a function and then sort the list of structs by the age, then name.
I want to see how to organize the array of structs as I will later have to use multiple files with names, ages, ids.
//- Functions needed
//Swap
//Selection sort
//Bubble sort
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct person
{
int age;
double id;
char name[64];
} person;
int main()
{
person **array = calloc(2, sizeof(person*));
int sizes[2];
for (int i = 0; i < 5; i++) {
array[i] = calloc(sizes[i], sizeof(person));
}
//Num1
strcpy(array[1][0].name, "0yblTP");
array[1][0].id = 7.567;
array[1][0].age = 34;
//Num 2
strcpy(array[1][1].name, "t700nwzB");
array[1][1].id = 8.6576;
array[1][1].age = 85;
//Num3
strcpy(array[1][2].name, "Vx8eR");
array[1][2].id = 179;
array[1][2].age = 59;
//Num4
strcpy(array[1][3].name, "n5FUgA");
array[1][3].id = 1.082797;
array[1][3].age = 45;
//Num5
strcpy(array[1][4].name, "Bzm9dq");
array[1][4].id = 179;
array[1][4].age = 23;
}
i think 'send an array of person' to sort function and sorting them in the function is good to solve your problem.
void main {
//Swap (&person, &person) === Swap(&array[1][i], &array[i][j])
//Selection sort(array[1])
//Bubble sort(array[1])
}
like this. this will send address of your person array to each sorting function, so you just need to execute each function inside.
void selectionSort(person*) {
for(int i = 0; i < length of person array; i++) {
(algorithm for sorting your person by age, name)
you can use them by person[i].age
}
}
like this.
i think it is better than your skill to put struct to an array
person* A = calloc..
A.name = ".."
A.id = ".."
A.age = ".."
//and then put your struct in the array
array[1][i] = A;

Segmentation Fault when returning integer

I recently joined Stackoverflow community because I had to ask this question. I've been searching for possible explanations and solutions on the website but so far nothing enlightened me as I wanted. My error is probably caused by a very specific line of code. I'm trying to create a function that reads an array of struct votes, (struct contains integer member number, char *category, char *nominee) and copies all the votes that contain the same number and category to another array of struct. Basically to show all the repeated votes.
typedef struct
{
int member;
char *categ;
char *nom;
}Vote
Vote vote(int member, char *categ, char *nom)
{
Vote result;
result.member = member;
result.categ = categ;
result.nom = nom;
return result;
}
int votes_count(Vote *v, int n, Vote *v1)
{
int result = 0;
int *index = malloc(sizeof(int) * 1000);
int a = 0;
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
if (a == 0 && v[i].member == v[j].member && strcmp(v[i].categ, v[j].categ) == 0)
{
v1[result++] = vote(v[j].member, str_dup(v[j].categ), str_dup(v[j].nom));
index[a++] = j;
}
for (int b = 0; b < a; ++b)
{
if( a > 0 && v[i].member == v[j].member && strcmp(v[i].categ, v[j].categ) == 0 && j != index[b])
{
v1[result++] = voto(v[j].member, str_dup(v[j].categ), str_dup(v[j].nom));
index[a++] = j;
}
}
}
}
return result;
}
Afterwads, it returns the number of elements of new array that contains all repetitions. I want to use an array of ints to save all line indexes so that the function doesn't read and copy the lines it already accounted.
Sorry if the code is hard to understand, if needed I can edit to be more understandable. Thanks for any answears.
P.S: I'm portuguese, sorry in advance for grammar mistakes
if your only intention is to harvest the duplicates, you only need to compare to the elements that came before an element
you don't need the index[] array
For simplicity, I used two integer arrays, you should change them to your struct arrays, also change the compare function.
unsigned fetchdups(int orig[], int dups[], unsigned count)
{
unsigned this, that, ndup=0;
for (this=1; this<count; this++){
for (that=0; that<this; that++){
/* change this to your compare() */
if(orig[that] == orig[this]) break;
}
if (this == that) continue; /* no duplicate */
dups[ndup++] = this;
}
return ndup;
}

Order array of struct by one chosen attribute in C

I'm having trouble while ordering an array of a struct that contains 3 infos types. I want to order using one of the info, then organize the other 2 infos, but I'm using heapsort and don't know how I would change the code to automatically reorganize. There is any logical hint that would help me? here's the struct
typedef struct{
int orig;
int dest;
float cost;
}infos;
thanks. i can add any info that help you people help me!
[EDIT]
void build ( Armaz x[], int n ){
int i;
float val;
int s;
int f;
for (i = 1; i<n; i++){
val = x[i].cost;
s = i;
f = (s-1)/2;
while (s>0 && x[f].cost<val){
x[s].cost = x[f].cost;
s = f;
f = (s-1) / 2;
}
x[s].cost = val;
}
}
void heapsort (infos x[], int n){
build(x,n);
int i;
int s;
int f;
float vali ;
for (i = n - 1 ; i > 0 ; i--){
vali = x[i].cost;
x[i].cost = x[0].cost;
f = 0 ;
if (i == 1){
s = -1;
}
else s = 1;
if ( i > 2 && x[2].cost > x[1].cost) s = 2 ;
while ( s >= 0 && vali < x[s].cost){
x[f].cost = x[s].cost;
f = s;
s = 2 * f + 1;
if ( s + 1 <= i - 1 && x[s].cost < x[s + 1].cost ) s++;
if (s > i-1) s = -1;
}
x[f].cost = vali;
}
}
Even if you implement your own sorting functions, I recommend you take a closer look at how the standard qsort function works.
In short: It has an argument that is a pointer to a function used for comparison. That function receives pointers to two "objects" that should be compared, and can do whatever it wants to compare the two "objects". That means one could have three different comparison functions, one for each member of your structure, and pass the appropriate one when needed.

Resources