C passing a pointer to an array on the stack - arrays

I am getting confused as to whether it is valid (in C) to pass a pointer to an array that has been initiated as follows (e.g. at compile time on the stack):
int a[] = {1, 2, 3};
my_func(&a);
void my_func(int **a)
{
int *tmp = *a; /* this statement fixes the problem */
printf("%d %d %d", (*a)[0], (*a)[1], (*a)[2]); /*doesn't work */
printf("%d %d %d", tmp[0], tmp[1], tmp[2]); /*does work */
}
when I step through this with gdb I can't 'see' any of the values (*a)[0], etc. from 'inside' my_func. e.g.
(gdb) p (*a)[0]
Cannot access memory at address 0x0
I'm thinking that possibly I have a fundamental misunderstanding with regard to what you can and can't do with arrays that are on the stack rather than the heap?
I hope thats not the case as it is very convenient for my unit tests to declare arrays on the stack as in the example, but I need to test functions that are expecting pointers to pointers to int.
Note I do get a compiler warning as follows:
test_utility.c:499:5: warning: passing argument 1 of ‘int_array_unique’ from incompatible pointer type [enabled by default]
../src/glamdring2.h:152:5: note: expected ‘int **’ but argument is of type ‘int (*)[12]’
but I thought it would be ok to mix int *a[] with **a? Perhaps not? Are they not equivalent?

a[] is an array, not a pointer ("not an lvalue"); in your function call
func( &a);
&a decays to a pointer to int; &a is not a pointer to pointer to int. Why? there is no pointer to point to.
The function prototype
void func( int **p);
expects a pointer to pointer to int, that does not fit the function being called with a pointer to int as an argument, like you did.
UPDATE: I don't know what the OP's intentions were, so this is just a guess...
void my_func(int *a);
int a[] = {1, 2, 3};
my_func(a); /* note: this is equivalent to my_func( &a ); */
void my_func(int *a)
{
printf("%d %d %d\n", a[0], a[1], a[2] );
}

printf("%p vs %p vs %p\n",&a,&a[0],a);
&a &a[0] and a - are all the same - the address of the first int in the array
void my_func(int **a);
int main(int ac, char *av[]) {
int a[] = {1, 2, 3};
int *p = a;
printf("%p vs %p vs %p\n",&a,&a[0],a); //are all the same - the address of the first int in the array
my_func(&p);
return 0;
}
void my_func(int **a) {
printf("%d %d %d", (*a)[0], (*a)[1], (*a)[2]);
}
http://www.ibiblio.org/pub/languages/fortran/append-c.html
http://publications.gbdirect.co.uk/c_book/chapter5/arrays_and_address_of.html

It's perfectly fine to declare an array on the stack and pass its address to a function, so long as the function doesn't try to store a reference to the array for later use.
Not sure why you're adding the extra indirection to the the argument, though. Why not just declare my_func to take an int* as a parameter, and simply pass a as the argument? This is less likely to confuse the debugger.

You are assuming that sizeof(int) == sizeof(void *). This might not be true. I am not sure if this is the cause of your problem, but at least I would start by either adding a runtime test asserting the assumption, or probably better change from int to pointer.

Related

cannot understand this error

As I am a beginner in C
When I run the following C code :
#include<stdio.h>
void f(int *p)
{
*p=3;
}
int main()
{
int *p;
f(&p);
return 0;
}
I get these messages after compilation:
1) warning:passing arg 1 of 'f' from incompatible pointer type f(&p)
2) note: expected 'int *' but argument is of type 'int **' void
f(int *p)
Please note:
&p is the memory address of a variable
*p is the actual value of the variable
So what you are doing is:
In main: You are generating a variable pointer p. And you are passing this pointers address to a function f.
f thinks it gets a pointer as parameter but it gets a memory address and obviusly can't handle it.
More information is here
Hope I could help!
You're passing a pointer to a pointer as an argument to a function expecting a pointer to an int. They're two different types and the compiler will complain.
There is another issue where you have the 'pointer' to the int but not the space allocated to store it. There are a couple solutions to this situation.
1)
{
int q; // add a new int, to which p points to. this allocates memory for an int
int *p = &q;
f(p); // don't pass a pointer to a pointer, just the pointer
return 0;
}
2)
{
int p; // have p be the int in the first place, not a pointer
f(&p); // your original call is unchanged and works now
return 0;
}
It's hard to think about this, because there are multiple levels of pointers.
Here's a simpler example. This is what we might call "pass by reference":
#include <stdio.h>
void f(int *ip)
{
*ip = 5;
}
int main(){
{
int i = 7;
printf("%d\n", i);
f(&i);
printf("%d\n", i);
}
Function f accepts a pointer to an int. It modifies that int. In main, we have an int variable i. We take the address of that variable using &, and pass the resulting pointer to function f. In this way, function f is able to modify i in the caller. Note that function f takes a pointer to something, and that what it takes a pointer to is the type of i in the caller -- in other words, pointer to int.
Now let's look at another example. This time, instead of manipulating an int by reference, we're going to manipulate a pointer variable, a char *. (We're going to end up dealing with pointers to pointers.)
void g(char **sp)
{
*sp = malloc(10);
strcpy(*sp, "oranges");
}
int main(){
{
char *s = "apples";
printf("%s\n", s);
g(&s);
printf("%s\n", s);
}
Again, function g accepts an argument by reference. Again, function g is able to modify a variable in its caller. Again, the pointer type accepted by g is a pointer to the type being manipulated. Since the type being manipulated is "pointer to char", function g accepts a pointer to pointer to char, or char **.
But the code you posted is sort of a mixture of the two. Your function f accepts an int pointer, just like mine, and it tries to use that int pointer to modify an int variable in the caller. But then, in your main function, the variable you're trying to modify isn't an int, it's a pointer to int, or int *.
When you call
f(&p);
you're starting with a pointer-to-int, p, and you're taking its address with &, resulting in a pointer-to-pointer-to-int. But then you;re calling function f, which expects a pointer-to-int. That's what the compiler is trying to tell you with the messages
warning: passing arg 1 of 'f' from incompatible pointer type
note: expected 'int *' but argument is of type 'int **'

When using a multi-dimensional array, What is the difference between using the pointer to that array and using actual array name as pointer

I have this code, Which uses function to which a pointer to an array is passed
#include<stdio.h>
void func(int ptr[][3])
{
printf("%d %d",*ptr,*ptr+1);
}
void main()
{
int arr[2][3]={{1,2,3},{4,5,6}};
int (*ptr)[3]=arr;
func(ptr);
}
Now, If I pass the actual array name to the function as
#include<stdio.h>
void func(int ptr[][3])
{
printf("%d %d",*ptr,*ptr+1);
}
void main()
{
int arr[2][3]={{1,2,3},{4,5,6}};
int (*ptr)[3]=arr;
func(arr);
}
Both of the above code executes and prints the same address. But what is the point of having a pointer if array name of multi-dimensional array does the same job.
Or is there any difference between them?
This:
printf("%d %d",*ptr,*ptr+1);
...isn't doing what I'd guess you intend it to. In particular, the precedence means that *ptr+1 means the same as (*ptr)+1, whereas I'd guess what you really wanted was:
*(ptr + 1)
To get an idea of the real difference between the two, it might make more sense to not dereference the pointers at all, and just print out the addresses:
void func1(int *a) {
printf("%p %p\n", (void *)a, (void *)(a+1));
}
void func2(int ptr[][3]) {
printf("%p %p\n", (void *)ptr, (void *)(ptr+1));
}
int main() {
int x[] = {1, 2, 3};
printf("sizeof int == %d\n\n", (int)sizeof(int));
func1(x);
func2(&x);
}
Now let's look at the result:
sizeof int == 4
0x7ffe3f67ba20 0x7ffe3f67ba24
0x7ffe3f67ba20 0x7ffe3f67ba2c
The first shows addresses ending in f00 and f04. As shown, sizeof(int) == 4, so we're seeing pretty much what we expect--adding 1 to an int * yields a pointer to the next int, so the address is increased by 4.
In the second case, the addresses end with a20 and a2c, so we're seeing a difference of c (12 decimal). In this case, it's not a pointer to an int--it's a pointer to an array of three ints. So, when we add one, the address changes by the size of an array of three ints of 4 bytes apiece (i.e., 3x4 = 12).
But what is the point of having a pointer if array name of multi-dimensional array does the same job.
The point is that an array is something completely different than a pointer and of course, you could have a pointer without an array.
The array holds many objects of the same type in a contiguous memory region. So pointer vs array makes a (huge) difference for the declaration.
Taking a pointer of an array just to pass it along is not necessary because that happens automatically in C. It doesn't hurt either.

Passing a variable into a function and changing its global value

I am trying to pass a variable into a function and change its global value but it does not work. Here is the simplified code:
int main()
{
int *Num = malloc (sizeof (int));
ChangeValue(&Num);
printf("Number is %i\n", Num);
}
int ChangeValue(int *temp)
{
*temp = 10
}
The error message is:
expected 'int *' but argument is of type 'int **'
I tried to change the function to int ChangeValue(int **temp) but received the following error:
warning: assignment makes pointer from integer without a cast.
Any suggestions?
int *Num means Num is of type int *. Since it's already an integer pointer, there's no need to take its address again when you pass it to your function that takes an int *.
ChangeValue(Num);
OTOH, since it is a pointer you will have to dereference it to use it as an integer, like with printf.
printf("Number is %i\n", *Num);
Variable Num is a pointer to an int (int*). Function ChangeValue(int*) takes a pointer to an int (int*). However, you are passing a pointer to Num (int**) to it.
Short answer: remove & before Num in ChangeValue(&Num);
Long answer: You seem to have a problem understanding how pointers work, you might want to read more about this before going further.

statically allocated array as function argument in C

Can I do this in C:
void myFunc(int *vp) {
// do some stuff with vp
}
int main() {
int v[5] = {1,2,3,4,5};
myFunc(v);
return 0;
}
I mean, what would be the correct? myFunc(&v); ?
Thanks!!
Arrays decay to pointers when you pass them as arguments. However, array decay is not the same as taking the address of an array.
"Decay" is how some types are transformed when passed as function arguments. Even though v's type is int [5], it becomes int* when you pass it to a function. This is a behavior a lot of people don't like, but there's nothing to do about it.
Note that, on the other hand, the type of &v is int (*)[5], that is, a pointer to an array of 5 integers. This type doesn't decay, that is, it doesn't transform automatically into another type if you pass it as a function parameter (and that's also why it wouldn't work if you used it in your example, since you need a pointer to integers, not a pointer to an array of integers).
The "correct" thing to do (assuming decay is OK) is to do myFunc(v), just as you're doing in your snippet. Keep in mind that you lose array bounds information when you do it.
Yes ... Your code is correct.
Here v==&v[0] array name is equal to address of first element of array
myFunc(v);
passing array name as argument that means you are passing address of first element in array.
void myFunc(int *vp)
Here you are using pointer. which store the address of first element of array which is passed so you can access the block which is covered with the array.by incrementing the pointer location.
And
myFunc(&v);
&v==&&v[0];
&v is address of address of array first element.
Now
void myFunc(int *vp)
Here You got address of address of array first element, This is not pointing to array. Instead pointing some memory location.Now You can't access the array by incrementing the pointer.
Your code is correct It will work....
But you should take extra care to check the boundary condition.
Please look through the code.
void myFunc(int *vp) {
vp[5] = 30;
}
int main() {
int v[5] = {1,2,3,4,5};
int a = 10;
printf("Value of a before fun call %d\n", a);
myFunc(v);
printf("Value of a before fun call %d\n", a);
return 0;
}
similarly
void myFunc(int *vp) {
vp[5] = 30;
myFunc2(vp);
}
void myFunc2(int *vp) {
vp[6] = 30;
}
int main() {
int v[5] = {1,2,3,4,5};
int a = 10;
printf("Value of a before fun call %d\n", a);
myFunc(v);
printf("Value of a before fun call %d\n", a);
return 0;
}
This will result in segmentation fault due to stack curruption. Since local variables are in stack.

Difference between pointer to pointer and pointer to array?

Given that the name of an array is actually a pointer to the first element of an array, the following code:
#include <stdio.h>
int main(void)
{
int a[3] = {0, 1, 2};
int *p;
p = a;
printf("%d\n", p[1]);
return 0;
}
prints 1, as expected.
Now, given that I can create a pointer that points to a pointer, I wrote the following:
#include <stdio.h>
int main(void)
{
int *p0;
int **p1;
int (*p2)[3];
int a[3] = {0, 1, 2};
p0 = a;
p1 = &a;
p2 = &a;
printf("p0[1] = %d\n(*p1)[1] = %d\n(*p2)[1] = %d\n",
p0[1], (*p1)[1], (*p2)[1]);
return 0;
}
I expected it to compile and print
p0[1] = 1
(*p1)[1] = 1
(*p2)[1] = 1
But instead, it goes wrong at compile time, saying:
test.c: In function ‘main’:
test.c:11:5: warning: assignment from incompatible pointer type [enabled by default]
Why is that assignment wrong? If p1 is a pointer to a pointer to an int and a is a pointer to an int (because it's the name of an array of ints), why can't I assign &a to p1?
Line 11 is
p1 = &a;
where p1 has type int ** and a has type int[3], right?
Well; &a has type int(*)[3] and that type is not compatible with int** as the compiler told you
You may want to try
p1 = &p0;
And read the c-faq, particularly section 6.
In short: arrays are not pointers, and pointers are not arrays.
a is not a pointer to int, it decays to such in certain situations. If &a was of type int ** you couldn't very well use it to initialize p2, could you?
You need to do p1 = &p0; for the effect you want. "pointer to pointer" means "at this address, you will find a pointer". But if you look at the address &a, you find an array (obviously), so int ** is not the correct type.
For many operations, a implies &a and both return the same thing: The address of the first item in the array.
You cannot get the address of the pointer because the variable does not store the pointer. a is not a pointer, even though it behaves like one in some cases.

Resources