convert function for use with qsort - c

I'm working on a simple library which operate on vectors.
It define a type of function that is regularly used:
typedef float (*vec_pair_fun) (float x, float y);
For ease-of-use reason, I want to create a sorting function that use a vec_pair_fun to compare each element of a vector.
At the moment, I'm doing this:
static vec_pair_fun sort_function;
// follow improvements suggested by #chux below
static int converted_sort_function(const void* a, const void* b){
//old code: return (int) qsort_function(*(float*)a,*(float*)b);
float f = sort_function(*(float*)a,*(float*)b);
return (f > 0.0f) - (f < 0.0f);
}
void vecx_sort(int x, float v[], vec_pair_fun func){
sort_function=func;
qsort(v,x,sizeof(float),converted_sort_function);
}
but I don't really like that workaround because it's not threadsafe as sort_function can be changed by another thread.
Any idea on how to improve this?
EDIT:
One way would be to sort the array myself.
Recoding qsort is really not what I planned to do, so I'm really open for suggestions

Q: Any idea on how to improve this?
A: Do not cast float result to int for compare.
Maybe not OP's main concern but (int) sort_function(*(float*)a,*(float*)b); is weak.
The FP point result could be -0.4 or 0.4, both of these convert to (int) 0.
The FP point result could be > INT_MAXand conversion to int is UB.
Suggest:
static int converted_sort_function(const void* a, const void* b){
float f = sort_function(*(float*)a,*(float*)b);
return (f > 0.0f) - (f < 0.0f);
}
As to your thread safe problem, consider qsort_s() which passes in a context pointer. qsort_s() is specified in C11 Annex K, so it may not exist in your compiler.
errno_t qsort_s(void *base, rsize_t nmemb, rsize_t size,
int (*compar)(const void *x, const void *y, void *context),
void *context);

Following wikibooks 5th C implementation and Apple's implementation of a quicksort algorithm, I was able to create my function.
It appear to be quicker than the stdlib version, and it has no global/static variable.
// x: length of v
// v: array of float
// func: a function that takes two float as argument and return a float
void vecx_qsort(unsigned int x, float v[], vec_pair_fun cmpf)
{
float pivot,tmp;
unsigned int al,l,r,ar,cnt;
while (x>8)
{
cnt=0;
al=l=1; r=ar=x-1;
pivot=v[x/2];
v[x/2]=v[0];
v[0]=pivot;
while (1)
{
while ( l<=r && (tmp=cmpf(v[l],pivot))<=0.0f ) {
if(tmp==0.0f){
cnt=1;
vecx_swap(1,v+al,v+l); //swap vl & val
al++;
}
l++;
}
while ( l<=r && (tmp=cmpf(v[r],pivot))>=0.0f ) {
if(tmp==0.0f){
cnt=1;
vecx_swap(1,v+r,v+ar);//swap vr & var
ar--;
}
r--;
}
if(l>r)
break;
cnt=1;
vecx_swap(1,v+r,v+l);
l++; r--;
}
if(cnt==0 && x<=32) // no swap made => almost sorted small array => insertion sort
break;
// swap values equal to pivot to the center
cnt = (al<(l-al))?al:l-al;
vecx_swap(cnt,v,v+l-cnt); // swap of element before al
cnt = ((ar-r)<(x-ar-1))?ar-r:x-ar-1;
vecx_swap(cnt,v+l,v+x-cnt); // swap of element after ar
l=l-al; // size of "smaller element array"
r=ar-r; // size of "bigger element array"
// Recursion on the shorter side & loop (with new indexes) on the longer
if (l>r) {
vecx_qsort(r, v+x-r, cmpf);
x=l;
}
else {
vecx_qsort(l, v, cmpf);
v+=x-r;
x=r;
}
}
// insertion sort
for (r=1; r<x; r++)
{
pivot=v[r];
for(l=r; l>0 && cmpf(pivot,v[l-1])<0.0f; l--)
v[l]=v[l-1];
v[l]=pivot;
}
}

Related

How do I make use of a custom library in C

I've written some code in regard to a uni assignment, but I keep stumbling across the problem where my custom function doesn't give any other output then zero.
Basically, I'm asking how to retrieve the result of the function to use in my code.
Here I will paste my code.
#include <stdio.h>
//math.h is included via the header file because the compiler liked it better.
int V;
int H;
int R;
int result;
#include "A1_header.h"
int main()
{
//small introduction
printf("Welcome to the volume test game\n");
printf("We will start with spheres. \n");
printf("Please input your sphere radius here:");
scanf("%d", &R);
CalcSphVolume(&V, &R);
printf("please input your result:");
scanf("%d", &result);
if(result == V){
printf("Congratulations, your answer is correct!\n");
}
else{
printf("Wrong answer, the correct result was %d \n", V);
}
return 0;
}
Below is my .h file which I use to define functions.
#ifndef Point
#define Point
#include <math.h>
//these are the functions for Sphere calculations
void CalcSphVolume(int V, int R) {
V = 1.33*3.14(R*R*R);
}
void CalcSphRadius(int V, int R) {
R = cbrt(V/4.1762);
return;
}
//these are the functions for the Cone calculations
void CalcConVolume(int V, int R, int H) {
V = 0.33*(3.14*(R*R))H;
return;
}
void CalcConHeight(int V, int R, int H) {
H = V/(0.33*(3.14*(R*R)));
}
void CalcConRadius(int V, int R, int H) {
R = sqrt(V/(0.33*3.14H));
}
//these are the functions for the Cilinder calculations
void CalcCilVolume(int V, int R, int H) {
V = 3.14*H*(R*R);
}
void CalcCilHeight(int V, int R, int H) {
H = V/(3.14(R*R));
}
void CalcCilRadius(int V, int R, int H) {
R = sqrt(V/(3.14*H));
}
#endif
I am not sure how you are running the code, because under ordinary circumstances this code will not compile.
There are a couple of things that are wrong in this code -
void CalcSphVolume(int V, int R) {
V = 1.333.14(RRR);
}
Firstly, I think there might be an error in your formatting, because RRR is not the correct way to compute, what you want is (R*R*R), similarly, 1.333.14 is not an accepted datatype. From context, since it is the volume of a sphere, this should be
void CalcSphVolume(int V, int R) {
V = 1.333 * 3.14 * (R*R*R);
}
Now that this is out of the way, there are some issues with this function (and similar to the other functions in your code.)
You are mixing types here - 1.333 is double, but V is int, so your actual answer will be implicitly converted to an integer, and you will lose precision. So V should be of the type double. So you get a more accurate answer.
void CalcSphVolume(double V, int R) {
V = 1.333 * 3.14 * (R*R*R);
}
Another thing to note here is that your functions parameters are by value and do not accept pointers. This means that any result that you get in this void function, will be lost unless you explicitly return it. Local variables only exist in the scope of the function. Since you are passing a pointer to the function and trying to populate the value outside the function, you should modify the function and function signature to
void CalcSphVolume(double* V, int* R) {
int r = *R // for clarity
*V = 1.333 * 3.14 * (r*r*r);
}
We have to dereference to get the "actual" value that is held by the pointer. You cannot apply arithmetic logic in this manner to raw pointers.
An alternative way to accomplish the same is
double CalcSphVolume(int R) {
double V = 1.333 * 3.14 * (R*R*R);
return V; // or simply return 1.333 * 3.14 * (R*R*R)
}
Here you are passing by value, but returning the value computer back to the caller. So you could use this function like so -
double Volume = CalcSphVolume(R);
This is much more clearer in this case, instead of having to pass pointers all over the place.
For your use case, using pointers is not necessary - consider using pointers when you have to mutate or pass large objects (Imagine a really huge array, so you don't want to create a copy it each time you use it in a function) which cannot be declared on the stack.
The issue is your function parameters are taking in an integer rather than a pointer to the memory address.
What you want to do instead is:
void CalcSphRadius(int *V, int *R)
{
*R = cbrt((*V)/4.1762);
return;
}
Now, the function is taking in a pointer to V and R and will read/write to their memory address.
As shown above, don't forget to dereference your pointers by using an asterisk '*' so that way you are writing to the value stored in those addresses, rather than just doing pointer arithmetic.
You can also retrieve values by using return types for functions.
int CalcSphRadius(int V)
{
return cbrt(V/4.1762);
}
And then use them to assign variables like so:
R = CalcSphRadius(V);
Your .h file name should be A1_header.h
Also, the code can be like this:
#ifndef Point
#define Point
#include <math.h>
#include <stdio.h>
//these are the functions for Sphere calculations
void CalcSphVolume(int V, int R);
void CalcSphRadius(int V, int R);
//these are the functions for the Cone calculations
void CalcConVolume(int V, int R, int H);
void CalcConHeight(int V, int R, int H);
void CalcConRadius(int V, int R, int H);
//these are the functions for the Cilinder calculations
void CalcCilVolume(int V, int R, int H);
void CalcCilHeight(int V, int R, int H);
void CalcCilRadius(int V, int R, int H);
#endif
#include "A1_header.h" in the wrong place.
It should be like
//directives
#include <stdio.h>
#include "A1_header.h"
int main(void)
{
variable declaration;
statements
}
Please try to learn the structure of the C program.
You need to declare the variables inside the main function.
When you call the function CalcSphVolume(V, R); why the address of the variable? It should be:
printf("Please input your sphere radius here:");
scanf("%d", &R);
CalcSphVolume(V, R);
Arrange all the functions properly
eg: CalcCilHeight function should be properly formatted with *
void CalcCilHeight(int V, int R, int H)
{
H = V/(3.14 * (R * R));
}

Error when compiling : incompatible types and similar warnings ( picture attached )

I'm writing a function that returns the inverse of an array using recursivity but I keep getting these warnings :
Here is my code
#include <stdio.h>
#include <stdlib.h>
int inv( float* t[],int n)
{ float u;
if (n==0) return 0;
else
{
u=*t;
*t=*(t+n);
*(t+n)=u;
return(inv(*(t+1),n-1));
}
}
int main()
{
float t[]={1,2,3,4,5,6,7,8,9};
int n=sizeof t /sizeof *t;
int i=0;
inv(t,n);
for(i=0;i<n;i++)printf("%f",t[i]);
return 0;
}
int inv( float* t[],int n)
Here, float* t[] declares an array of pointers. Please note that *t[i] = *(*(t+i))
For i = 0, *(*(t+i)) = *(*(t)) = *(*t).
Here, *t is of type float*, and u is of type float.
Using the expression u=*t; gives you that error (assigning float* value to float)
Solution : Change int inv( float* t[],int n) to int inv( float t[],int n)
I use a procedure to arrange the array elements in descending order
#include <stdio.h>
#include <stdlib.h>
void revs(int i, int n, float *arr)
{
if(i==n)
{
return ;
}
else
{
revs(i+1, n, arr);
printf("%.f ", arr[i]);
}
return 0;
}
int main()
{
float t[]={1,2,3,4,5,6,7,8,9};
int n=sizeof t /sizeof t[0];
int i=0;
revs(0,n,t);
}
It looks like the intended action of OP's function inv is to reverse the elements of an array of n float values in place, using recursion.
In the original inv code, the parameter declaration float* t[] will be adjusted to be equivalent to float** t by the compiler. This needs to be changed to float t[] or equivalently float* t.
In the original inv code, the return value is either 0 or the result of the recursive call to itself, which can only be 0. Therefore the return value is of no use. It would be better to change the return type of the function to void.
In the inv function, the parameter n is set to the length of the array in the initial call from main. The function swaps the values of elements at indices 0 and n before recursing, but there is no element at index n. The last element has index n-1. The function should swap the elements at indices 0 and n-1 before recursing. After swapping the first and last elements, the remaining n-2 elements with indices from 1 to n-2 can be swapped by a recursive call. The original inv code uses the value n-1 in the recursive call, but it should be n-2.
If n is less than 2, the inv function does not need to do anything.
A possible implementation of inv based on OP's original code follows:
void inv(float* t,int n)
{
float u;
if (n>=2)
{
u=*t;
*t=*(t+n-1);
*(t+n-1)=u;
inv(t+1,n-2));
}
}
The same function can be written using array subscripting operators as follows:
void inv(float t[],int n)
{
float u;
if (n>=2)
{
u=t[0];
t[0]=t[n-1];
t[n-1]=u;
inv(&t[1],n-2));
}
}

why pass as argument of a function a function?

i have a little question.
i'm studying C with devc++ (as start) and i have seen as argument function you can pass a function, this is ok but why?
for example u can write as argument:
void myfunc(void(*func)(int)){}
but if u simple call function with his name and argument it is not better?
like example:
void myfunction (){name of func to call(myargs); }
there's a difference?
it seems the same thing but with more simple and short code
edit:
i want only know
void map (int (*fun) (int),int x[ ], int l) {
for(i = 0; i < l; i++)
x[i] = fun(x[i]);
}
why u use this instead of:
void map (int x[ ], int l) {
for(i = 0; i < l; i++)
x[i] = nameoffunction(yourargument);
}
You can use a function pointer as a parameter if you want your function to do different things depending on what the user wants.
Here's a simple example:
#include <stdio.h>
int add(int x, int y)
{
return x + y;
}
int subtract(int x, int y)
{
return x - y;
}
int multiply(int x, int y)
{
return x * y;
}
int divide(int x, int y)
{
return x / y;
}
int operation(int x, int y, int (*func)(int, int))
{
printf(" x=%d, y=%d\n", x, y);
return func(x,y);
}
int main()
{
int x = 8, y = 4;
printf("x+y=%d\n", operation(x,y,add));
printf("x-y=%d\n", operation(x,y,subtract));
printf("x*y=%d\n", operation(x,y,multiply));
printf("x/y=%d\n", operation(x,y,divide));
return 0;
}
A very good example is the classic sorting function qsort. It's a library function, which means that you only have access to it's prototype. In order to make qsort general, you have to write your own compare function. A typical implementation looks like this for regular integers:
int cmpfunc (const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
And then, if you have an array arr of integers you can sort it with qsort(arr, sizeof(arr), cmpfunc)
You might ask why this is not built in the qsort function? After all, it would be easy to make it work for both floats and integers. Yes, but imagine if you have an array of structs that look like this:
struct {
char *firstname;
char *lastname;
int age;
} persons[10];
How would you sort this? Well, that's not obvious. You might want all three. In that case, write three different compare functions.
i want only know
void map (int (*fun) (int),int x[ ], int l) {
for(i = 0; i < l; i++)
x[i] = fun(x[i]);
}
why u use this instead of:
void map (int x[ ], int l) {
for(i = 0; i < l; i++)
x[i] = nameoffunction(yourargument);
}
Let's answer the question with a question - what if you want to perform more than one type of mapping? What if you want to map both x2 and √x?
You could certainly do something like
void map( int x[], int l, int type )
{
for ( int i = 0; i < l; i++ )
{
if ( type == MAP_SQUARED )
x[i] = int_square( x );
else if ( type == MAP_ROOT )
x[i] = int_root( x );
...
}
}
which works, but is hard to read and cumbersome to maintain - every time you want to perform a new mapping, you have to add a new case to the map function.
Compare that to
void map( int x[], int l, int (*fun)(int) )
{
for ( int i = 0; i < l; i++ )
x[i] = fun( x[i] );
}
...
map( x, l, int_square );
map( y, l, int_root );
You don't have to hack the map function to get different mappings - you only have to pass the function that operates on the individual elements. If you want to perform a new mapping, all you have to do is write a new function - you don't have to edit the map function at all.
The C standard library uses this form of delegation in several places, including the qsort function (allowing you to sort arrays of any type in any order) and the signal function (allowing you to change how a program reacts to interrupts dynamically).

Sorting data from struct alphabetically? [duplicate]

Is there any library function available in C standard library to do sort?
qsort() is the function you're looking for. You call it with a pointer to your array of data, the number of elements in that array, the size of each element and a comparison function.
It does its magic and your array is sorted in-place. An example follows:
#include <stdio.h>
#include <stdlib.h>
int comp (const void * elem1, const void * elem2)
{
int f = *((int*)elem1);
int s = *((int*)elem2);
if (f > s) return 1;
if (f < s) return -1;
return 0;
}
int main(int argc, char* argv[])
{
int x[] = {4,5,2,3,1,0,9,8,6,7};
qsort (x, sizeof(x)/sizeof(*x), sizeof(*x), comp);
for (int i = 0 ; i < 10 ; i++)
printf ("%d ", x[i]);
return 0;
}
C/C++ standard library <stdlib.h> contains qsort function.
This is not the best quick sort implementation in the world but it fast enough and VERY
EASY to be used... the formal syntax of qsort is:
qsort(<arrayname>,<size>,sizeof(<elementsize>),compare_function);
The only thing that you need to implement is the compare_function, which takes in two
arguments of type "const void", which can be cast to appropriate data structure, and then
return one of these three values:
negative, if a should be before b
0, if a equal to b
positive, if a should be after b
1. Comparing a list of integers:
simply cast a and b to integers
if x < y,x-y is negative, x == y, x-y = 0, x > y, x-y is positive
x-y is a shortcut way to do it :)
reverse *x - *y to *y - *x for sorting in decreasing/reverse order
int compare_function(const void *a,const void *b) {
int *x = (int *) a;
int *y = (int *) b;
return *x - *y;
}
2. Comparing a list of strings:
For comparing string, you need strcmp function inside <string.h> lib.
strcmp will by default return -ve,0,ve appropriately... to sort in reverse order, just reverse the sign returned by strcmp
#include <string.h>
int compare_function(const void *a,const void *b) {
return (strcmp((char *)a,(char *)b));
}
3. Comparing floating point numbers:
int compare_function(const void *a,const void *b) {
double *x = (double *) a;
double *y = (double *) b;
// return *x - *y; // this is WRONG...
if (*x < *y) return -1;
else if (*x > *y) return 1; return 0;
}
4. Comparing records based on a key:
Sometimes you need to sort a more complex stuffs, such as record. Here is the simplest
way to do it using qsort library.
typedef struct {
int key;
double value;
} the_record;
int compare_function(const void *a,const void *b) {
the_record *x = (the_record *) a;
the_record *y = (the_record *) b;
return x->key - y->key;
}
For sure: qsort() is an implementation of a sort (not necessarily quicksort as its name might suggest).
Try man 3 qsort or have a read at http://linux.die.net/man/3/qsort
While not in the standard library exactly, https://github.com/swenson/sort has just two header files you can include to get access to a wide range of incredibly fast sorting routings, like so:
#define SORT_NAME int64
#define SORT_TYPE int64_t
#define SORT_CMP(x, y) ((x) - (y))
#include "sort.h"
/* You now have access to int64_quick_sort, int64_tim_sort, etc., e.g., */
int64_quick_sort(arr, 128); /* Assumes you have some int *arr or int arr[128]; */
This should be at least twice as fast as the standard library qsort, since it doesn't use function pointers, and has many other sorting algorithm options to choose from.
It's in C89, so should work in basically every C compiler.
try qsort in stdlib.h.
I think you are looking for qsort.
qsort function is the implementation of quicksort algorithm found in stdlib.h in C/C++.
Here is the syntax to call qsort function:
void qsort(void *base, size_t nmemb, size_t size,int (*compar)(const void *, const void *));
List of arguments:
base: pointer to the first element or base address of the array
nmemb: number of elements in the array
size: size in bytes of each element
compar: a function that compares two elements
Here is a code example which uses qsort to sort an array:
#include <stdio.h>
#include <stdlib.h>
int arr[] = { 33, 12, 6, 2, 76 };
// compare function, compares two elements
int compare (const void * num1, const void * num2) {
if(*(int*)num1 > *(int*)num2)
return 1;
else
return -1;
}
int main () {
int i;
printf("Before sorting the array: \n");
for( i = 0 ; i < 5; i++ ) {
printf("%d ", arr[i]);
}
// calling qsort
qsort(arr, 5, sizeof(int), compare);
printf("\nAfter sorting the array: \n");
for( i = 0 ; i < 5; i++ ) {
printf("%d ", arr[i]);
}
return 0;
}
You can type man 3 qsort in Linux/Mac terminal to get a detailed info about qsort.
Link to qsort man page
Use qsort() in <stdlib.h>.
#paxdiablo
The qsort() function conforms to ISO/IEC 9899:1990 (``ISO C90'').
There are several C sorting functions available in stdlib.h. You can do man 3 qsort on a unix machine to get a listing of them but they include:
heapsort
quicksort
mergesort
GNU qsort source in stdlib shows that it is quicksort.

Haskell Foldr C implementation

I'm trying to implement a version of Haskell's foldr function in C but have hit a wall making it generic as I want to make the + or * characters (char y in foldr) work as addition or multiplication. I was thinking of trying a macro but wasn't sure what would work.
Here the code:
int
foldr(int *v, int (*f)(int*), int x, char y)
{
int temp;
if(*v == (int) NULL) //v is null terminated int array
return x;
else{
temp = *v;
return temp y ((*f)(++v));
}
}
Main issue is making char y work so I can say:
int
sum(int *v)
{
return foldr(v, (sum), 0, '+');
}
and it would just work.
Thanks
I'll show a recursion-based approach. As an exercise, you could turn it into an iterative solution, if you wish.
(Warning: untested)
Haskell:
foldr :: (Int->Int->Int) -> Int -> [Int] -> Int
foldr f x [] = x -- base case
foldr f x (v:vs) = f v (foldr f x vs) -- recursion
C:
int foldr(int (*f)(int,int),
int x,
int *v, size_t length) {
// base case
if (length == 0) return x;
// recursion
return f(*v, foldr(f, x, v+1, length-1));
}
Test:
int add(int a, int b) {
return a+b;
}
int main() {
int a[] = {1,2,3} ;
int res = foldr(add, 0, a, sizeof a/sizeof *a);
printf("%d\n", res);
return 0;
}
If you pass a proper function pointer (like add) above, there is not need to pass the character operator '+'.
Note that functional programming languages also allow to build closures, as in:
let y = 5
in foldr (\x c -> x*y+c) 0 [1..3]
Note how the function \x c -> x*y+c also depends on the value of y. C does not allow to do craft closures, but you can emulate the captured y, if you allow an addition void * argument to the C function.
int foldr(int (*f)(void *, int, int),
void *data,
int x,
int *v, size_t length) {
// base case
if (length == 0) return x;
// recursion
return f(data, *v, foldr(f, data, x, v+1, length-1));
}
Test:
int g(void *data, int x, int c) {
int y = *(int *)data;
return x*y+c;
}
int main() {
int a[] = {1,2,3} ;
int y = 5;
int res = foldr(g, &y, 0, a, sizeof a/sizeof *a);
printf("%d\n", res);
return 0;
}
In this way you can reuse g with different values of y. If you need to capture more variables, pass a pointer to a suitable struct containing all such variables.

Resources