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).
Related
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.
Suppose I have a function:
void add(int a, int b , int c);
and I have an array which contains 3 integer values:
int L[] = {1,2,3};
Now I want to pass these values to add without writing add(L[0],L[1],L[2]).
I mean is there a way of creating a Single input from multiple inputs and passing it to the function which will treat that single input as multiple inputs ??.
You could try this
int L[] = {1,2,3};
add(L, 3);
where
void add(int *x, int length)
{
// use x[0], x[1], etc.
}
But I am not sure why you are having problem with your current approach.
Another option would probably be to encapsulate those three integers into a structure and pass the structure along.
If you mean something like Python
def foo(a, b, c):
return a + b + c
x = (1, 2, 3)
print(foo(*x)) # the '*' does the magic of calling foo with 1, 2, 3
then this is not possible in portable C.
What you can do is change the interface of foo to accept an array of arguments, e.g.
int sum(int *data, int n) {
int tot = 0;
for (int i=0; i<n; i++) {
tot += data[i];
}
return tot;
}
can call it with
int x[] = {10, 20, 30, 40};
int res = sum(x, 4);
If you cannot change the function definitions and you have many of them with the same signature what you can do is use function pointers to factor out the call:
int sum3(int a, int b, int c) {
return a+b+c;
}
int mul3(int a, int b, int c) {
return a*b*c;
}
int call_int_int3(int(*f)(int, int, int), int* args) {
return f(args[0], args[1], args[2]);
}
...
int data[] = {10, 20, 30};
int sum = call_int_int3(sum3, data);
int prod = call_int_int3(mul3, data);
but you will need a different wrapper for each distinct signature (number and type of arguments and type of return value).
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;
}
}
A am trying an implementation of some sorting algorithms and I have to calculate how much time they spend. This is the function I wrote:
void bubble_sort(int A[], int len) {
bool ord = false;
for (int i=0; i<len-1 && ord==false; i++) {
ord = true;
for (int j=len-1; j>i; j--) {
if (A[j]-1>A[j]) {
ord = false;
swap(A[j]-1, A[j]);
}
}
}
}
And of course here there is a typical swap() function:
void swap(int x, int y) {
int d;
d = x;
x = y;
y = d;
}
I am not having troubles with Insertion Sort, Selection Sort and Merge Sort. By the way bubble_sort is not sorting the numbers in my array.
I cannot find what's wrong. Do you have any ideas?
In C, function parameters are passed by value, not by reference.
your swap() function does nothing (it doesn't even return... didn't your compiler complain?)
To actually sort, you have to change swap() to
void swap(int *x, int *y) {
int d = *x;
*x = *y;
*y = d;
return;
}
and invoke it with
swap(&A[j-1], &A[j]);
You have to include -1 in array A. Not outside the []. Your code non just chech if value in A[j]minus 1 is bigger than value in A[j]. Which is obviously always false.
Also in swap function you dont pass the ponter of the Array A. Actually swap() does nothing.
Try
if (A[j-1]>A[j]) {
ord = false;
int temp=A[j-1];
A[j-1]=A[j];
A[j]=temp;
I have successfully fscanf a text file and saved in to an array E2N1. I am trying to pass this into a function as a pointer but it is not working. Whenever I try to call E2N1[0][0], it says that E2N is neither an array or a pointer. I've been looking all over for a solution on this.
(Sorry E2N was meant to be E2N1)
I use fscanf as:
int E2N1[noz.rowE2N][Q.N];
FILE* f = fopen("E2N.txt", "r");
for(i=0; i<noz.rowE2N; i++){
for (j=0; j<Q.N; j++){
fscanf(f,"%d",&E2N1[i][j]);
}
fscanf(f,"\n");
}
fclose(f);
and again I can't pass E2N1 into function.
Your help will be greatly appreciated.
The function is:
double *dudtF = stiffness(&U, &massM, &noz, &newV, &E2N1, &I2E, &B2E, &PP, &QQ);
and I write the function header as:
double *stiffness(double *U, double *massM, MESH *meshN, double *V1, int *E2N1, int *I2E, int *B2E, ordApprox *pp, ordApprox *qq)
V1, I2E, B2E are three arrays and I'm trying to do the same with them as I am trying to do with E2N1.
The funny thing about arrays is that they actually act as pointers.
if you have array char a[3] the variable is equivalent to char* p the same way if you have array char b[3][4] the variable b is equivalent to char** q. In other words, you should consider changing the handling in the method to take reference to reference (and possibly once more to reference) to integer.
Try google... here are some results I've got.
http://www.dailyfreecode.com/code/illustrate-2d-array-int-pointers-929.aspx
http://www.cs.cmu.edu/~ab/15-123S09/lectures/Lecture%2006%20-%20%20Pointer%20to%20a%20pointer.pdf
You don't need to pass as &E2N1, just pass as E2N1 no & as array name itself translates to pointer.
double *dudtF = stiffness(&U, &massM, &noz, &newV, E2N1, &I2E, &B2E, &PP, &QQ);
Also, you need to take it as int ** as its 2-dimensional array.
double *stiffness(double *U, double *massM, MESH *meshN, double *V1, int **E2N1, int *I2E, int *B2E, ordApprox *pp, ordApprox *qq)
Here is the example how to transfer matrix from one function to another ...
void foo (int **a_matrix)
{
int value = a_matrix[9][8];
a_matrix[9][8] = 15;
}
void main ()
{
#define ROWS 10
#define COLUMNS 10
int **matrix = 0;
matrix = new int *[ROWS] ;
for( int i = 0 ; i < ROWS ; i++ )
matrix[i] = new int[COLUMNS];
matrix[9][8] = 5;
int z = matrix[9][8] ;
foo (matrix);
z = matrix[9][8] ;
}
You cannot reference a multi-dimensional array passed to a function by point referencing as in the following:
int iVals[10][10];
foo(iVals);
void foo(int** pvals)
{
// accessing the array as follows will cause an access violation
cout << pvals[0][1]; // access violation or unpredictable results
}
You will need to specify the second dimension to the array in the function prototype
for example:
foo(int ivals[][10])
{
cout << ivals[0][1]; // works fine
}
If do not know the dimensions, then I would suggest you follow the principles outlined here:
void foo(int *p, int r, int c)
{
for(int i=0; i<r; i++)
{
for(int j=0; j<c; j++)
{
printf("%d\n", p[i*c+j]);
}
}
}
int c[6][6];
// pointer to the first element
foo(&c[0][0], 6, 6);
// cast
foo((int*)c, 6, 6);
// dereferencing
foo(c[0], 6, 6);
// dereferencing
foo(*c, 6, 6);
I hope this helps.
Alternatively you could use SAFEARRAY - see:
http://limbioliong.wordpress.com/2011/06/22/passing-multi-dimensional-managed-array-to-c-part-2/