Function pointers, arrays and lvalues in C - c

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.

Related

Accessing variable value without declaring it in function prototype

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;

C - parameter in function can't handle int if declared as int*

I want to use the C function called is_subsetOf() in two different ways:
Way 1: int* a and int* b are arrays with sizes >=2.
Way 2: int* a has size >=2, but int* b is only size 1, which means b is an int.
How can I force C to be okay with int* b being of size 1? Or is this not possible in C? An int IS an array of size 1??
int* is_in(int *left_hand, int n_l, int *right_hand, int n_r) {
int *get_bool;
get_bool = malloc(sizeof(int)*n_l);
for (int i=0; i<n_l; i++) {
if (is_subsetOf(right_hand, n_r, *(left_hand+i), 1)) {
*(get_bool+i) = 1;
}
}
return (get_bool);
}
int desc(const void *a, const void *b) {
return (*(int*)a - *(int*)b);
}
int is_subsetOf(int *a, int n_a, int *b, int n_b) {
qsort(a, n_a, sizeof(int), desc);
qsort(b, n_b, sizeof(int), desc);
int v = includes(a, n_a, b, n_b);
return(v);
}
Here are the messages I get from the compiler. It's just a warning, I know, but I'd like everything to be clean.
tmp.c: In function ‘is_in’:
tmp.c:73:47: warning: passing argument 3 of ‘is_subsetOf’ makes pointer
from integer without a cast [-Wint-conversion]
if (is_subsetOf(right_hand, n_r, *(left_hand+i), 1)) {
~~~~~~~~~^~~
tmp.c:37:39: note: expected ‘int *’ but argument is of type ‘int’
int is_subsetOf(int *a, int n_a, int *b, int n_b) {
int* a and int* b are arrays with sizes >=2.
No, they are pointers and they don't have any size. You probably meant that you pass arrays through them, but they are not arrays. Know that there is a difference.
An int IS an array of size 1
No, int a[1]; is an array of size 1; int a; is just int. But arrays can decay into pointers to their first element and variables have addresses, so this is correct:
int a[1];
int b;
int* ptr1 = a;//Points to the a[0]
int* ptr2 = &b;
Both are now same type and can be used in the same way. Of course you don't know if the int is followed by any more ints in memory, that kind of checking is up to the programmer (usually by passing the length param as you do). The following is the code you are actually looking for:
is_subsetOf(right_hand, n_r, left_hand+i, 1)
Pointers can be incremented, left_hand+i will point to the i-th int after the int to which left_hand currently points to. Again, validity of such pointer is up to programmer.
The compiler warning is quite important here, because *(left_hand+i) is of type int and the compiler warns that it will treat is as int*. Essentially looking that the value of int as an address to memory. That's not at all what you want and it is an error.

Why do these pointers cause a crash?

I'm a bit confused as to why the following code crashes:
int main(){
int *a;
int *b;
*a = -2;
*b = 5; //This line causes a crash on my system.
return 0;
}
Shouldn't memory automatically be allocated for two pointers and two integers before run-time because of the declarations?
Or must you always explicitly allocate memory?
No. You've only declared the pointers, not what they point to. The pointers are allocated on the stack, and since you've not initialized them to anything, their values are garbage.
int main() {
int a = 7;
int *p_a; // p_a contains whatever garbage was on the stack at its
// location when main() is called. (Effectively points nowhere).
p_a = &a; // p_a points to (gets the address of) variable a, also on
// the stack.
printf("Before: a = %d\n", a); // prints 7
*p_a = -2;
printf("After: a = %d\n", a); // prints -2
return 0;
}
I would code up the above example, and step through it in a debugger. You'll see what I mean about what p_a is pointing to.
Shouldn't memory automatically be allocated for two pointers and two integers before run-time because of the declarations?
I only see you specifying two pointers. Where are the two integers?
Or must you always explicitly allocate memory?
Pointers have to point to something. Either local variables on the stack, or malloc'd memory from the heap.
In this code:
int* a;
*a = -2;
a is an uninitialized pointer, dereferencing of which produces undefined behavior, that you were luckily able to observe as a crash of your application.
You need to initialize the pointer (make it point to the valid memory) before you dereference it (i.e. before you use *, the dereference operator):
int a;
int* pA = &a;
*pA = -2;
Consider
int m;
int n;
m = n;
This is invalid because you're trying to use n but you haven't assigned a value to it. Now:
int *a;
*a = -2;
Likewise, this is invalid because you're trying to use a but you haven't assigned a value to it. The value of a is not an int, it's a pointer to int. For example,
int someint;
a = &someint;
*a = -2;
puts -2 into someint. Without the assignment to a, the place to put -2 is undeterminable. Also,
a = malloc(sizeof(int));
*a = -2;
Here, a is given the value of the address of some location in the heap; -2 goes into that heap location.
Perhaps an analogy would be helpful:
Consider the phrase "her dog". This is a reference to someone's' dog, but it won't do to tell me "give her dog a bone" if you haven't told me who she is. Similarly, "pointer to an int" doesn't tell the system which int it is.
Your *a and *b pointers are not initializated properly.
Try this one:
int my_a;
int my_b;
int *a;
int *b;
a = &my_a; // init the pointer a to the direction of my_a int variable
b = &my_b;
*a = 3; // set the my_a value via pointer
*b = 2;
You have just declared pointers but you haven't initialized them. So, you can't be sure that *b = 5 is causing the program to crash. It could be *a = -2 as well. To fix it, you should initialize your pointers as well.
int aval = -2;
int bval = 5;
int *a = &aval; // declared and initialized pointers
int *b = &bval;
// Now you can change the value using the pointer
*a = 15;
*b = 20;

What does (*ptr)[10] mean?

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!

passing a pointer as argument to a function in C

Something I stumbled upon and made me wonder.
Why does this work?
void foo (int* a)
{
int x = 3;
*a = x;
}
int main()
{
int a;
foo(&a);
return 0;
}
But this causes a segmentation fault (both on Visual Studio 2008 and gcc)?
void foo (int* a)
{
int x = 3;
*a = x;
}
int main()
{
int* a;
foo(a);
return 0;
}
Is it something defined in the language or just an implementation issue?
When you declare
int* a;
You are declaring a pointer variable a but you are not making it point to anything. Then in the function, you do
*a = x;
Which dereferences the pointer and tries to assign what it points to the value of x. But since it doesn't point to anything, you get undefined behaviour, manifested in a segmentation fault.
You should do this:
int i; // the actual integer variable
int* a = &i; // a points to i
The difference between that and the first one is that int a; declares a real integer variable, then you take its address with &a and passes it to the function. The pointer a inside the function foo points to the variable a in main, and so dereferencing it and assigning to it is perfectly fine.
int a;
Assigns memory as soon as you declare it but this not the case with int *a;
int *a;
is pointer declaration (MEMORY not yet allocated for that).
int *a = (int*)malloc(sizeof(int)); // allocate memory

Resources