i have a problem in my code when i try to use compelx structure in a generic sorting library on C lang: (you can find the complete code https://github.com/Tramontz/ASD_2023)
i have a binary-merge insertion sort, thatt take in imput a void pointer (first element of an array), and ,can work with array of int and string (all unity test pass).
Now i'm tryng to use it with an array of:
struct record{
int id;
char* string_field_1;
int integer_field_2;
double float_field_3;
};
stored in another struct
struct _StructArray{
void**array;
unsigned long el_num;
unsigned long array_capacity;
};
with subroutine
void struct_array_add(StructArray *struct_array, void* element){
if(struct_array->el_num >= struct_array->array_capacity){
printf("array too short, must be reallocate \n");
struct_array->array = (void**)realloc(struct_array->array,2*(struct_array->array_capacity)*sizeof(void*));
struct_array->array_capacity = 2*struct_array->array_capacity;
}
struct_array->array[struct_array->el_num] = element;
struct_array->el_num++;
}
void* struct_array_get(StructArray *struct_array, unsigned long index){
return &(struct_array->array)[index];
}
i must order the void**array of record.
this is an example of the data took from a csv file
<POSIZION:0, ID:0, String:noto, Integer:233460, Float:32209.073312 >
<POSIZION:1, ID:1, String:piangea, Integer:4741192, Float:81176.622633 >
<POSIZION:2, ID:2, String:spenti!, Integer:1014671, Float:4476.013614 >
<POSIZION:3, ID:3, String:misericordia, Integer:496325, Float:61628.929334 >
the ordering mode is choosed by
switch (field) {
case 1://struct_array_get(array,0) return the first element of the array
merge_binary_insertion_sort(struct_array_get(array,0), struct_array_size(array), sizeof(struct record), k, precedes_record_string_field);
so basically i store with a loop all my data in the record *array inside structArray.
the array is correctly loaded, because the print function
for(unsigned long i=0;i<el_num;i++){
array_element = (struct record *)struct_array_get(array, i);
printf("<POSIZION:%d, ID:%d, String:%s, Integer:%d, Float:%lf >\n",i,array_element->id,array_element->string_field_1,array_element->integer_field_2,array_element->float_field_3);
}
can show all the record in the array.
so the problem appear when the sorting function is called:
void bin_insertion_sort(void *arr, int n, size_t elementSize, CompareFunction compare) {
int i, loc, j;
void *selected = malloc(elementSize);
if (selected == NULL) {
fprintf(stderr, "Errore nell'allocazione di memoria per 'selected'\n");
exit(EXIT_FAILURE);
}
for (i = 1; i < n; ++i) {
j = i - 1;
memcpy(selected, arr + i * elementSize, elementSize);
// Find location where selected should be inserted
loc = binary_search(arr, selected, 0, j, compare, elementSize);
i store in the void *selected the item that i want to find location in the array, and call the binary search
int binary_search(void *arr, void *item, int low, int high, CompareFunction compare, size_t elementSize) {
if (high <= low){
return (compare(item, arr + low * elementSize) > 0) ? (low + 1) : low ;
We can focus only in the binary_search, here is the problem: when i call return (compare(item, arr + low * elementSize) > 0) ? (low + 1) : low ; for the records's array, with this compare function
static int precedes_record_string_field(const void* r1_p, const void* r2_p) {
if (r1_p == NULL || r2_p == NULL) {
fprintf(stderr, "precedes_record_string_field: one of the parameters is a null pointer\n");
exit(EXIT_FAILURE);
}
const struct record* rec1_p = (const struct record*)r1_p;
const struct record* rec2_p = (const struct record*)r2_p;
printf("Record 1: ID=%d, String=%s, Integer=%d, Float=%f\n", rec1_p->id, rec1_p->string_field_1, rec1_p->integer_field_2, rec1_p->float_field_3);
sleep(1);
printf("Record 2: ID=%d, String=%s, Integer=%d, Float=%f\n", rec2_p->id, rec2_p->string_field_1, rec2_p->integer_field_2, rec2_p->float_field_3);
sleep(5);
return strcmp(rec1_p->string_field_1, rec2_p->string_field_1);
}
it print the rec2 data, but not the rec1 data, so i suppose that it can cast the arr + low * elementSize pointer, but not the void item* pointer that I pass through the compare(item, arr + low * elementSize) and store in rec1(item) and rec2(arr + low * elementSize).
I'm doing something wrong in the memory adress management? maybe i'm adressing all the structArray with item, and not the second element of the record* array?
i'm stucked because all my unity test with single, null, and multiple string and integer arrays work correctly.
Thank you all.
It seems very very very complex the way you wrote.
keep things separated
Here we have your data record, the 4 required functions and a function to show the results
Use encapsulation and write code around your data.
See this :
This is data to test all your functions.
###'
mainfor a test ###Here:
the output
And it seems to be ok.
It is easier this way: first test all functions.
Since you said the code already works for integers, just make sure the sorting code really abstracted the data record. In general is just a case of writing correct swapping functions. And paying special attention to the navigating process...
complete
CcodePart II
This is
main.cfor the second example:test_with_struct_array()is the original program. The 2nd function sorts the same array in avoid**array, in order to test the mechanics in isolation, and the 3rd function uses the author's originalStructArray--- with a minor modification, see code below.usind a
void**This is the code to build the array using the original data:
The compare funcions are all different, since there is a new level of indirection to accesss the actual data. The new functions are
cmp_[5678]fromcmp_[1234]and here is a pair, that compares thei_fieldfromTarget:The difference is just in getting the data address. Since
StructArrayis also avoid**thing, these functions are used there too.Sister functions were added to display the data from the different sources, so the output is exactly the same, as expected.
The first function displays a single data record, so can be used by all 3 formats. It is passed as a parameter so it is easy to use an alternate display for each test if needed.
The change in
StructArrayThis function was added in order to get the base address from inside
StructArrayOn using
StructArrayas a containerThis is how the container was abstracted for sorting, at the start of the test function. This should work for any sorting algorithm on the contiguous array of
void*.Hope it helps
code for the second example
output for the 3rd test
Not interesting since it is the same data 3 times, but generated by differen containers built from the same original data.