I try to sort an array of double value using qsort, but it doesn't seems to work. Wonder what has gone wrong here??
#include <stdio.h>
#include <stdlib.h>
static double compare (const void * a, const void * b)
{
if (*(double*)a > *(double*)b) return 1;
else if (*(double*)a < *(double*)b) return -1;
else return 0;
}
int main() {
int idx;
double* sum_least_square_err;
sum_least_square_err = (double*) malloc (2500*2500*sizeof(double));
sum_least_square_err[0] = 0.642;
sum_least_square_err[1] = 0.236;
sum_least_square_err[2] = 0.946;
idx = 3;
qsort(sum_least_square_err, idx, sizeof(sum_least_square_err), compare);
int i;
for (i=0; i<idx; i++){
fprintf(stderr,"sum_least_square_err[%d] = %.3f\n", i, sum_least_square_err[i]);
}
fprintf(stderr,"MAEE = %.3f\n", sum_least_square_err[idx/2]);
free(sum_least_square_err);
}
Result:
sum_least_square_err[0] = 0.642
sum_least_square_err[1] = 0.236
sum_least_square_err[2] = 0.946
MAEE = 0.236
Change:
static double compare (const void * a, const void * b)
to:
static int compare (const void * a, const void * b)
and change:
qsort(sum_least_square_err, idx, sizeof(sum_least_square_err), compare);
to:
qsort(sum_least_square_err, idx, sizeof(sum_least_square_err[0]), compare);
Note: you should have got an appropriate compiler warning about the first bug - are you compiling with gcc -Wall or equivalent, and if so are you taking notice of compiler warnings ? (If not then please take the hint and let the compiler catch problems such as this for you in future.)
I believe your error is at the line:
qsort(sum_least_square_err, idx, sizeof(sum_least_square_err), compare);
The problem is the 3rd parameter should be sizeof(double), that is, the size of an element of the array. You were instead passing the size of a pointer, which can be (and usually is) different from the size of the element.
For more information, see: http://www.cplusplus.com/reference/clibrary/cstdlib/qsort/
Edit: And Paul R is right in his answer: The prototype of your comparison function is wrong. The prototype should be:
int ( * comparator ) ( const void *, const void * )
Last but not least, in your code:
if (*(double*)a > *(double*)b) return 1;
else if (*(double*)a < *(double*)b) return -1;
You are casting away the const. This has not consequence here, but still, this is bad form.
Related
What is bool (*comparator)(void *, void *)?
I'm trying to use this function from a library, but I don't understand its signature.
The function seems to be expecting some kind of criteria to sort the list (as ASC or DESC in SQL, I think), as a higher order function.
void list_sort(t_list *self, bool (*comparator)(void *, void *)) {
int unsorted_elements = self->elements_count;
if(unsorted_elements < 2) {
return;
}
t_link_element *aux = NULL;
bool sorted = true;
do {
t_link_element *previous_element = self->head, *cursor = previous_element->next;
sorted = true;
int index = 0, last_changed = unsorted_elements;
while(index < unsorted_elements && cursor != NULL) {
if(!comparator(previous_element->data, cursor->data)) {
aux = cursor->data;
cursor->data = previous_element->data;
previous_element->data = aux;
last_changed = index;
sorted = false;
}
previous_element = cursor;
cursor = cursor->next;
index++;
}
unsorted_elements = last_changed;
} while(!sorted);
}
The last definition of the function was in commons/collections/list.h.
I can't figure how to use this function properly after many attempts.
#include <stdio.h>
#include <stdlib.h>
#include <commons/collections/list.h>
/*I added this function thanks to the help of the community,
*and now it works, the list is printed backwards now.*/
bool comparator(void * a, void * b) {
return (int*) a > (int*) b;
}
int main()
{
t_list *list = list_create();
int add[] = {4, 55, 9, 7, 17};
list_add(list, (void*) &add[0]);
list_add(list, (void*) &add[1]);
list_add(list, (void*) &add[2]);
list_add(list, (void*) &add[3]);
list_add(list, (void*) &add[4]);
int size = list_size(list);
int j = 0 ;
while( j++ < 2)
{
for ( int i = 0 ; i < size; i++)
{
int* element = (int*) list_get(list, i);
printf("Found %d\n", *element);
}
//I edited this line, now the second parameter is comparator
list_sort(list, comparator);
}
list_destroy(list);
}
The main() function prints
Found 4 Found 55 Found 9 Found 7 Found 17
Found 17 Found 7 Found 9 Found 55 Found 4
EDIT:
I created the function comparator that actually allows me to run the code
After printing the result I showed before, it prints the same list but backwards.
Thanks everyone who's been nice and helped me fixed this, I still don't know how to print the sorted list. Sorry if my question is useless and/or violates some guideline, I wouldn't ask it this way if I knew it did.
Looking at the code in your last edit, the function is plain wrong. (int*) a > (int*) b compares pointer addresses, not values. If you intend to return true if a is greater than b, then it should be:
bool is_greater (void * a, void * b) {
return *(int*) a > *(int*) b;
}
More readably written as:
bool is_greater (void* a, void* b)
{
const int* ia = a;
const int* ib = b;
return *ia > *ib;
}
The function pointer type used by that API has some code smell, the parameters should have been declared as const void* so that the code can be used on read-only data too, but I guess you can't change that part.
In C++ we would have a predicate - an operator which returns true if the lhs < rhs
So your C function looks like it is following that pattern.
bool myLessInt(void * lhs, void * rhs)
{
// assume input parameters lhs and rhs are pointers into the data.
int intLhs = *((int*)lhs);
int intRhs = *((int*)rhs);
if( intLhs < intRhs ) return true; // lhs was less than rhs
return false; // rhs == or is less than lhs
}
I would look for a function like the one above to solve your problem.
#include <stdio.h>
#include <stdlib.h>
#define LEN 5
#define sum_mac(func,type)\
void* func (void* arr, int size)\
{\
int i;\
type *sum = (type*)malloc(sizeof(type));\
if(sum == NULL)\
{\
printf("Error\n");\
exit(1);\
}\
*sum = 0;\
for(i = 0; i<size ; i++)\
{\
*sum = *sum + *((type*)arr[i]);\
}\
return sum;\
}\
sum_mac(int_sum,int);
void *summary(void* arr, int size, void *(*func)(void*, int))
{
if (func == NULL)
return NULL;
return (*func)(arr, size);
}
int main()
{
int arr[] = { 1,2,3,4,5 };
int *sum = summary(arr, LEN, int_sum(arr, LEN));
printf("the sum is: %d ", *sum);
free(sum);
return 0;
}
I get the following error when I try to compile this code:
Error LNK2019 unresolved external symbol _int_sum referenced in function _main
When I searched possible causes for this problem I got that "a reference to a function or variable that the linker can't resolve, or find a definition for".
Can someone help me find the problem.
There is (at least) three problems:
You included the macro instanciation in the macro itself, change:
}\
sum_mac(int_sum,int);
to:
}
sum_mac(int_sum,int);
Thus sum_mac is not part of the macro.
In the macro definition, change:
*sum = *sum + *((type*)arr[i]);
to:
*sum = *sum + ((type*)arr)[i];
In the first case, you try to use indexing on void pointer type, which is not possible (void has no size). So convert arr to pointer of the right type and use arithmetic on it.
--------------EDIT-----------
Change:
int *sum = summary(arr, LEN, int_sum(arr, LEN));
to
int *sum = summary(arr, LEN, int_sum);
In the first case you call summary with the third parameter value being the result of a call to int_sum, and that result if not a function pointer but the pointer to some int. You need to pass the function pointer.
Most of your problems are due to macro usage. This bypass the type system and fool the compiler, which is never a good idea.
Problem is here:
return sum;\
}\ <---------- Remove the \
sum_mac(int_sum,int); <---- also remove the ; because this is not a statement
void *summary(void* arr, int size, void *(*func)(void*, int))
Compiler thinks that sum_mac(int_sum,int); is part of the macro definition because \ at the end of line concatenates lines. That is why sum_mac(int_sum,int); is never called.
However, this reveals another problem with operator precendence on line:
*sum = *sum + *((type*)arr[i]);\
Array access [i] has higher precedence than cast (type*), so you are trying to access void array which won't work. Also the last dereference is pointless. Line should be changed to:
*sum = *sum + ((type*)arr)[i];\
There is also third problem: You are passing calling int_sum too early. Function expects function pointer so you should only pass the pointer:
int *sum = summary(arr, LEN, int_sum); // Only pass int_sum
You should make sure that you have enabled all warnings on the compiler, since this is an error that compiler could warn you about.
The other problem is here:
int *sum = summary(arr, LEN, int_sum(arr, LEN));
The third argument of summary should be a function pointer, but int_sum(arr, LEN) is not a function pointer but it is the result of the int_sum function.
You need to write this:
int *sum = summary(arr, LEN, int_sum);
You don't declare the function you call anywhere, so the linker doesn't know what to do.
That being said, putting whole functions inside macros is not a good idea, nor to malloc single items. And the code *sum = *sum + *((type*)arr[i]); goes wildly out of bounds, because you didn't allocate an array, but use it as if it was one.
I would rewrite this from scratch. This is what you can do instead:
#include <stdio.h>
#include <stdlib.h>
int int_sum (size_t size, int arr[size])
{
int sum = 0;
for(size_t i=0; i<size; i++)
{
sum += arr[i];
}
return sum;
}
float float_sum (size_t size, float arr[size])
{
float sum = 0.0f;
for(size_t i=0; i<size; i++)
{
sum += arr[i];
}
return sum;
}
#define sum_array(arr) _Generic((arr[0]), \
int: int_sum, \
float: float_sum) (sizeof(arr)/sizeof(arr[0]), arr)
int main (void)
{
int arr[] = { 1,2,3,4,5 };
int sum = sum_array(arr);
printf("int, the sum is: %d\n", sum);
float farr[] = {1.0f, 2.0f, 3.0f};
printf("float, the sum is: %f\n", sum_array(farr));
return 0;
}
Which can be made even more generic, even without involving function pointers:
#define do_stuff(arr, stuff) _Generic((arr[0]), \
int: int_##sum, \
float: float_##sum) (sizeof(arr)/sizeof(arr[0]), arr)
int main (void)
{
int arr[] = { 1,2,3,4,5 };
int sum = do_stuff(arr, sum);
printf("int, the sum is: %d\n", sum);
float farr[] = {1.0f, 2.0f, 3.0f};
printf("float, the sum is: %f\n", do_stuff(farr, sum));
return 0;
}
The Second Param of qsort
Now I want to sort a set of points by x.Following is my code:
typedef struct {
int x;
int y;
} point;
int cmpfunc( const void * a, const void * b){
point *point1 = (point *)(a);
point *point2 = (point *)(b);
if(point1->x < point2->x){
return -1;
}
return 0;
}
int main(){
point *points = (point *)malloc(sizeof(point)*3);
points[0].x = 1;
points[0].y = 2;
points[1].x = 0;
points[1].y = 4;
points[2].x = 4;
points[2].y = 3;
qsort(points,2,(sizeof(points[0])),cmpfunc);
int i=0;
while (i<3){
printf("x=%d",points[i].x);
printf("y=%d\n",points[i].y);
i++;
}
return 0;
}
Please notice qsort(points,2,(sizeof(points[0])),cmpfunc);
The result is correct when I pass the second param value 2 not 3.What's wrong with my code?
To sort on the x axis, you need something like:
static void cmpfunc(const void *a, const void *b)
{
const point *pa = a, *pb = b;
return pa->x < pb->x ? -1 : pa->x > pb->x;
}
It must return less than, equal to, or greater than zero. See the manual page for more.
Oh, and you really shouldn't "drop const" like that, for no reason, and of course you never need to cast from void * to a pointer to struct like we have here. Keep it simple, and learn these things so you don't feel a need to "throw in a cast for good measure".
Consider this code for qsort:
#include <stdio.h>
#include <stdlib.h>
int values[] = { 88, 56, 100, 2, 25 };
int cmpfunc(const void * a, const void * b)
{
return *(int*)a - *(int*)b;
}
int main()
{
int n;
printf("Before sorting the list is: \n");
for (n = 0; n < 5; n++)
{
printf("%d ", values[n]);
}
qsort(values, 5, sizeof(int), cmpfunc);
printf("\nAfter sorting the list is: \n");
for (n = 0; n < 5; n++)
{
printf("%d ", values[n]);
}
return(0);
}
what does *(int*)a means specifically? It looks like a pointer to a pointer? why cant i do:
**a // dereferrencing twice would get the value, no?
or
*(int *a) // looks about the same. Also why do i need the int?
apologies if this question seemed obvious as I've been looking at this for hours now, and i still cant grasp why that '*' is wrapping around the bracket.
void* and const void* are used in C to stand in for a generic pointer of unknown type. qsort doesn't really know what it's sorting: the callback comparison function cmpfunc does that task. But C is statically-typed, so the callback function needs to have a specific prototype. That's where const void* is useful.
Of course, within your supplied cmpfunc, you know the type of object being sorted, so you are able to cast the const void* to your type. That is what (int*) is doing: it's a cast.
Technically you should cast to const int* instead:
return *(const int*)a - *(const int*)b;
Casting away const can cause you trouble.
A pointer to void can't be dereferenced. Therefore, in the given case it must have to cast to int * before dereferencing.
In *(int*)a, (int*) is casting a to pointer to int and then * outside the parenthesis dereferencing the value at that address.
I'm trying to use qsort to sort a 2D array in C. The sort works, but I get the warning:
warning: initialization discards 'const' qualifier from pointer target type [enabled by default]
How can I modify my compare function to eliminate the warning (given that qsort requires the parameters const void *pa, const void *pb ?
int cmp (const void *pa, const void *pb ) {
const int (*a)[2] = pa; // warning here
const int (*b)[2] = pb; // warning here
if ( (*a)[1] < (*b)[1] ) return 1;
if ( (*a)[1] > (*b)[1] ) return -1;
return 0;
}
I've read this post on Stack Overflow, but I'm still not sure how I should alter the compare function.
I have an array that looks like this:
int letterCount[26][2] = {{0, 0},{1, 0},{2, 0},{3, 0},{4, 0},{5, 0},{6, 0},{7, 0},{8, 0},{9, 0},{10, 0},{11, 0},{12, 0},{13, 0},{14, 0},{15, 0},{16, 0},{17, 0},{18, 0},{19, 0},{20, 0},{21, 0},{22, 0},{23, 0},{24, 0},{25, 0}};
Except in the second column, instead of zeroes, those are filled with other numbers. I'm trying to sort this 2d array by the second column, after 0s are filled in.
You could toy with the decls, but in the end I think this will suffice for the comparator you're using:
int cmp (const void *pa, const void *pb )
{
const int *a = pa;
const int *b = pb;
if (a[1] < b[1])
return -1;
return (b[1] < a[1]);
}
Your data "items" are nothing more than int[] offsets in a 2D array. Were this a pointer array rather than a genuine 2D array, this would be considerably different. Grijesh was very close to this, only missing the [1] offsets (and the simple math), and if he undeletes his answers to fix it I'll just drop this.
what is this supposed to do (*a)[2] ?
it appears that you're dereferencing a pointer to an array in a declaration.
here for a lack of better things to do I wrote my own version , I hope it'll help you :
#include <time.h>
#include <stdio.h>
void Qsort(int matrix[][2] , int lenght)
{
if(!lenght)
return;
int temp = 0 , pivot , b = 0 , e = lenght - 1 , test = 0;
const int MIN =0 , MAX = e;
srand(time(NULL));
test = (rand() % (MAX - MIN + 1)) + MIN;
pivot = matrix[test][1];
while(b < e)
{
while(matrix[b][1] < pivot)
b++;
while(matrix[e][1] > pivot)
e--;
temp = matrix[b][1];
matrix[b][1] = matrix[e][1];
matrix[e][1] = temp;
}
Qsort(matrix , b);
Qsort(&(matrix)[b + 1] , lenght - 1 - b);
}