Using qsort() with Structs - c

I just started learning C and I'm still new to it.
In this program I'm working with an array of structs. The structs are:
typedef struct {
int day;
int month;
int year;
} Date;
typedef struct {
int serial_num;
char full_name[15];
Date *pDate;
} Person;
The array is Person *people.
Now I have two arrays of people and birth dates of those people (same indexes):
const char* names[MAX] = { "Sasson_Sassoni", "Pooh", "James_Bond", "Elvis_is_Alive", "Shilgiya", "Cleopatra", "Sissoo_VeSimmhoo" };
const int dates[MAX][COLS] = {
{ 10, 1, 1988 },
{ 12, 12, 1948 },
{ 4, 12, 1970 },
{ 11, 11, 1890 },
{ 11, 11, 1948 },
{ 1, 10, 1213 },
{ 12, 11, 1948 }
};
By using switch case, every time the user types 1 a person from the lists (Name and birthday) is added to the list people. Then if the user types 3, the list people should be sorted by date (oldest to youngest). So I wrote the following two functions:
void sortList(Person **people, int index) {
qsort(*people, index, sizeof(Person), intcmp);
}
int intcmp(const void *a, const void *b) {
Person *one = (Person *)a;
Person *two = (Person *)b;
int year1 = one->pDate->year;
int year2 = two->pDate->year;
int month1 = one->pDate->month;
int month2 = two->pDate->month;
int day1 = one->pDate->day;
int day2 = two->pDate->day;
if (year1 > year2)
return -1;
else if (year2 > year1)
return 1;
if (month1 > month2)
return -1;
else if (month2 > month1)
return 1;
if (day1 > day2)
return -1;
else if (day2 > day1)
return 1;
return 0;
}
But every time I get an error saying:
Exception thrown: read access violation.
one->pDate was nullptr.
Any help?
Thanks!
EDIT:
Further explanation: In order to insert the people to the array one by one, I made a variable called index and every time a person is added the index grows by one. So When calling the function qsort(), index is the number of people in the array. Also MAX=7, COLS=3, LEN=10. The function that adds people to the array is:
void addToList(Person **people, int *index, const char *names[MAX], const int dates[][COLS]) {
people[*index] = (Person *)malloc(sizeof(Person));
people[*index]->serial_num = *index + 1;
strcpy(people[*index]->full_name, names[*index]);
Date *temp = (Date *)malloc(sizeof(Date));
temp->day = dates[*index][0];
temp->month = dates[*index][1];
temp->year = dates[*index][2];
people[*index]->pDate = temp;
printf("%d %s %d/%d/%d \n", people[*index]->serial_num, people[*index]->full_name, people[*index]->pDate->day, people[*index]->pDate->month, people[*index]->pDate->year);
*index = *index + 1;
}

Your mcve is not complete but I think it's because you confuse pointer and struct:
void sortList(Person **people, int index) {
qsort(people, index, sizeof(Person *), intcmp);
// or qsort(people, index, sizeof *people, intcmp);
}
int intcmp(const void *a, const void *b) {
const Person *one = *(const Person **)a;
const Person *two = *(const Person **)b;

Related

munmap_chunk(): invalid pointer while freeing a struct in an array

So I wrote a program where I have to realloc an array of structs whenever I want to add something to it.
But when I try to free the array, I free every element individually but I get a munmap_chunk(): invalid pointer at some point.
Here is the full code :
#include <stdlib.h>
#include <string.h>
struct Date {
int day;
int month;
int year;
};
struct Person {
char *name;
char *surname;
struct Date birth;
};
struct Directory {
int size;
struct Person *array;
};
struct Date create_date() {
struct Date date = {
.day = 0,
.month = 0,
.year = 0
};
return date;
}
struct Directory create_directory() {
struct Directory directory = {
.size = 0,
.array = NULL
};
return directory;
}
struct Person *create_person() {
struct Person *person_ptr = (struct Person *) malloc(sizeof(struct Person));
person_ptr->name = NULL;
person_ptr->surname = NULL;
return person_ptr;
}
void copy_date(struct Date *dest, struct Date *src) {
dest->day = src->day;
dest->month = src->month;
dest->year = src->year;
}
void initialize_person(struct Person *person_ptr, char *name, char *surname, struct Date *birth) {
if (name != NULL && surname != NULL && birth != NULL) {
person_ptr->name = realloc((*person_ptr).name, (strlen(name) * sizeof(char)) + 1);
strcpy(person_ptr->name, name);
person_ptr->surname = realloc((*person_ptr).surname, (strlen(surname) * sizeof(char)) + 1);
strcpy(person_ptr->surname, surname);
copy_date(&person_ptr->birth, birth);
}
}
void copy_person(struct Person *dest, struct Person *src) {
dest->name = realloc((*dest).name, (strlen(src->name) * sizeof(char)) + 1);
dest->surname = realloc((*dest).surname, (strlen(src->surname) * sizeof(char)) + 1);
struct Date date = create_date();
dest->birth = date;
strcpy(dest->name, src->name);
strcpy(dest->surname, src->surname);
copy_date(&dest->birth, &src->birth);
}
int add_person(struct Directory *directory_ptr, const struct Person *new_person_ptr) {
int return_code = 0;
directory_ptr->size++;
directory_ptr->array = realloc(directory_ptr->array, (directory_ptr->size * sizeof(struct Person)));
if (directory_ptr->array) {
copy_person(&directory_ptr->array[directory_ptr->size - 1], (struct Person *) new_person_ptr);
} else {
return_code = 1;
}
return return_code;
}
int add_multiple_persons(struct Directory *directory_ptr, const struct Person **persons_ptr, int nb_persons) {
for (int i = 0; i < nb_persons; i++) {
add_person(directory_ptr, (persons_ptr[i]));
}
return 0;
}
void destroy_person(struct Person *person_ptr) {
free(person_ptr->name);
person_ptr->name = NULL;
free(person_ptr->surname);
person_ptr->surname = NULL;
free(person_ptr);
person_ptr = NULL;
}
void destroy_directory(struct Directory *directory_ptr) {
if (directory_ptr->array) {
for (int i = 0; i < directory_ptr->size; i++) {
destroy_person(&directory_ptr->array[i]);
}
directory_ptr->array = NULL;
directory_ptr->size = 0;
}
}
int main(void) {
struct Directory directory = create_directory();
struct Person *person1 = create_person();
struct Person *person2 = create_person();
struct Person *person3 = create_person();
struct Date date = {
.day = 17,
.month = 04,
.year = 1999};
initialize_person(person1, "Marcel", "Juan", &date);
initialize_person(person2, "Albin", "Michel", &date);
initialize_person(person3, "Suzerain", "Bernard", &date);
const struct Person *array[] = {
person1,
person2,
person3
};
add_multiple_persons(&directory, array, 3);
destroy_person(person1);
destroy_person(person2);
destroy_person(person3);
destroy_directory(&directory);
return 0;
}
I've been on this error for more than a week, and it keeps bugging me.
How can I fix this ?
In the destroy_directory function, you freed the persons contained by the array. But in this array you didn't put pointers to structures but the structures themselves. Therefore you must free the space you allocated for the array and nothing else :
void destroy_directory(struct Directory *directory_ptr) {
if (directory_ptr->array) {
free(directory_ptr->array); //<==== Here
directory_ptr->array = NULL;
directory_ptr->size = 0;
}
}
person_ptr is a part of the memory allocated at directory_ptr->array. You need to remove this line.
As a rule of gold, memory responsible is the same while allocation and while freeing. In your code, the person holder is the array inside directory_ptr, which is allocated by add_person. Despite its name, it is a directory manager, so freeing its memory should be done only on directory destroyer.

Sort an array of structs by different members

I need to sort an array of structs each having members with different data types using qsort.
typedef struct {
char* name;
int age;
float wage;
} employee;
The question is, do I have to write 3 different comparator functions for each of them or is there a nice way to implement 1 function?
In any case you need to write a separate function for each data member by which the array will be sorted because within the function you need to compare values of concrete data members.
However you can write a general function that will supply the required comparison function for a call of qsort.
Here is a demonstrative program.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
char* name;
int age;
float wage;
} employee;
int cmp_by_name( const void *a, const void *b )
{
const employee *first = a;
const employee *second = b;
return strcmp( first->name, second->name );
}
int cmp_by_age( const void *a, const void *b )
{
const employee *first = a;
const employee *second = b;
return ( second->age < first->age ) - ( first->age < second->age );
}
int cmp_by_wage( const void *a, const void *b )
{
const employee *first = a;
const employee *second = b;
return ( second->wage < first->wage ) - ( first->wage < second->wage );
}
enum SortBy { ByName, ByAge, ByWage };
int ( *select( enum SortBy sort_by ) )( const void *, const void * )
{
int ( *cmp[] )( const void *, const void * ) =
{
cmp_by_name, cmp_by_age, cmp_by_wage
};
switch ( sort_by )
{
default:
case ByName:
return cmp[ByName];
case ByAge:
return cmp[ByAge];
case ByWage:
return cmp[ByWage];
}
}
int main(void)
{
enum { N = 3 };
employee e[N] =
{
{ "Tom", 18, 3500.0f },
{ "Bob", 26, 4500.0f },
{ "Jim", 28, 4000.0f }
};
for ( size_t i = 0; i < N; i++ )
{
printf( "%s, %d, %f\n", e[i].name, e[i].age, e[i].wage );
}
putchar( '\n' );
qsort( e, N, sizeof( employee ), select( ByName ) );
for ( size_t i = 0; i < N; i++ )
{
printf( "%s, %d, %f\n", e[i].name, e[i].age, e[i].wage );
}
putchar( '\n' );
qsort( e, N, sizeof( employee ), select( ByAge ) );
for ( size_t i = 0; i < N; i++ )
{
printf( "%s, %d, %f\n", e[i].name, e[i].age, e[i].wage );
}
putchar( '\n' );
qsort( e, N, sizeof( employee ), select( ByWage ) );
for ( size_t i = 0; i < N; i++ )
{
printf( "%s, %d, %f\n", e[i].name, e[i].age, e[i].wage );
}
putchar( '\n' );
return 0;
}
The program output is
Tom, 18, 3500.000000
Bob, 26, 4500.000000
Jim, 28, 4000.000000
Bob, 26, 4500.000000
Jim, 28, 4000.000000
Tom, 18, 3500.000000
Tom, 18, 3500.000000
Bob, 26, 4500.000000
Jim, 28, 4000.000000
Tom, 18, 3500.000000
Jim, 28, 4000.000000
Bob, 26, 4500.000000
This function should accomplish what you seek:
int compare_employees(const void * e1, const void * e2) {
const employee * emp1 = (employee*)e1;
const employee * emp2 = (employee*)e2;
int ret1 = strcmp(emp1->name, emp2->name);
if (ret1 == 0) {
if (emp1->age == emp2->age) {
float ret2 = emp1->wage - emp2->wage;
if (ret2 == 0)
return 0;
else if (ret2 > 0)
return 1;
else
return -1;
} else {
return emp1->age - emp2->age;
}
} else {
return ret1;
}
}
It first takes alphabetical order into account, then age, and finally wage.
Of course, I assumed you wanted to sort the elements in ascending order. If you want to sort them in descending order, all you'd have to do is flip the values for each comparison:
float ret2 = emp2->wage - emp1->wage; to sort employees by wage in descending order, for example.
Moreover, if you want a different priority for your sorting function (i.e. wage is more decisive than the names' alphabetical order, but the latter is still more decisive than age), arrange them differently within the if statements:
if (ret1 == 0) {
int ret2 = strcmp(emp1->name, emp2->name);
if (ret2 == 0)
return emp1->age - emp2->age;
else
return ret2;
} else if (ret1 > 0) {
return 1;
} else {
return -1;
}
A comparison function appropriate for sorting objects of type employee will receive arguments that point to employee objects. That each object has members of several types affects how you would implement such a function, but that does not in itself present any reason why you would need more than one function.
int compare_employees(const void *e1, const void *e2) {
const employee *employee1 = e1;
const employee *employee2 = e2;
// ... code to compare *employee1 with *employee2 ...
}
However, each comparison function defines a particular way of sorting the objects. If you want to provide for sorting on different criteria then you need a different comparison function for each method of ordering. This has nothing in particular to do with whether the members all have the same data type.

Update a struct in Arduino

I have one structure like below in Arduino, I want to update it
struct record
{
int bookId;
int qtyInStock;
};
typedef struct record Record;
Record aRec;
aRec.bookId = 100;
aRec.qtyInStock = 12;
aRec.bookId = 101;
aRec.qtyInStock = 10;
aRec.bookId = 102;
aRec.qtyInStock = 100;
If bookId 101 is sold then how can I update qtyInStock? So, qtyInStock for bookId 101 should be 9 now.
Thanks
You can use an array of type record to store multiple books. Sold being your inbuilt function, you can try this:
struct record
{
int bookId;
int qtyInStock;
};
typedef struct record Record;
void sold(int id, Record* records) {
int i;
for(i=0;i<3;i++) {
if(records[i].bookId == id) {
records[i].qtyInStock--;
}
}
}
void updateId(int id, int new_id, Record* records) {
int i;
for(i=0;i<3;i++) {
if(records[i].bookId == id) {
records[i].bookid = new_id;
}
}
}
void updateQty(int id, int new_qty, Record* records) {
int i;
for(i=0;i<3;i++) {
if(records[i].bookId == id) {
records[i].qtyInStock = new_qty;
}
}
}
void main() {
Record records[3];
records[0].bookId = 100;
records[0].qtyInStock = 12;
records[1].bookId = 101;
records[1].qtyInStock = 10;
records[2].bookId = 102;
records[2].qtyInStock = 100;
int i;
sold(101, records);
updateId(100, 99, records);
updateQty(102, 15, records);
for(i=0;i<3;i++) {
printf("%d\n", records[i].bookId);
printf("%d\n\n", records[i].qtyInStock);
}
}
I would keep all records in a linked list, and iterate over them, find the book id, decrease it's available count.
You know that you are editing a single record (aRec) in your example code right? You will need some sort of container for that:
struct node {
Record* value;
Node* next;
}
sruct recordList {
Node* head;
}
/* ... */

Othello Minimax Algorithm not working

I am trying to make a minimax algorithm, but my function does not return the correct position. It returns the deepest node. I would like it to return the best possible move. Here is my code:
pos minimax(game* g, strategy_config sc)
{
int points = 0;
sc.minimax_config.heuristic(g, sc.minimax_config.hc);
pos p, p2;
int search_depth = sc.minimax_config.ply;
for (p.r = 0; p.r < g->b->nrows; p.r++)
{
for (p.c = 0; p.c < g->b->ncols; p.c++)
{
game* copy = g;
apply_move(copy, p);
if (sc.minimax_config.heuristic(copy, sc.minimax_config.hc)
> points && sc.minimax_config.ply > 0)
{
if (sc.minimax_config.ply == search_depth)
{
p2 = p;
}
sc.minimax_config.ply = sc.minimax_config.ply - 1;
minimax(copy, sc);
}
}
}
return p2;
}
And here are the relevant structs:
struct edge_corner_weight {
unsigned int edge_weight;
unsigned int corner_weight;
};
union heuristic_config {
unsigned int edge_weight;
struct edge_corner_weight edge_corner_weight;
};
typedef union heuristic_config heuristic_config;
struct minimax_config {
int (*heuristic)(game*, heuristic_config);
heuristic_config hc;
unsigned int ply;
};
typedef struct minimax_config minimax_config;
union strategy_config {
minimax_config minimax_config;
};

Why are my qsort results incorrect?

When I run add cards using add_card, on the 7th card it is supposed to sort all of the cards. But when I run this I get a semi-ordered result.
>> require 'ext/straight_count' #=> true >> s = EV::StraightCount.new; s.add_card(5,0); s.add_card(8,1); s.add_card(12,2); s.add_card(14,3); s.add_card(12,4); s.add_card(3,5); s.add_card(5,6)
card: 12
card: 5
card: 12
card: 14
card: 8
card: 5
card: 3
I don't think there is a problem with NUM2INT, because when I print the array back unordered, it comes out as expected.
straight.h
int *pCards, *pSortedCards;
int cCards[NUM_CARDS], cSortedCards[NUM_CARDS];
straight.c
void Init_straight()
{
pCards = &cCards[0];
}
static VALUE
add_card(VALUE self, int rCardValue, int rCardIndex)
{
*(pCards + NUM2INT(rCardIndex)) = NUM2INT(rCardValue);
if (NUM2INT(rCardIndex) == 6)
check_for_straight();
return Qnil;
}
check_for_straight()
{
sort_by_value(pCards);
}
card_sort.c
int compare_card_values (const void *a, const void *b)
{
const double *da = (const double *) a;
const double *db = (const double *) b;
return (*da > *db) - (*da < *db);
}
void sort_by_value(int *pCards)
{
qsort(pCards, NUM_CARDS, sizeof(pCards[0]), compare_card_values);
}
You're casting the card values to double in compare_card_values even though the array contains int. Try this instead:
int compare_card_values (const void *a, const void *b)
{
const int *da = (const int *) a;
const int *db = (const int *) b;
return (*da > *db) - (*da < *db);
}

Resources