How do you deference a pointer to an array to get the value stored in it? For example:
void testFunction(int **test){
printf("%d", *test[1]);
}
int main()
{ int test[10];
test[1] = 5;
testFunction(&test);
return 0;
}
I get an error. Anyone could explain?
How do you deference a pointer to an array to get the value stored in it?
You use the * operator, as for every pointer. (Oh, and pay attention to operator precedence!)
void foo(int (*arr)[5])
{
printf("%d\n", (*arr)[0]);
}
int main()
{
int arr[5] = { 0, 1, 2, 3, 4 };
foo(&arr);
return 0;
}
Your code would have generated a diagnostic about an incompatible type being passed to the function. For example, GCC complains:
prog.c: In function 'main':
prog.c:9: warning: passing argument 1 of 'testFunction' from incompatible pointer type
You should pay attention to all diagnostics issued by your compiler, and make sure you understand them, and take the appropriate measures to address them. For this particular one, if you intend to pass in a pointer to an array, you need to write your function to accept such a thing. Then, when you dereference the pointer, you have an array. So, you access it like one.
void testFunction(int (*test)[10]){
printf("%d", (*test)[1]);
}
The [] has higher precedence that *, so the parentheses are required both for the function parameter argument, and for accessing the value in the printf(). When the pointer to int[10] is derferenced, the resulting value is the address of the first element of the array test defined in main. The [] operation then access the 2nd element of the array, and you get the value you expected.
You may be more convinced that your use of int **test is wrong for a pointer to an array if you note that the assertion below will always be true:
int test[10];
assert(&test == (void *)test);
As the compiler warning indicates, a pointer to a pointer to int is not the same as a pointer to an int[10]. The type being pointed to determines the type that results from a dereference.
So:
int test[10] = { [1] = 5 };
testFunction(&test);
This passes the address of test to testFunction. The address of a variable corresponds to its location in memory. This is not so different for an array, but the location in memory for an array variable is the address of its first element. So, the address returned by &test above is the same address returned by test alone.
This gives a disastrous consequence when you treat this pointer value as a pointer to a pointer to int in your testFunction. First, note that you ignore proper operator precedence, so the first dereference is:
test[1]
Since you declare the test parameter to be a pointer to a pointer to int, this increments the address in test by sizeof(int *) and treats the result as an int *. Then, you dereference again:
*test[1]
This now takes the value of test[1] and dereferences it again in an attempt to get an int. However, the address returned by test[1] has no relationship with the array test defined in main, and you are accessing a totally nonsensical memory location.
Even if you paid attention to the precedence with your pointer to pointer to int parameter type, a similar problem would have resulted.
(*test)[1]
Now, the pointer to int[10] is treated as a pointer to pointer to int is derferenced first. This results in the first sizeof(int **) bytes of the test array in main to be treated as a pointer to int. This is already a nonsensical value at this point, but the array dereference now increments this value by sizeof(int) bytes and dereferences that value in an attempt to obtain an int.
The other user gave an example of how it is usually done already, but if you insist on passing an int ** then because of operator precedence the syntax would be like:
void testFunction(int **test){
printf("%d", (*test)[1]);
}
int main()
{ int test[10];
test[1] = 5;
int *testptr= &test[0]; // or int *testptr= test;
testFunction(&testptr); // this passes an int **
return 0;
}
But in c the name of an array is a pointer to the array elements, so int *ptrtest and ptrtest[1] is more commonly used.
Related
I am trying to figure out this program and not understanding the usage of this double asterisk. I know it means a pointer to char but never used it before.
#include<stdio.h>
void fun(int **p);
int main()
{
int a[3][4] = {1, 2, 3, 4, 4, 3, 2, 8, 7, 8, 9, 0};
int *ptr;
ptr = &a[0][0];
fun(&ptr);
return 0;
}
void fun(int **p)
{
printf("%d\n", **p);
}
There are three occurrences of the double asterisk in you original problem, and it’s unclear if you’re talking about a compiler error, a runtime “segfault” error, or the program didn’t throw an error but just didn’t print the results you expected, so there’s ambiguity in your question. But one explanation should clarify all.
The type of ptr is an int pointer (int*), so the type of &ptr becomes int**, which means a pointer to an int pointer.
If your compiler is generating an error when you didn’t use double asterisk in the function’s formal parameter list, thats because the type checking has failed. What you pass in to the function (ie the actual parameter) is &ptr, whose type is obviously int**.
C is a strongly typed language, so the C compiler forbids one to use an int** where int* is expected. But you can do (int*)(ptr) to cast ptr from one type to another.
On the other hand, If you’re using double asterisks in the function formal parameter list, but execute printf(…, *p), it will print the address of the stack variable ptr from function main. It won’t print the value of a[0][0].
To wrap up, the double asterisk has two different semantics depending on the how you use it. When declaring a variable, T **<variable name> means a “second-order pointer to type T”. Yet at other times - when you’re not declaring variables but using them - “**” means dereferencing twice.
Update: what does double dereferencing mean?
In c, every variable has an unique address. “Deference” is the operation of reading a value from an address that is indeterminate at compile time, and that address is in a value only known at run time. This value is called a pointer.
Double asterisk simply means to do the “dereference” operation first on a value, then do the “dereference” operation on the result.
A single * doesn't mean "a pointer to char", it means a pointer to whichever data type it is pointing at. In this case it's pointing to an int. Double asterisk means a pointer to pointer to int.
To dereference a pointer to an int, you'd use
int *p
But in this case, you passed a pointer to a pointer to an int. So to dereference the value, you'd need two levels of indirection. Hence
int **p
Edit 1: What is stored in the ptr variable is the address of a[0][0], so a single level of indirection gives the address of a[0][0], not the value stored at it.
Edit 2: The statement:
&ptr;
is sending the address of ptr variable to the function, which is a different from a[0][0] and has a different memory address.
Let's draw it out:
+------+ +-----------+
- - - -
- ptr - ----> - a[0][0] - ----> 1
- - - -
+------+. +-----------+
A pointer to a pointer to an int.
I have a basic doubt, when we de-reference a pointer to an array why we get name of the array instead the value of first member of an array, I see this has been asked here but I didn't get it
exactly how?
dereferencing pointer to integer array
main()
{
int var[10] = {1,2,3,4,5,6,7,8,9,10};
int (*ptr) [10] = &var;
printf("value = %u %u\n",*ptr,ptr); //both print 2359104. Shouldn't *ptr print 1?
}
So, is it like when we dereference a pointer, it cancel out the reference operator and what we get is variable name, and in case of pointer to an array, it is the array name ?
main()
{
int a = 10;
int *p = &a;
printf("%d\n", *p) /* p = &a; *p = *(&a); and having a dereference cancel out the &, gives us *p = a ? */
}
Because ptr has type int (*)[10] which is a pointer to an array, *ptr has type int[10] which is an array type.
This array decays to a pointer to its first element when it is passed to printf which then prints the pointer value. The result would be the same if you passed var to printf instead of *ptr.
You do not get a variable name when you dereference a pointer. If the pointer points to an object the you get that object. If it does not point to an object then you get undefined behavior. In particular, if the pointer points to a whole array, then you get that array. That's a fundamental aspect of how pointers work.
However, a fundamental aspect of how arrays work is that in most contexts, an expression of array type is automatically converted to a pointer to the first array element. This address corresponds to the address of the array itself, but has different type (int * in your case, as opposed to int (*)[10]). Typically, converting these to an integer type produces the same value. Thus, in your example code, *ptr is equivalent to var, and each is automatically converted to a pointer of type int *, equivalent to &var[0].
But note also that it is not safe to convert pointers to integers by associating them with printf directives, such as %u, that expect a corresponding integer argument. The behavior is undefined, and in practice, surprising or confusing results can sometimes be observed. One prints a pointer value with printf by using a %p directive, and converting the pointer value to type void *. Example:
printf("pointer = %p %p\n", (void *)*ptr, (void *)ptr);
Combined with the type and value of ptr from your example, this can be expected to reliably print two copies of the same hexadecimal number.
I couldn't understand use of (int*) p in following program for pointer to an array
#include<stdio.h>
void main()
{
int s[4][2];
int (*p)[2];
int i,j,*pint;
for(i=0;i<=3;i++)
{
p=&s[i];
pint=(int*)p; /*here*/
printf("\n");
for(j=0;j<=1;j++)
printf("%d",*(pint+j));
}
}
can i use *p instead of (int*) p here. thanks in advance
In your code,
pint=(int*)p;
p is of type int (*)[2], i.e., pointer to an array of 2 ints, and pint is a int *. They are not compatible types, so you need the cast.
If you have an array declaration like this
int s[4][2];
then these three pointers have the same value
int ( *p1 )[4][2] = &s;
int ( *p2 )[2] = &s[0];
int *p3 = &s[0][0];
because all the pointers point to the initial address of the extent of memory allocated for the array.
However the pointers have different types because they point to objects of different types.
The first pointer points to the array in whole as a single object.
the second pointer points to an array element that in turn has the array type int[2].
And the third array point to a scalar object of the type int.
So you may not assign directly one pointer to another because they are incompatible though as it was mentioned they have the same value (address).
You need to cast one pointer type to another pointer type explicitly.
This assignment in the original program
p=&s[i];
assigns the address of each element (array of the type int[2]) to the pointer. In fact it is the address of the first element of the array that is it is equal to &s[i][0]. However the first expression and the last expression have different pointer types.
So you need to use casting in this assignment
pint=(int*)p;
Now using the pointer arithmetic in this expression
*(pint+j)
you can traverse all scalar elements of the array initially pointed to by the pointer p.
Pay attention to that this declaration of main
void main()
is nit a standard declaration.
You should declare the function main like
int main( void )
I wanted to test if I could change the constant pointer that points to the first element of an array in C. While testing I got some strange output that I don't understand:
//Constant pointer to pointer to constant value
void test(int const * * const a) {
//printf("%d", **a); //Program crashes (2)
(*a)++;
}
int main()
{
int a[5] = { 1,2,3,4,5 };
test(&a);
printf("%d", *a); //Prints 5 as output (1)
return 0;
}
I expected the compiler to give an error when I try to compile (*a)++ but instead I can run the code, but when I try to print the element I get a strange value (1).
Then I wanted to print out the value (2) of the first element of the array. When I tried this, the program crashes.
By doing &a you are making a pointer to an array (int (*)[]).
Then when this pointer to array is passed to the test function, it's converted to a pointer to a pointer(int **);
Then (*a)++; is UB.
1. So why 5?
On modern implementation of C like GCC, pointer to a array has the same numerical value as the beginning of the array, so is the address value when the array decays to a pointer: they all are the beginning address of the array.
So, in test, int **a points to the beginning of the array, (*a)++ deferences the pointer as int * and increment the pointer by 1 int element, which is usually implemented as adding the sizeof(int) to the numerical value of the pointer.
Then, 1+sizeof(int) gives you 5.
2. Why it crashed in the second case?
Assuming you are using a 32bit x86 machine, or some machine whose pointer type has the same size as int type, then *a equal to 1. Then further dereferencing the pointer at a memory address at 1 usually gives you a segfault.
The program crashes at the printf because test assumes that when it dereferences a the resulting object is a pointer. If it were one and contained a valid address, the second dereferencing would yield an int object. Alas, a contains the address of the array, which is numerically the address of its first element. The 4 or 8 bytes there are considered an address (because test thinks that *a is a pointer) and the code then tries to access the memory at address 1 in order to print the int value assumed at that address. The address is invalid though, so the program crashes.
Now that we have established that the program considers the data at the beginning of the array a pointer to int, we know what (*a)++ does: it increments the value there by sizeof(int) so that the "pointer" point to the next int "element". I guess an int on your machine is 4 bytes long because 1+4=5, which is printed.
This code is illegal in C, you should get a compiler diagnostic. (If not, turn up your warning level). The results of running any executable produced are meaningless.
The code is illegal because int (*)[5] does not implicitly convert to int const **.
the constant pointer that points to the first element of an array in C
There is no such thing. You misunderstand what arrays are. Arrays are a series of contiguous elements. int a[5] is like int a; except that there are 5 ints instead of 1.
int a; and int a[1]; cause identical memory layout. The only difference is the syntax used to access that memory.
Here is my code snip
#include <stdio.h>
void change(int a[]){
printf("%p\n",&a);
}
int main(){
int b[] = {1,2} ;
printf("%p\n",&b);
change(b);
return 0;
}
I run it and it get the result following
0x7fff5def1c60
0x7fff5def1c38
As we can see the actual parameter address is defferent from the formal parameter address
Then I edited my following
#include <stdio.h>
void change(int a[]){
printf("%p\n",a);
}
int main(){
int b[] = {1,2} ;
printf("%p\n",b);
change(b);
return 0;
}
Then I get the results
0x7fff56501c60
0x7fff56501c60
So it seems that the actual parameter and the formal parameter have the same address.
I am confused that what's the different between &a and a(a is a array),and why I get the different address from the first snippet?
Thanks!
In:
printf("%p\n",&b);
you are printing the address to the first array cell.
In:
change(b);
and specifically in:
void change(int a[]){
printf("%p\n",&a);
}
you are printing the address of the variable a which in itself is a decayed pointer. So it is semantically equivalent to:
void change(int* a){
printf("%p\n",&a);
}
To retrieve the array first cell you would need to write the function as:
void change(int* a){
printf("%p\n", a);
// ^^
}
You can think of a is the starting address of the memory where to store array[1, 2].
Please also think of a is a variable that stores the array address. A variable means itself is somewhere in the memory. So &a is the address of the variable a. All in all, address &a in memory stores the address of the array[1,2].
In your first case, you are passing the address of variable b to function change so that the function variable a stores the address of variable b. But &a is the address of a not the content of a. That's the reason cause the difference.
Because I don't think that the answers so far stress it enough, I'll give another answer:
There is no difference between b and &b, if b is an array. An array is almost like a pointer, but not 100%. A pointer is a variable that stores an address, as you know. So when you create a pointer p, you create a new variable and then assign some address to it. Now the pointer variable p has an address, and it's value is also an address. You can do three things with it:
- Get ps address with &p
- Get ps value with p
- Get ps dereferenced value with *p
With an array ar, it is different. It acts like a pointer, but it is not a distinct variable where an adress is stored! By creating an array, you just allocate the memory for the elements you want to store, but not for a variable that stores the address of these elements. The variable ar just 'stands for' the address of the first element, but it is not saved somewhere in an extra space; the compiler makes sure to translate ar to the memory of the first element - this is important to understand. So what you can do with it is:
- Get ars address with &ar or with ar
- Get ars value with ar[0]
This is the reason why in your change function, int a[] is the same as int *a but in your main function, int b[] is not the same as int *b. The latter allocates memory for an address, while the first just creates memory for a specified amount of elements, and just uses b as a placeholder for the first address of these elements - there is no extra memory allocated for the first element's address, as it would be with a pointer.
This is also the reason why in main, you can't do b = some_pointer, but you can do it in change - because one is a pointer that has memory allocated and thus can change it's value like every other variable, and the other one is just a placeholder for it's first element and thus cannot change it's value.
I hope now it is clear why &b is the same as b - Since b is not a distinct variable with a place in memory, you cannot ask for it's address - it will just give you the address that b stand for anyway.
In main(), b is an array which size if derived from the initialisation, and &b denotes the adress of the array.
In change(), a is an array of unknown size, which as parameter is handled as a pointer. &a is the adress of this pointer.
In the second version of your code, without the & you refer in both case to the value of the pointer.
Here the relevant extracts from the C11 standard:
6.5.3 Unary operators, pt 3: The unary & operator yields the address of its operand.
6.7.6.3 Function declarators, pt 7: A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within
the [ and ] of the array type derivation.
The "&" operator returns the address of a variable and the "%p" construct in printf returns the address of the pointer.
In your example, these calls in main() are equivalent:
printf("%p\n",b);
printf("%p\n",&b);
Both return the memory position of b, which is 0x7fff56501c60 in your example
When you define a function, you introduce a local variable a:
void change(int a[]){
This is a pointer (equivalent to int * a) and has its own memory address.
When you call this inside the function:
printf("%p\n",a);
you get the same as above: The address of b: The value of pointer b is copied to a and printf tells you where it points at.
However if you do this:
printf("%p\n",&a);
Then you get the address of the local variable a, which is distinct to b. It does not matter what is inside a and in your example the value of b is not even used by function "change", you could also run this:
#include <stdio.h>
void change(int a[]){
printf("%p\n",&a);
}
int main(){
int b[] = {1,2} ;
printf("%p\n",&b);
change((int *)0);
return 0;
}
This runs "change" with a Nullpointer and it is still equivalent to your first example: "change" just prints out the address of the local variable a, regardless of contents.