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".
Related
I have a lot of records formed by 4 parameters each one (id, field1, field2, field3). Records are contained in a pointer called records. My goal is to create an InsertionSort function in order to sort these records. The sorting will be done for every parameter of the record (through multiple calling). The trouble is that the function must be general.
What can I write in parameters of InsertionSort function so that the pointer works?
main.c
struct fields{
int id;
char field1[20];
int field2;
float field3;
};
int main() {
struct fields *records = malloc(100000 * sizeof *records);
/* Here , I fill *records with values */
InsertionSort(records,field1,100000); // I order by parameter "field1"
InsertionSort(records,id,100000); // I order by parameter "id"
InsertionSort(records,field2,100000); // I order by parameter "field2"
}
InsertionSort function
void InsertionSort(fields *records, char parameter ,int sizeofrecords) {
int i, j;
void* temp;
for (i = 1; i < size; i++) {
temp = records[i].parameter; //this command doesn't work (records[i])
j = i - 1;
while (j >= 0 && records[j].parameter> temp) {
records[j + 1].parameter= records[j].parameter;
j--;
}
records[j + 1].parameter= temp;
}
}
Look at the design of standard C (and POSIX) qsort(). Pass a pointer to a comparator function to your InsertionSort() function in place of the char parameter argument. When you need to compare in the sort function, invoke the comparator on the two records to be compared. Write different comparators to sort on the different fields. A standard (qsort-compatible) comparator has the signature int comparator(const void *p1, const void *p2). You might be able to use const fields * as the argument type, but then you'd not be able to use the standard qsort() function.
Without debugging any other issues in your sort (I'm not sure whether there are any), you might end up with:
void InsertionSort(fields *records, int (*cmp)(const void *p1, const void *p2), int size)
{
for (int i = 1; i < size; i++)
{
void *temp = &records[i];
int j = i - 1;
while (j >= 0 && (*cmp)(&records[j].parameter, temp) > 0)
{
records[j + 1].parameter = records[j].parameter;
j--;
}
records[j + 1].parameter = temp;
}
}
You can write just cmp(records[j].parameter, temp). I learned C long enough ago to prefer the older, more explicit notation for invoking a function via a function pointer. (I learned C in an era when the simpler notation was not an option.)
Your comparator functions might look like these (the other two are trivial variants on cmp_id):
static int cmp_id(const void *p1, const void *p2)
{
const fields *v1 = p1;
const fields *v2 = p2;
// +1 if v1 > v2; -1 if v1 < v2; else 0
return (v1->id > v2->id) - (v1->id < v2->id);
}
static int cmp_field1(const void *p1, const void *p2)
{
const fields *v1 = p1;
const fields *v2 = p2;
return strcmp(v1->field1, v2->field1);
}
The numeric comparator (cmp_id) avoids overflow and branching. You could write:
if (v1->id > v2->id)
return +1;
if (v1->id < v2->id)
return -1;
return 0;
as the body of the function. It is simpler to understand. It can also be extended to deal with tie-breakers, so that if the id values are the same, you can compare the field1 strings or the values in field2 or field3. You simply add extra comparisons after the if statements and before the return 0;.
Warning: this code has not been anywhere near a compiler, much less tested. Caveat Lector.
So Peppino wants to know how to actually do it. Well, kinda. The problem is while we can pass the member, we can't pass the member's type so this will run incorrectly. If we had all the members being the same type instead this would work:
#include <stddef.h>
struct fields{
int id;
char field1[20];
char field2[11];
char field3[20];
};
void InsertionSort(fields *records, size_t parameter ,int size) {
int i, j;
struct fields temp;
for (i = 1; i < size; i++) {
temp = records[i];
j = i - 1;
while (j >= 0 && strnatsort((char *)records[i] + parameter, (char *)records[i] + parameter) > 0) {
records[j + 1] = records[j];
j--;
}
records[j + 1] = temp;
}
}
InsertionSort(records,offsetof(fields, field1),100000);
where strnatsort does natural sort: How to implement a natural sort algorithm in c++?
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.
I have to create a program that solves the following gate circuit. However, something goes wrong during program execution, because I am prompted to input eight times instead of six. Please, only provide solutions that involve changes in the main function, and not others.
Here is a diagram of the circuit problem I have to solve:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef int (*CallBack)(int, int);
typedef struct gate {
CallBack f;
struct gate * in1 ;
struct gate * in2 ;
} Gate;
int getinput() {
int x;
scanf("%d", &x);
return x;
}
int myand (int a, int b) {
return a * b;
}
int myor (int a, int b) {
return a + b>0;
}
int mynand (int a, int b) {
return !(a * b);
}
int mynor (int a, int b) {
return a + b<=0;
}
int myxor (int a, int b) {
return a!=b;
}
Gate * creategate(CallBack f) {
Gate * temp ;
temp = malloc(sizeof (Gate));
temp->f = f;
temp->in1 = NULL;
temp->in2 = NULL;
return temp;
}
int eval(Gate *x) {
int a, b;
if (x->in1 != NULL)
a = eval(x->in1);
if (x->in2 != NULL)
b = eval(x->in2);
if (x->in1==NULL && x->in2 == NULL)
return (x->f)(0,0);
else
return (x->f)(a,b);
}
int main( ) {
Gate * gate1_ptr, * gate2_ptr, * gate3_ptr, * gate4_ptr, * gate5_ptr, * gate6_ptr;
Gate * a_ptr, * b_ptr, * c_ptr, * d_ptr, * e_ptr, * f_ptr;
gate1_ptr = creategate(mynor);
gate2_ptr = creategate(myand);
gate3_ptr = creategate(myor);
gate4_ptr = creategate(mynand);
gate5_ptr = creategate(myxor);
gate6_ptr = creategate(myor);
printf("Enter six inputs, split by enter:\n");
a_ptr = creategate(getinput);
b_ptr = creategate(getinput);
c_ptr = creategate(getinput);
d_ptr = creategate(getinput);
e_ptr = creategate(getinput);
f_ptr = creategate(getinput);
gate1_ptr->in1 = a_ptr;
gate1_ptr->in2 = b_ptr;
gate2_ptr->in1 = c_ptr;
gate2_ptr->in2 = d_ptr;
gate3_ptr->in1 = e_ptr;
gate3_ptr->in2 = f_ptr;
gate4_ptr->in1 = gate1_ptr;
gate4_ptr->in2 = gate2_ptr;
gate5_ptr->in1 = gate2_ptr;
gate5_ptr->in2 = gate3_ptr;
gate6_ptr->in1 = gate4_ptr;
gate6_ptr->in2 = gate5_ptr;
printf("%d", eval(gate6_ptr));
return 0;
}
Every time you try to evaluate one of your "input" terms, you ask for input from the user. Since gate2_ptr is referenced by two gates, its value is evaluated twice, and each of its inputs is evaluated twice. This results in the two extra input prompts when ou run the program.
You should ask for the input values when the inputs are created, not when they are evaluated.
Unrelated, but some compilers will issue a warning for creategate(getinput) because creategate expects a pointer to a function that takes two int parameters, while getinput expects none. In this instance, this is harmless because the extra parameters will be ignored by getinput and removed by the caller, but it does represent a potentially flawed design. (If getinput would expect more parameters - like 3 ints - you'd get a different set of warnings and introduce more serious problems.)
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.
I have the following code:
int takeEven(int *nums, int numelements, int *newlist) {
newlist = malloc(numelements * sizeof *newlist);
int i, found = 0;
for(i = 0; i < numelements; ++i, nums++) {
if (!(*nums % 2)) {
*(newlist++) = *nums;
found++;
}
}
newlist -= found;
printf("First number found %d\n", *newlist); // <= works correctly
return found;
}
int main()
{
int nums[] = {1,2,3,4,5};
int *evenNums;
int i;
int n = takeEven(nums, sizeof(nums) / sizeof(*nums), evenNums);
for (i = 0; i < n; ++i) {
printf("%d\n", *(evenNums++));
}
return 0;
}
The output of the above code:
-1
2088999640
2088857728
If I try printing the first element of the newlist pointer before returning the function (printf("First number found %d\n", *newlist);), it works as intended, but why is it that when I try to access the pointer from outside of the function I get those values from seemingly unmalloced addresses?
You are passing the newList pointer by value, so it will not be modified by your function. You should do instead.
int takeEven(int *nums, int numelements, int **newlist) {
*newlist = malloc(numelements * sizeof *newlist);
...
}
...
int n = takeEven(nums, sizeof(nums) / sizeof(*nums), &evenNums);
You need to pass in a pointer to pointer, i.e. int **newlist. Specifically, newlist is being passed into your function by value, so the newlist in main and inside your function are two completely different variables.
There is also a bug in your test for even numbers:
#include <stdio.h>
#include <stdlib.h>
int takeEven(int *nums, int numelements, int **newlist) {
int *list = malloc(numelements * sizeof **newlist);
*newlist = list; // this modifies the value of newlist in main
int i, found = 0;
for(i = 0; i < numelements; ++i, nums++) {
if ((*nums % 2) == 0) {
*(list++) = *nums;
found++;
}
}
list -= found;
printf("First number found %d\n", *list); // <= works correctly
return found;
}
int main()
{
int nums[] = {1,2,3,4,5};
int *evenNums;
int i;
int n = takeEven(nums, sizeof(nums) / sizeof(*nums), &evenNums);
for (i = 0; i < n; ++i) {
printf("%d\n", *(evenNums++));
}
return 0;
}
You can also take a look at this question from the C-FAQ which deals with your problem also:
Q: I have a function which accepts, and is supposed to initialize, a pointer:
void f(int *ip)
{
static int dummy = 5;
ip = &dummy;
}
But when I call it like this:
int *ip;
f(ip);
the pointer in the caller remains unchanged.
A: Are you sure the function initialized what you thought it did? Remember that arguments in C are passed by value. In the code above, the called function alters only the passed copy of the pointer. To make it work as you expect, one fix is to pass the address of the pointer (the function ends up accepting a pointer-to-a-pointer; in this case, we're essentially simulating pass by reference):
void f(ipp)
int **ipp;
{
static int dummy = 5;
*ipp = &dummy;
}
...
int *ip;
f(&ip);
Another solution is to have the function return the pointer:
int *f()
{
static int dummy = 5;
return &dummy;
}
...
int *ip = f();
See also questions 4.9 and 4.11.
The newlist you have at the end of the function is not the same as you have when calling the function.
You are passing a copy of a pointer, then malloc changes that pointer(internal to the function) to point to allocated memory, but the outside one is still unmodified.
You need to use a pointer to pointer as a parameter so that you can set where the ourtside one points by double indirection.
int use_pointed_memory(char **pointer){
*pointer = malloc();
}
char *myptr;
use_pointed_memory(&myptr);
So effectively you are giving the function the place where you store the address of what you want and asking the function to store there a valid memory pointer.
You're passing a pointer by value here:
int n = takeEven(nums, sizeof(nums) / sizeof(*nums), evenNums);
Which means that a copy of the pointer is made within that function. You then overwrite that copy:
newlist = malloc(numelements * sizeof *newlist);
Since it is but a copy, the caller won't see the result of your assignment. What you seemingly want here is to pass a pointer by reference - for that, you need a pointer to pointer:
int takeEven(int *nums, int numelements, int **newlist) {
*newlist = malloc(numelements * sizeof **newlist); // apply * to newlist
...
}
int n = takeEven(nums, sizeof(nums) / sizeof(*nums), &evenNums);
And don't forget to free:
free(evenNums);
In C, everything is passed by value. So you are passing a copy of evenNums to the function. Whatever you modify it inside the function doesn't get reflected outside. You need to int** as the third parameter.