What does the following declaration mean?
char *(*g(char a, int b))
So far, I know that,
char *(*g)(char, int)
declares a pointer to a function that returns a char *, and I can successfully assign a value to it, however I can't do the same with the first. Any hints?
It looks like a function g that takes two arguments (char a and int b) and returns char**.
The outer parenthesis looks working like ones in char** x = /* some value */; char y = *(*x);
As a proof, this code compiles:
char *(*g(char a, int b));
char** test(void) {
return g(0, 0);
}
The two lines of code in the question are very different:
char *(*g(char a, int b)) // #1
char *(*g)(char, int) // #2
In #2 you have added a ) just after the g and that really changes the meaning a lot.
The first one is simply a function with the name g. It's the same as
char **g(char a, int b) // #1 without the unnecessary ( ) pair
but number two is a function pointer variable with the name g.
That also explains why you can assign to g in case #2 but can't assign to g in case #1.
Also notice that #1 is a function returning pointer-to-pointer-to-char while #2 is a function-pointer to a function returning pointer-to-char
So the two lines of code are different in more than one aspect.
What does , char *(*g(char a, int b)) mean?
g as function (char, int) returning pointer to pointer to char
When you write :
char *(*g)(char, int);
g is a pointer to a function...
Is you've got several functions taking a character and an integer for parameters and returning a 'char *' you can assign either of these functions to this pointer..
Example :
char *function1(char c, int i) {
...
}
char *function2(char c, int i) {
...
}
when you declare a pointer like you can see below, it can point on either of the above functions :
char *(*g)(char, int);
You can write:
g = function1 ;
or:
g = function2 ;
And when you call the function using the pointer:
char *retVal = (*g)('a', 12) ;
It will call either function1 or function2 depending on the last function that was assigned to the pointer.
As for :
char *(*g(char a, int b))
This is equivalent to :
char **g(char a, int b)
considering operator () has precedence level 1 and operator * has precedence level 2, the parenthesis doesn't affect the evaluation order.
Related
In the function read, I need to access the values of integer a and integer b from the main function without declaring them in the prototype of the function read, using pointers.
Pointer x should point to integer a, and pointer y should point to integer b.
#include <stdio.h>
void read(int zzz[], int n) {
int *arr = zzz, *x=a,*y=b;
}
int main() {
int a, b;
scanf("%d", &a);
scanf("%d", &b);
return 0;
}
How this could be implemented?
There are two ways that the read function can read the values or addresses of a and b:
Pass them as parameters
Make a and b global
So if you don't want to make them parameters, you need to move them outside of the main function and before the read function.
Also, read is the name of a system function, so you should name it something else so you don't conflict with it.
You have already received the more conventional answer. It is the most logical choice for your given restriction.
However ... Silly artificial restrictions sometimes deserve a silly contrived solution in kind.
A less conventional way would be to create an understanding with the function that the values will be passed in with the array pointer in some non-standard way.
For example, you can make two extra array members to represent a and b.
int array_for_my_read[array_size + 2];
/* instead of a and b, you use those extra array members */
...
int *x = zzz + n, *y = x + 1;
Alternatively, you could create a special structure that holds the array, and the pointers. Then the function recovers the pointer to the structure from the array pointer.
struct extra_parameters {
int *a;
int *b;
int zzz[zzz_size];
};
...
struct extra_parameters x;
int a, b;
x.a = &a;
x.b = &b;
read(x.zzz, zzz_size);
...
void *p = (char *)zzz - offsetof(struct extra_parameters, zzz);
struct extra_parameters *xp = p;
int *a = xp->a, *b = xp->b;
Let's suppose that we have the following functions (in C):
int sum(int a, int b){
return a+b;
}
int diff(int a, int b){
return a-b;
}
So we know that we can declare an array of funtion pointers in the following way:
int (*test[2]) (int a, int b);
test[0] = sum;
test[1] = diff;
But the following is also valid (but we use heap allocation):
int (**test) (int a, int b) = malloc( 2*sizeof(*test));
test[0] = sum;
test[1] = diff;
So far so good. Now let remember that to declare a (dynamically allocated) array of two integers we can do:
int* test = malloc( 2*sizeof(int));
So why we cannot declare an array of function pointers as
int (*test) (int a, int b) = malloc( 2*sizeof(*test)); ?
Is the reason that as test is the same as *test and **test (and so on), malloc( 2*sizeof(*test)) is returning a pointer to a function pointer and therefore it cannot be assigned to (*test) ?
If this supposition is correct, can you explain in detail why we get the compilation error
error: lvalue required as left operand of assignment
when we try to do
int (*test) (int a, int b) = malloc( 2*sizeof(*test));
test=diff; //<--- This is ok.
test+1 = sum; //<--- This is what gives the error!
Disclaimer: I suppose that this is a basic question and the supposition is correct, but I would like a better explanation to have this kind of thing clear one and for all.
Edit:
Notice that this is equivalent to
int (*test) (int a, int b) = malloc( 2*sizeof(*test));
*test=*diff; //<--- This is ok.
*(test+1) = *sum; //<--- This is what gives the error!
as this is somewhat more similar to the case:
int *test = malloc(2*sizeof(*test));
*test = 0;
*(test+1) = 1;
So why we cannot declare an array of function pointers as
int (*test) (int a, int b) = malloc( 2*sizeof(*test));
Because test does not point to a function pointer; it is a function pointer. Thus it cannot point to the first element of an array of function pointers.
If you want an array of function pointers use the previous form:
int (**test) (int a, int b) = malloc( 2*sizeof(*test));
Here, *test has function pointer type and thus test can (and does) point to the first element of an array of function pointers. Further:
error: lvalue required as left operand of assignment
when we try to do
int (*test) (int a, int b) = malloc( 2*sizeof(*test));
test=diff; //<--- This is ok.
test+1 = sum; //<--- This is what gives the error!
No matter what type test has, test+1=anything is always invalid C. test+1 can never be an lvalue. I don't see why you would expect this to work.
GCC is also papering over another bug in your program, sizeof(*test). Since *test has function type, sizeof(*test) is invalid, but GCC silently assigns it the value 1. This results in allocating too little memory for a function pointer, but it doesn't matter anyway because in the following line you throw away the memory you got from malloc and assign something else to test.
void main()
{
int (*d)[10];
d[0] = 7;
d[1]=10;
printf("%d\n",*d);
}
It should print 10 but compiler is showing error such as follows:
test.c:4:7: error: incompatible types when assigning to type ‘int[10]’ from type ‘int’
Note that I have included some errors , not all.
As noted by chris, d is a pointer to an array. This means you use the variable improperly when you access it, but also that you will access random memory unless you assign d to point to a valid array.
Change your program as follows:
int main(void)
{
int (*d)[10]; /* A pointer to an array */
int a[10]; /* The actual array */
d = &a; /* Make `d` point to `a` */
/* Use the pointer dereference operator (unary prefix `*`)
to access the actual array `d` points to */
(*d)[0] = 7;
(*d)[1] = 10;
/* Double dereference is okay to access the first element of the
arrat `d` points to */
printf("%d\n", **d);
return 0;
}
In C, [] is the same as *, the pointer syntax. Thus the following lines are the same:
int** array2d1;
int* array2d2[];
int array2d3[][];
To relate to a closer example, the main function has the following popular forms:
int main(int argc, char** argv){ ... }
or
int main(int argc, char* argv[]){ ... }
Thus
int (*d)[10]
is the same as
int* d[10]
which is the same as
int** d;
int firstArray[10];
d = &firstArray;
Effectively, you are creating a pointer to a pointer (which is a pointer to an array) and allocating the first pointer to an array that 10 elements. Therefore, when you run the following lines:
d[0] = 7;
d[1] = 10;
You are assigning the 1st array's address to 7 and the second array's address to 10. So as Joachim has mentioned, to assign values, you need to deference twice:
(*d)[0] = 7
(*d)[1] = 10
Which says "Assign 7 to the 0th index at the value pointed by d". I hope that makes sense?
d is a pointer to an array of 10 ints.
int (*d)[10] is the declaration for a point to an array of 10 ints.
vs.
int *d[10], which is an array of 10 int pointers.
For more complex syntax like this (usually involving pointers), I use cdecl to help me decode it.
It's used in this form
int d[10]
I guess you are mistaken that d must be a "kind of pointer" and therfor you put an * before the d.
But that's not what you want. You wan to name an array of integer and the notation for that is seen above.
Concept of pointer can get confusing sometimes in C.
Consider an array int d[6] = {0,1,2,3,4,5}
Then, *d is equivalent to d[0]. d is itself an pointer to an array and *d dereferences that pointer and gives us the value.
Hence, following code would print the same values:
int main()
{
int (d)[10];
*d = 7;
*(d + 1)=10;
printf("%d\n",*d);
printf("%d\n",d[0]);
return 0;
}
result:
7
7
Please see http://codepad.org/LYY9ig1i.
If you change your code as follows:
#include<malloc.h>
int main()
{
int *d[10]; //not (*d)[10]
d[0] = (int *)malloc(sizeof(int *) * 10);
d[0][0] = 7;
printf("%d\n",d[0][0]);
return 0;
}
Hope this helps you!
I would just like to confirm that when I have a function of the sort
int subtract(int a, int b)
{
return a-b;
}
I am passing values when i call subtract(3,2) rather than pointers.
Thanks,
Yes you are
a parameter of type int a means pass an integer by value to the function
a parameter of type int* a means pass a a pointer to some integer to the function.
so for this
int subtract(int a, int b)
{
// even if I change a or b in here - the caller will never know about it....
return a-b;
}
you call like this:
int result = substract(2, 1); // note passing values
for pointers
int subtract(int *a, int *b)
{
// if I change the contents of where a or b point the - the caller will know about it....
// if I say *a = 99; then x becomes 99 in the caller (*a means the contents of what 'a' points to)
return *a - *b;
}
you call like this:
int x = 2;
int y = 1;
int result = substract(&x, &y); // '&x means the address of x' or 'a pointer to x'
Yes, C always pass function parameters by value . To pass a pointer you have to specify the star (asterisk) that identify the pointer type.
Bear in mind that C always pass by value function parameters even in the case of a pointer, in that case the address of the pointer is actually copied .
Yes, you are passing values. A pointer would be denoted by an asterisk after the type name and before the variable name.
how to return more than one value from a function?
A function can only have a single return value. You could either pack multiple values into a compound data type (e.g. a struct), or you could return values via function parameters. Of course, such parameters would have to be passed using pointers to memory declared by the caller.
1
Declare method like this foo (char *msg, int *num, int *out1, int *out2);
and call it like this
int i=10;
char c='s';
int out1;
int out2;
foo(&c,&i,&out1,&out2);
Now what ever values u assign to out1 and out2 in function will be available after the function returns.
2
Return a structure having more than one members.
In C, one would generally do it using pointers:
int foo(int x, int y, int z, int* out);
Here, the function returns one value, and uses out to "return" another value. When calling this function, one must provide the out parameter with a pointer pointing to allocated memory. The function itself would probably look something like this:
int foo(int x, int y, int z, int* out) {
/* Do some work */
*out = some_value;
return another_value;
}
And calling it:
int out1, out2;
out1 = foo(a, b, c, &out2);
You cannot return more than 1 value from a function. But there is a way. Since you are using C, you can use pointers.
Example:
// calling function:
foo(&a, &b);
printf("%d %d", a, b);
// a is now 5 and b is now 10.
// called function:
void foo(int* a, int* b) {
*a = 5;
*b = 10;
}
Functions can return arrays or lists