Is an array's name a pointer in C?
If not, what is the difference between an array's name and a pointer variable?
An array is an array and a pointer is a pointer, but in most cases array names are converted to pointers. A term often used is that they decay to pointers.
Here is an array:
int a[7];
a contains space for seven integers, and you can put a value in one of them with an assignment, like this:
a[3] = 9;
Here is a pointer:
int *p;
p doesn't contain any spaces for integers, but it can point to a space for an integer. We can, for example, set it to point to one of the places in the array a, such as the first one:
p = &a[0];
What can be confusing is that you can also write this:
p = a;
This does not copy the contents of the array a into the pointer p (whatever that would mean). Instead, the array name a is converted to a pointer to its first element. So that assignment does the same as the previous one.
Now you can use p in a similar way to an array:
p[3] = 17;
The reason that this works is that the array dereferencing operator in C, [ ], is defined in terms of pointers. x[y] means: start with the pointer x, step y elements forward after what the pointer points to, and then take whatever is there. Using pointer arithmetic syntax, x[y] can also be written as *(x+y).
For this to work with a normal array, such as our a, the name a in a[3] must first be converted to a pointer (to the first element in a). Then we step 3 elements forward, and take whatever is there. In other words: take the element at position 3 in the array. (Which is the fourth element in the array, since the first one is numbered 0.)
So, in summary, array names in a C program are (in most cases) converted to pointers. One exception is when we use the sizeof operator on an array. If a was converted to a pointer in this context, sizeof a would give the size of a pointer and not of the actual array, which would be rather useless, so in that case a means the array itself.
When an array is used as a value, its name represents the address of the first element.
When an array is not used as a value its name represents the whole array.
int arr[7];
/* arr used as value */
foo(arr);
int x = *(arr + 1); /* same as arr[1] */
/* arr not used as value */
size_t bytes = sizeof arr;
void *q = &arr; /* void pointers are compatible with pointers to any object */
If an expression of array type (such as the array name) appears in a larger expression and it isn't the operand of either the & or sizeof operators, then the type of the array expression is converted from "N-element array of T" to "pointer to T", and the value of the expression is the address of the first element in the array.
In short, the array name is not a pointer, but in most contexts it is treated as though it were a pointer.
Edit
Answering the question in the comment:
If I use sizeof, do i count the size of only the elements of the array? Then the array “head” also takes up space with the information about length and a pointer (and this means that it takes more space, than a normal pointer would)?
When you create an array, the only space that's allocated is the space for the elements themselves; no storage is materialized for a separate pointer or any metadata. Given
char a[10];
what you get in memory is
+---+
a: | | a[0]
+---+
| | a[1]
+---+
| | a[2]
+---+
...
+---+
| | a[9]
+---+
The expression a refers to the entire array, but there's no object a separate from the array elements themselves. Thus, sizeof a gives you the size (in bytes) of the entire array. The expression &a gives you the address of the array, which is the same as the address of the first element. The difference between &a and &a[0] is the type of the result1 - char (*)[10] in the first case and char * in the second.
Where things get weird is when you want to access individual elements - the expression a[i] is defined as the result of *(a + i) - given an address value a, offset i elements (not bytes) from that address and dereference the result.
The problem is that a isn't a pointer or an address - it's the entire array object. Thus, the rule in C that whenever the compiler sees an expression of array type (such as a, which has type char [10]) and that expression isn't the operand of the sizeof or unary & operators, the type of that expression is converted ("decays") to a pointer type (char *), and the value of the expression is the address of the first element of the array. Therefore, the expression a has the same type and value as the expression &a[0] (and by extension, the expression *a has the same type and value as the expression a[0]).
C was derived from an earlier language called B, and in B a was a separate pointer object from the array elements a[0], a[1], etc. Ritchie wanted to keep B's array semantics, but he didn't want to mess with storing the separate pointer object. So he got rid of it. Instead, the compiler will convert array expressions to pointer expressions during translation as necessary.
Remember that I said arrays don't store any metadata about their size. As soon as that array expression "decays" to a pointer, all you have is a pointer to a single element. That element may be the first of a sequence of elements, or it may be a single object. There's no way to know based on the pointer itself.
When you pass an array expression to a function, all the function receives is a pointer to the first element - it has no idea how big the array is (this is why the gets function was such a menace and was eventually removed from the library). For the function to know how many elements the array has, you must either use a sentinel value (such as the 0 terminator in C strings) or you must pass the number of elements as a separate parameter.
Which *may* affect how the address value is interpreted - depends on the machine.
An array declared like this
int a[10];
allocates memory for 10 ints. You can't modify a but you can do pointer arithmetic with a.
A pointer like this allocates memory for just the pointer p:
int *p;
It doesn't allocate any ints. You can modify it:
p = a;
and use array subscripts as you can with a:
p[2] = 5;
a[2] = 5; // same
*(p+2) = 5; // same effect
*(a+2) = 5; // same effect
The array name by itself yields a memory location, so you can treat the array name like a pointer:
int a[7];
a[0] = 1976;
a[1] = 1984;
printf("memory location of a: %p", a);
printf("value at memory location %p is %d", a, *a);
And other nifty stuff you can do to pointer (e.g. adding/substracting an offset), you can also do to an array:
printf("value at memory location %p is %d", a + 1, *(a + 1));
Language-wise, if C didn't expose the array as just some sort of "pointer"(pedantically it's just a memory location. It cannot point to arbitrary location in memory, nor can be controlled by the programmer). We always need to code this:
printf("value at memory location %p is %d", &a[1], a[1]);
I think this example sheds some light on the issue:
#include <stdio.h>
int main()
{
int a[3] = {9, 10, 11};
int **b = &a;
printf("a == &a: %d\n", a == b);
return 0;
}
It compiles fine (with 2 warnings) in gcc 4.9.2, and prints the following:
a == &a: 1
oops :-)
So, the conclusion is no, the array is not a pointer, it is not stored in memory (not even read-only one) as a pointer, even though it looks like it is, since you can obtain its address with the & operator. But - oops - that operator does not work :-)), either way, you've been warned:
p.c: In function ‘main’:
pp.c:6:12: warning: initialization from incompatible pointer type
int **b = &a;
^
p.c:8:28: warning: comparison of distinct pointer types lacks a cast
printf("a == &a: %d\n", a == b);
C++ refuses any such attempts with errors in compile-time.
Edit:
This is what I meant to demonstrate:
#include <stdio.h>
int main()
{
int a[3] = {9, 10, 11};
void *c = a;
void *b = &a;
void *d = &c;
printf("a == &a: %d\n", a == b);
printf("c == &c: %d\n", c == d);
return 0;
}
Even though c and a "point" to the same memory, you can obtain address of the c pointer, but you cannot obtain the address of the a pointer.
The following example provides a concrete difference between an array name and a pointer. Let say that you want to represent a 1D line with some given maximum dimension, you could do it either with an array or a pointer:
typedef struct {
int length;
int line_as_array[1000];
int* line_as_pointer;
} Line;
Now let's look at the behavior of the following code:
void do_something_with_line(Line line) {
line.line_as_pointer[0] = 0;
line.line_as_array[0] = 0;
}
void main() {
Line my_line;
my_line.length = 20;
my_line.line_as_pointer = (int*) calloc(my_line.length, sizeof(int));
my_line.line_as_pointer[0] = 10;
my_line.line_as_array[0] = 10;
do_something_with_line(my_line);
printf("%d %d\n", my_line.line_as_pointer[0], my_line.line_as_array[0]);
};
This code will output:
0 10
That is because in the function call to do_something_with_line the object was copied so:
The pointer line_as_pointer still contains the same address it was pointing to
The array line_as_array was copied to a new address which does not outlive the scope of the function
So while arrays are not given by values when you directly input them to functions, when you encapsulate them in structs they are given by value (i.e. copied) which outlines here a major difference in behavior compared to the implementation using pointers.
NO. An array name is NOT a pointer. You cannot assign to or modify an array name, but you can for a pointer.
int arr[5];
int *ptr;
/* CAN assign or increment ptr */
ptr = arr;
ptr++;
/* CANNOT assign or increment arr */
arr = ptr;
arr++;
/* These assignments are also illegal */
arr = anotherarray;
arr = 0;
From K&R Book:
There is one difference between an array name and a pointer that must
be kept in mind. A pointer is a variable, but an array name is not a
variable.
sizeof is the other big difference.
sizeof(arr); /* size of the entire array */
sizeof(ptr); /* size of the memory address */
Arrays do behave like or decay into a pointer in some situations (&arr[0]). You can see other answers for more examples of this. To reiterate a few of these cases:
void func(int *arr) { }
void func2(int arr[]) { } /* same as func */
ptr = arr + 1; /* pointer arithmetic */
func(arr); /* passing to function */
Even though you cannot assign or modify the array name, of course can modify the contents of the array
arr[0] = 1;
The array name behaves like a pointer and points to the first element of the array. Example:
int a[]={1,2,3};
printf("%p\n",a); //result is similar to 0x7fff6fe40bc0
printf("%p\n",&a[0]); //result is similar to 0x7fff6fe40bc0
Both the print statements will give exactly same output for a machine. In my system it gave:
0x7fff6fe40bc0
Related
Is an array's name a pointer in C?
If not, what is the difference between an array's name and a pointer variable?
An array is an array and a pointer is a pointer, but in most cases array names are converted to pointers. A term often used is that they decay to pointers.
Here is an array:
int a[7];
a contains space for seven integers, and you can put a value in one of them with an assignment, like this:
a[3] = 9;
Here is a pointer:
int *p;
p doesn't contain any spaces for integers, but it can point to a space for an integer. We can, for example, set it to point to one of the places in the array a, such as the first one:
p = &a[0];
What can be confusing is that you can also write this:
p = a;
This does not copy the contents of the array a into the pointer p (whatever that would mean). Instead, the array name a is converted to a pointer to its first element. So that assignment does the same as the previous one.
Now you can use p in a similar way to an array:
p[3] = 17;
The reason that this works is that the array dereferencing operator in C, [ ], is defined in terms of pointers. x[y] means: start with the pointer x, step y elements forward after what the pointer points to, and then take whatever is there. Using pointer arithmetic syntax, x[y] can also be written as *(x+y).
For this to work with a normal array, such as our a, the name a in a[3] must first be converted to a pointer (to the first element in a). Then we step 3 elements forward, and take whatever is there. In other words: take the element at position 3 in the array. (Which is the fourth element in the array, since the first one is numbered 0.)
So, in summary, array names in a C program are (in most cases) converted to pointers. One exception is when we use the sizeof operator on an array. If a was converted to a pointer in this context, sizeof a would give the size of a pointer and not of the actual array, which would be rather useless, so in that case a means the array itself.
When an array is used as a value, its name represents the address of the first element.
When an array is not used as a value its name represents the whole array.
int arr[7];
/* arr used as value */
foo(arr);
int x = *(arr + 1); /* same as arr[1] */
/* arr not used as value */
size_t bytes = sizeof arr;
void *q = &arr; /* void pointers are compatible with pointers to any object */
If an expression of array type (such as the array name) appears in a larger expression and it isn't the operand of either the & or sizeof operators, then the type of the array expression is converted from "N-element array of T" to "pointer to T", and the value of the expression is the address of the first element in the array.
In short, the array name is not a pointer, but in most contexts it is treated as though it were a pointer.
Edit
Answering the question in the comment:
If I use sizeof, do i count the size of only the elements of the array? Then the array “head” also takes up space with the information about length and a pointer (and this means that it takes more space, than a normal pointer would)?
When you create an array, the only space that's allocated is the space for the elements themselves; no storage is materialized for a separate pointer or any metadata. Given
char a[10];
what you get in memory is
+---+
a: | | a[0]
+---+
| | a[1]
+---+
| | a[2]
+---+
...
+---+
| | a[9]
+---+
The expression a refers to the entire array, but there's no object a separate from the array elements themselves. Thus, sizeof a gives you the size (in bytes) of the entire array. The expression &a gives you the address of the array, which is the same as the address of the first element. The difference between &a and &a[0] is the type of the result1 - char (*)[10] in the first case and char * in the second.
Where things get weird is when you want to access individual elements - the expression a[i] is defined as the result of *(a + i) - given an address value a, offset i elements (not bytes) from that address and dereference the result.
The problem is that a isn't a pointer or an address - it's the entire array object. Thus, the rule in C that whenever the compiler sees an expression of array type (such as a, which has type char [10]) and that expression isn't the operand of the sizeof or unary & operators, the type of that expression is converted ("decays") to a pointer type (char *), and the value of the expression is the address of the first element of the array. Therefore, the expression a has the same type and value as the expression &a[0] (and by extension, the expression *a has the same type and value as the expression a[0]).
C was derived from an earlier language called B, and in B a was a separate pointer object from the array elements a[0], a[1], etc. Ritchie wanted to keep B's array semantics, but he didn't want to mess with storing the separate pointer object. So he got rid of it. Instead, the compiler will convert array expressions to pointer expressions during translation as necessary.
Remember that I said arrays don't store any metadata about their size. As soon as that array expression "decays" to a pointer, all you have is a pointer to a single element. That element may be the first of a sequence of elements, or it may be a single object. There's no way to know based on the pointer itself.
When you pass an array expression to a function, all the function receives is a pointer to the first element - it has no idea how big the array is (this is why the gets function was such a menace and was eventually removed from the library). For the function to know how many elements the array has, you must either use a sentinel value (such as the 0 terminator in C strings) or you must pass the number of elements as a separate parameter.
Which *may* affect how the address value is interpreted - depends on the machine.
An array declared like this
int a[10];
allocates memory for 10 ints. You can't modify a but you can do pointer arithmetic with a.
A pointer like this allocates memory for just the pointer p:
int *p;
It doesn't allocate any ints. You can modify it:
p = a;
and use array subscripts as you can with a:
p[2] = 5;
a[2] = 5; // same
*(p+2) = 5; // same effect
*(a+2) = 5; // same effect
The array name by itself yields a memory location, so you can treat the array name like a pointer:
int a[7];
a[0] = 1976;
a[1] = 1984;
printf("memory location of a: %p", a);
printf("value at memory location %p is %d", a, *a);
And other nifty stuff you can do to pointer (e.g. adding/substracting an offset), you can also do to an array:
printf("value at memory location %p is %d", a + 1, *(a + 1));
Language-wise, if C didn't expose the array as just some sort of "pointer"(pedantically it's just a memory location. It cannot point to arbitrary location in memory, nor can be controlled by the programmer). We always need to code this:
printf("value at memory location %p is %d", &a[1], a[1]);
I think this example sheds some light on the issue:
#include <stdio.h>
int main()
{
int a[3] = {9, 10, 11};
int **b = &a;
printf("a == &a: %d\n", a == b);
return 0;
}
It compiles fine (with 2 warnings) in gcc 4.9.2, and prints the following:
a == &a: 1
oops :-)
So, the conclusion is no, the array is not a pointer, it is not stored in memory (not even read-only one) as a pointer, even though it looks like it is, since you can obtain its address with the & operator. But - oops - that operator does not work :-)), either way, you've been warned:
p.c: In function ‘main’:
pp.c:6:12: warning: initialization from incompatible pointer type
int **b = &a;
^
p.c:8:28: warning: comparison of distinct pointer types lacks a cast
printf("a == &a: %d\n", a == b);
C++ refuses any such attempts with errors in compile-time.
Edit:
This is what I meant to demonstrate:
#include <stdio.h>
int main()
{
int a[3] = {9, 10, 11};
void *c = a;
void *b = &a;
void *d = &c;
printf("a == &a: %d\n", a == b);
printf("c == &c: %d\n", c == d);
return 0;
}
Even though c and a "point" to the same memory, you can obtain address of the c pointer, but you cannot obtain the address of the a pointer.
The following example provides a concrete difference between an array name and a pointer. Let say that you want to represent a 1D line with some given maximum dimension, you could do it either with an array or a pointer:
typedef struct {
int length;
int line_as_array[1000];
int* line_as_pointer;
} Line;
Now let's look at the behavior of the following code:
void do_something_with_line(Line line) {
line.line_as_pointer[0] = 0;
line.line_as_array[0] = 0;
}
void main() {
Line my_line;
my_line.length = 20;
my_line.line_as_pointer = (int*) calloc(my_line.length, sizeof(int));
my_line.line_as_pointer[0] = 10;
my_line.line_as_array[0] = 10;
do_something_with_line(my_line);
printf("%d %d\n", my_line.line_as_pointer[0], my_line.line_as_array[0]);
};
This code will output:
0 10
That is because in the function call to do_something_with_line the object was copied so:
The pointer line_as_pointer still contains the same address it was pointing to
The array line_as_array was copied to a new address which does not outlive the scope of the function
So while arrays are not given by values when you directly input them to functions, when you encapsulate them in structs they are given by value (i.e. copied) which outlines here a major difference in behavior compared to the implementation using pointers.
The array name behaves like a pointer and points to the first element of the array. Example:
int a[]={1,2,3};
printf("%p\n",a); //result is similar to 0x7fff6fe40bc0
printf("%p\n",&a[0]); //result is similar to 0x7fff6fe40bc0
Both the print statements will give exactly same output for a machine. In my system it gave:
0x7fff6fe40bc0
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
As I'm learning C I often see pointers.
I get that a pointer is holding the hexadecimal value of a distinct location in memory. So a pointer is nothing other than e.g.:0x7fff5fbff85c
Every pointer is also of a distinct type.
int var = 10;
int *ptr = &var;
Ptr here points to the location of var. To get the value of var I have to dereference the pointer with *ptr.
Like
printf("Var = %d", *ptr);
would print `Var = 10;
However If I do a non inline declaration of a pointer like:
int var = 10;
int *ptr;
ptr = &var;
I don't have to use the * in the third line when I'm actually assigning the memory adress to the pointer.
But when I got a function that takes a pointer:
int var = 10;
void assignPointer(int *ptr) {
*ptr = 10;
}
Oh, wait! As I'm writing this I recognized that there are two different assignments for pointers:
*ptr = 10;
and
ptr = &var;
What is the difference? Am I in the first case first dereferencing the pointer, assigning 10 to the location that its holding?
And in the second case I'am assigning the actual location to the pointer.
I'm a little bit confused when to use the * and when not to in terms of assignment.
And if I'm working with arrays, why do I need pointers at all?
int array[];
"array" here is already holding the hexadecimal memory location. Doesn't that make it a pointer? So If I wanted to assign something to array wouldn't I write:
*array = [10, 2];
First I'm dereferencing, then I'm assigning.
I'm lost :(
EDIT: Maybe it's a bit unclear.
I don't know when you have to use a * when you are working with pointers an when not.
Everything that is carrying a hexadecimal is a pointer right?
The variable name of an array is carrying it's hexadecimal memory location. So why isn't it a pointer?
EDIT2: Thank you people you helped me a lot!
I don't know when you have to use a * when you are working with pointers an when not. Everything that is carrying a hexadecimal is a pointer right? The variable name of an array is carrying it's hexadecimal memory location. So why isn't it a pointer?
Last thing first - the name of an array is not a pointer; it does not store an address anywhere. When you define an array, it will be laid out more or less like the following:
+---+
arr: | | arr[0] Increasing address
+---+ |
| | arr[1] |
+---+ |
... |
+---+ |
| | arr[n-1] V
+---+
There is no storage set aside for an object arr separate from the array elements arr[0] through arr[n-1]. C does not store any metadata such as length or starting address as part of the array object.
Instead, there is a rule that says if an array expression appears in your code and that expression is not the operand of the sizeof or unary & operators, it will be converted ("decay") to a pointer expression, and the value of the pointer expression will be the address of the first element of the array.
So given the declaration
T arr[N]; // for any type T
then the following are true:
Expression Type Decays to Value
---------- ---- --------- -----
arr T [N] T * Address of first element
&arr T (*)[N] n/a Address of array (same value
as above
*arr T n/a Value of arr[0]
arr[i] T n/a Value of i'th element
&arr[i] T * n/a Address of i'th element
sizeof arr size_t Number of storage units (bytes)
taken up by arr
The expressions arr, &arr, and &arr[0] all yield the same value (the address of the first element of the array is the same as the address of the array), but their types aren't all the same; arr and &arr[0] have type T *, while &arr has type T (*)[N] (pointer to N-element array of T).
Everything that is carrying a hexadecimal is a pointer right?
Hexadecimal is just a particular representation of binary data; it's not a type in and of itself. And not everything that can be written or displayed in hex is a pointer. I can assign the value 0xDEADBEEF to any 32-bit integer type; that doesn't make it a pointer.
The exact representation of a pointer can vary between architectures; it can even vary between different pointer types on the same architecture. For a flat memory model (like any modern desktop architecture) it will be a simple integral value. For a segmented architecture (like the old 8086/DOS days) it could be a pair of values for page # and offset.
A pointer value may not be as wide as the type used to store it. For example, the old Motorola 68000 only had 24 address lines, so any pointer value would only be 24 bits wide. However, to make life easier, most compilers used 32-bit types to represent pointers, leaving the upper 8 bits unused (powers of 2 are convenient).
I don't know when you have to use a * when you are working with pointers an when not.
Pretty simple - when you want to refer to the pointed-to entity, use the *; when you want to refer to the pointer itself, leave it off.
Another way to look at it - the expression *ptr is equivalent to the expression var, so any time you want to refer to the contents of var you would use *ptr.
A more concrete example might help. Assume the following:
void bar( T *p )
{
*p = new_value(); // write new value to *p
}
void foo( void )
{
T var;
bar( &var ); // write a new value to var
}
In the example above, the following are true:
p == &var
*p == var
If I write something to *p, I'm actually updating var. If I write something to p, I'm setting it to point to something other than var.
This code above is actually the primary reason why pointers exist in the first place. In C, all function arguments are passed by value; that is, the formal parameter in the function definition is a separate object from the actual parameter in the function call. Any updates to the formal parameter are not reflected in the actual parameter. If we change the code as follows:
void bar( T p )
{
p = new_value(); // write new value to p
}
void foo( void )
{
T var;
bar( var ); // var is not updated
}
The value of p is changed, but since p is a different object in memory from var, the value in var remains unchanged. The only way for a function to update the actual parameter is through a pointer.
So, if you want to update the thing p points to, write to *p. If you want to set p to point to a different object, write to p:
int x = 0, y = 1;
int *p = &x; // p initially points to x
printf( "&x = %p, x = %d, p = %p, *p = %d\n", (void *) &x, x, (void *) p, *p );
*p = 3;
printf( "&x = %p, x = %d, p = %p, *p = %d\n", (void *) &x, x, (void *) p, *p );
p = y; // set p to point to y
printf( "&y = %p, y = %d, p = %p, *p = %d\n", (void *) &y, y, (void *) p, *p );
At this point you're probably asking, "why do I use the asterisk in int *p = &x and not in p = y?" In the first case, we're declaring p as a pointer and initializing it in the same operation, and the * is required by the declaration syntax. In that case, we're writing to p, not *p. It would be equivalent to writing
int *p;
p = &x;
Also note that in a declaration the * is bound to the variable name, not the type specifier; it's parsed as int (*p);.
C declarations are based on the types of expressions, not objects. If p is a pointer to an int, and we want to refer to the pointed-to value, we use the * operator to dereference it, like so:
x = *p;
The type of the expression *p is int, so the declaration is written as
int *p;
C syntax is weird like this. When you declare a variable, the * is only there to indicate the pointer type. It does not actually dereference anything. Thus,
int *foo = &bar;
is as if you wrote
int *foo;
foo = &bar;
Pointers are declared similar to regular variables.The asterisk character precede the name of the pointer during declaration to distinguish it as a pointer.At declaration you are not de-referencing,e.g.:
int a = 0;
int *p = &a // here the pointer of type int is declared and assigned the address of the variable a
After the declaration statement,to assign the pointer an address or value,you use it's name without the asterisk character,e.g:
int a;
int *p;
p = &a;
To assign the target of the pointer a value,you dereference it by preceding the pointer name with *:
int a = 0;
int *p;
p = &a;
*p = 1;
Dereferenced pointer is the memory it points to. Just don't confuse declaring the pointer and using it.
It may be a bit easier to understand if you write * in declaration near the type:
int* p;
In
int some_int = 10;
int* p = &some_int; // the same as int *p; p = &some_int;
*p = 20; // actually does some_int = 20;
You are pretty much correct.
Am I in the first case first dereferencing the pointer, assigning 10 to the location that its holding? And in the second case I'am assigning the actual location to the pointer.
Exactly. These are two logically different actions as you see.
"array" here is already holding the hexadecimal memory location. Doesn't that make it a pointer?
And you got the grasp of it as well here. For the sake of your understanding I would say that arrays are pointers. However in reality it is not that simple -- arrays only decay into pointers in most circumstances. If you are really into that matter, you can find a couple of great posts here.
But, since it is only a pointer, you can't "assign to array". How to handle an array in pointer context is usually explained in a pretty good way in any C book under the "Strings" section.
You are right about the difference between assignment and dereferencing.
What you need to understand is that your array variable is a pointer to the first element of your continuous memory zone
So you can access the first element by dereferencing the pointer :
*array = 10;
You can access the nth element by dereferencing a pointer to the nth element :
*(array + (n * sizeof(my_array_type)) ) = 10;
Where the address is the pointer to the first element plus the offset to the nth element (computed using the size of an element in this array times n).
You can also use the equivalent syntax the access the nth element :
array[n] = 10;
One of your examples isn't valid. *ptr = 10;. The reason is that 10 is a value but there is no memory assigned to it.
You can think of your examples as "assigning something to point at the address" or "the address of something is". So,
int *ptr is a pointer to the address of something. So ptr = &val; means ptr equals the address of val. Then you can say *ptr = 10; or val = 10; cause both *ptr and val are looking at the same memory location and, therefore, the same value. (Note I didn't say "pointing").
This question already has answers here:
Pointer to pointer clarification
(16 answers)
How do pointer-to-pointers work in C? (and when might you use them?)
(14 answers)
Closed 7 years ago.
I'm new to C with a good background in java and I'm trying to understand pointers and arrays.
I know that subscript operator[] is part of an array definition, so:
int numbers[] = {1,3,4,5};
would create a integer array, which would be represented in memory as 16 bytes, 4 lots of 4 bytes:
numbers[0] = 1, address 0061FF1C
numbers[1] = 3, address 0061FF20
numbers[2] = 4, address 0061FF24
numbers[3] = 5, address 0061FF28
However, when it comes to pointers my knowledge starts to break down, so if I was to create a pointer to the array numbers I would do the following:
int *pNumbers = &numbers[0];
which would look something like this:
And I'm guessing it would be of size 4 bytes?
However the ** I read as "pointer to a pointer" which makes no sense to me, why would anyone want a pointer to a pointer, surely if a->b->c then a->c would suffice? I know I'm missing something, and it must have something to do with arrays as argv can be of type char[ ] or char ** as seen bellow:
int main(int argc, char **argv){}
So:
what is this (**)?
what use does it have?
how is it represented in memory?
In C arguments are passed by values. For example if you have an integer varaible in main
int main( void )
{
int x = 10;
//...
and the following function
void f( int x )
{
x = 20;
printf( "x = %d\n", x );
}
then if you call the function in main like this
f( x );
then the parameter gets the value of variable x in main. However the parameter itself occupies a different extent in memory than the argument. So any changes of the parameter in the function do not influence to the original variable in main because these changes occur in different memory extent.
So how to change the varible in main in the function?
You need to pass a reference to the variable using pointers.
In this case the function declaration will look like
void f( int *px );
and the function definition will be
void f( int *px )
{
*px = 20;
printf( "*px = %d\n", *px );
}
In this case it is the memory extent occupied by the original variable x is changed because within the function we get access to this extent using the pointer
*px = 20;
Naturally the function must be called in main like
f( &x );
Take into account that the parameter itself that is the pointer px is as usual a local variable of the function. That is the function creates this variable and initializes it with the address of variable x.
Now let's assume that in main you declared a pointer for example the following way
int main( void )
{
int *px = malloc( sizeof( int ) );
//..
And the function defined like
void f( int *px )
{
px = malloc( sizeof( int ) );
printf( "px = %p\n", px );
}
As parameter px is a local variable assigning to it any value does not influence to the original pointer. The function changes a different extent of memory than the extent occupied by the original pointer px in main.
How to change the original pointer in the function?
Just pass it by reference!
For example
f( &px );
//...
void f( int **px )
{
*px = malloc( sizeof( int ) );
printf( "*px = %p\n", *px );
}
In this case the value stored in the original pointer will be changed within the function because the function using dereferencing access the same memory extent where the original pointer was defined.
Q: what is this (**)?
A: Yes, it's exactly that. A pointer to a
pointer.
Q: what use does it have?
A: It has a number of uses. Particularly in representing 2 dimensional data (images, etc). In the case of your example char** argv can be thought of as an array of an array of chars. In this case each char* points to the beginning of a string. You could actually declare this data yourself explicitly like so.
char* myStrings[] = {
"Hello",
"World"
};
char** argv = myStrings;
// argv[0] -> "Hello"
// argv[1] -> "World"
When you access a pointer like an array the number that you index it with and the size of the element itself are used to offset to the address of the next element in the array. You could also access all of your numbers like so, and in fact this is basically what C is doing. Keep in mind, the compiler knows how many bytes a type like int uses at compile time. So it knows how big each step should be to the next element.
*(numbers + 0) = 1, address 0x0061FF1C
*(numbers + 1) = 3, address 0x0061FF20
*(numbers + 2) = 4, address 0x0061FF24
*(numbers + 3) = 5, address 0x0061FF28
The * operator is called the dereference operator. It is used to retrieve the value from memory that is pointed to by a pointer. numbers is literally just a pointer to the first element in your array.
In the case of my example myStrings could look something like this assuming that a pointer/address is 4 bytes, meaning we are on a 32 bit machine.
myStrings = 0x0061FF14
// these are just 4 byte addresses
(myStrings + 0) -> 0x0061FF14 // 0 bytes from beginning of myStrings
(myStrings + 1) -> 0x0061FF18 // 4 bytes from beginning of myStrings
myStrings[0] -> 0x0061FF1C // de-references myStrings # 0 returning the address that points to the beginning of 'Hello'
myStrings[1] -> 0x0061FF21 // de-references myStrings # 1 returning the address that points to the beginning of 'World'
// The address of each letter is 1 char, or 1 byte apart
myStrings[0] + 0 -> 0x0061FF1C which means... *(myStrings[0] + 0) = 'H'
myStrings[0] + 1 -> 0x0061FF1D which means... *(myStrings[0] + 1) = 'e'
myStrings[0] + 2 -> 0x0061FF1E which means... *(myStrings[0] + 2) = 'l'
myStrings[0] + 3 -> 0x0061FF1F which means... *(myStrings[0] + 3) = 'l'
myStrings[0] + 4 -> 0x0061FF20 which means... *(myStrings[0] + 4) = 'o'
The traditional way to write the argv argument is char *argv[] which gives more information about what it is, an array of pointers to characters (i.e. an array of strings).
However, when passing an array to a function it decays to a pointer, leaving you with a pointer to pointer to char, or char **.
Of course, double asterisks can also be used when dereferencing a pointer to a pointer, so without the added context at the end of the question there are two answers to the question what ** means in C, depending on context.
To continue with the argv example, one way to get the first character of the first element in argv would be to do argv[0][0], or you could use the dereference operator twice, as in **argv.
Array indexing and dereferencing is interchangeable in most places, because for any pointer or array p and index i the expression p[i] is equivalent to *(p + i). And if i is 0 then we have *(p + 0) which can be shortened to *(p) which is the same as *p.
As a curiosity, because p[i] is equivalent to *(p + i) and the commutative property of addition, the expression *(p + i) is equal to *(i + p) which leads to p[i] being equal to i[p].
Finally a warning about excessive use of pointers, you might sometime hear the phrase three-star programmer, which is when one uses three asterisks like in *** (like in a pointer to a pointer to a pointer). But to quote from the link
Just to be clear: Being called a ThreeStarProgrammer is usually not a compliment
And another warning: An array of arrays is not the same as a pointer to a pointer (Link to an old answer of mine, which also shows the memory layout of a pointer to a pointer as a substitute of an array of arrays.)
** in declaration represents pointer to pointer. Pointer is itself a data type and like other data types it can have a pointer.
int i = 5, j = 6; k = 7;
int *ip1 = &i, *ip2 = &j;
int **ipp = &ip1;
Pointer to pointer are useful in case of allocating dynamic 2D array. To allocate a 10x10 2D array (may not be contiguous)
int **m = malloc(sizeof(int *)*10;
for(int i = 0; i < 10; i++)
m[i] = malloc(sizeof(int)*10
It is also used when you want to change the value of a pointer through a function.
void func (int **p, int n)
{
*p = malloc(sizeof(int)*n); // Allocate an array of 10 elements
}
int main(void)
{
int *ptr = NULL;
int n = 10;
func(&ptr, n);
if(ptr)
{
for(int i = 0; i < n; i++)
{
ptr[i] = ++i;
}
}
free(ptr);
}
Further reading: Pointer to Pointer.
** represents a pointer to a pointer. If you want to pass a parameter by reference, you would use *, but if you want to pass the pointer itself by reference, then you need a pointer to the pointer, hence **.
** stands for pointer to pointer as you know the name. I will explain each of your question:
what is this (**)?
Pointer to Pointer. Sometime people call double pointer. For example:
int a = 3;
int* b = &a; // b is pointer. stored address of a
int**b = &b; // c is pointer to pointer. stored address of b
int***d = &c; // d is pointer to pointer to pointer. stored address of d. You get it.
how is it represented in memory?
c in above example is just a normal variable and has same representation as other variables (pointer, int ...). Memory size of variable c same as b and it depends on platform. For example, 32-bit computer, each variable address includes 32bit so size will be 4 bytes (8x4=32 bit) On 64-bit computer, each variable address will be 64bit so size will be 8 bytes (8x8=64 bit).
what use does it have?
There are many usages for pointer to pointer, depends on your situation. For example, here is one example I learned in my algorithm class. You have a linked list. Now, you want to write a method to change that linked list, and your method may changed head of linked list. (Example: remove one element with value equals to 5, remove head element, swap, ...). So you have two cases:
1. If you just pass a pointer of head element. Maybe that head element will be removed, and this pointer doesn't valid anymore.
2. If you pass pointer of pointer of head element. In case your head element is removed, you meet no problem because the pointer of pointer still there. It just change values of another head node.
You can reference here for above example: pointer to pointer in linked list
Another usage is using in two-dimensional array. C is different from Java. Two dimensional array in C, in fact just a continuous memory block. Two dimensional array in Java is multi memory block (depend on your row of matrix)
Hope this help :)
Consider if you have a table of pointers - such as a table of strings (since strings in "C" are handled simply as pointers to the first character of the string).
Then you need a pointer to the first pointer in the table. Hence the "char **".
If you have an inline table with all the values, like a two-dimensional table of integers, then it's entirely possible to get away with only one level of indirection (i.e. just a simple pointer, like "int *"). But when there is a pointer in the middle that needs to be dereferenced to get to the end result, that creates a second level of indirection, and then the pointer-to-pointer is essential.
Another clarification here. In "C", dereferencing via pointer notation (e.g. "*ptr") vs array index notation (e.g. ptr[0]) has little difference, other than the obvious index value in array notation. The only time asterisk vs brackets really matters is when allocating a variable (e.g. int *x; is very different than int x[1]).
Of your int * example you say
And I'm guessing it would be of size 4 bytes?
Unlike Java, C does not specify the exact sizes of its data types. Different implementations can and do use different sizes (but each implementation must be consistent). 4-byte ints are common these days, but ints can be as small two bytes, and nothing inherently limits them to four. The size of pointers is even less specified, but it usually depends on the hardware architecture at which the C implementation is targeted. The most common pointer sizes are four bytes (typical for 32-bit architectures) and eight bytes (common for 64-bit architectures).
what is this (**)?
In the context you present, it is part of the type designator char **, which describes a pointer to a pointer to char, just as you thought.
what use does it have?
More or less the same uses as a pointer to any other data type. Sometimes you want or need to access a pointer value indirectly, just like you may want or need to access a value of any other type indirectly. Also, it's useful for pointing to (the first element of) an array of pointers, which is how it is used in the second parameter to a C main() function.
In this particular case, each char * in the pointed-to array itself points to one of the program's command-line arguments.
how is it represented in memory?
C does not specify, but typically pointers to pointers have the same representation as pointers to any other type of value. The value it points to is simply a pointer value.
First of all, remember that C treats arrays very differently from Java. A declaration like
char foo[10];
allocates enough storage for 10 char values and nothing else (modulo any additional space to satisfy alignment requirements); no additional storage is set aside for a pointer to the first element or any other kind of metadata such as array size or element class type. There's no object foo apart from the array elements themselves1. Instead, there's a rule in the language that anytime the compiler sees an array expression that isn't the operand of the sizeof or unary & operator (or a string literal used to initialize another array in a declaration), it implicitly converts that expression from type "N-element array of T" to "pointer to T", and the value of the expression is the address of the first element of the array.
This has several implications. First is that when you pass an array expression as an argument to a function, what the function actually receives is a pointer value:
char foo[10];
do_something_with( foo );
...
void do_something_with( char *p )
{
...
}
The formal parameter p corresponding to the actual parameter foo is a pointer to char, not an array of char. To make things confusing, C allows do_something_with to be declared as
void do_something_with( char p[] )
or even
void do_something_with( char p[10] )
but in the case of function parameter declarations, T p[] and T p[N] are identical to T *p, and all three declare p as a pointer, not an array2. Note that this is only true for function parameter declarations.
The second implication is that the subscript operator [] can be used on pointer operands as well as array operands, such as
char foo[10];
char *p = foo;
...
p[i] = 'A'; // equivalent to foo[i] = 'A';
The final implication leads to one case of dealing with pointers to pointers - suppose you have an array of pointers like
const char *strs[] = { "foo", "bar", "bletch", "blurga", NULL };
strs is a 5-element array of const char *3; however, if you pass it to a function like
do_something_with( strs );
then what the function receives is actually a pointer to a pointer, not an array of pointers:
void do_something_with( const char **strs ) { ... }
Pointers to pointers (and higher levels of indirection) also show up in the following situations:
Writing to a parameter of pointer type: Remember that C passes all parameters by value; the formal parameter in the function definition is a different object in memory than the actual parameter in the function call, so if you want the function to update the value of the actual parameter, you must pass a pointer to that parameter:
void foo( T *param ) // for any type T
{
*param = new_value(); // update the object param *points to*
}
void bar( void )
{
T x;
foo( &x ); // update the value in x
}
Now suppose we replace the type T with the pointer type R *, then our code snippet looks like this:
void foo( R **param ) // for any type R *
{
...
*param = new_value(); // update the object param *points to*
...
}
void bar( void )
{
R *x;
foo( &x ); // update the value in x
}
Same semantics - we're updating the value contained in x. It's just that in this case, x already has a pointer type, so we must pass a pointer to the pointer. This can be extended to higher levels of direction:
void foo( Q ****param ) // for any type Q ***
{
...
*param = new_value(); // update the object param *points to*
...
}
void bar( void )
{
Q ***x;
foo( &x ); // update the value in x
}
Dynamically-allocated multi-dimensional arrays: One common technique for allocating multi-dimensional arrays in C is to allocate an array of pointers, and for each element of that array allocate a buffer that the pointer points to:
T **arr;
arr = malloc( rows * sizeof *arr ); // arr has type T **, *arr has type T *
if ( arr )
{
for ( size_t i = 0; i < rows; i++ )
{
arr[i] = malloc( cols * sizeof *arr[i] ); // arr[i] has type T *
if ( arr[i] )
{
for ( size_t j = 0; j < cols; j++ )
{
arr[i][j] = some_initial_value();
}
}
}
}
This can be extended to higher levels of indirection, so you have have types like T *** and T ****, etc.
1. This is part of why array expressions may not be the target of an assignment; there's nothing to assign anything to.
This is a holdover from the B programming language from which C was derived; in B, a pointer is declared as auto p[].
Each string literal is an array of char, but because we are not using them to initialize individual arrays of char, the expressions are converted to pointer values.
I think I'm going to add my own answer in here as well as everyone has done an amazing job but I was really confused at what the point of a pointer to a pointer was. The reason why I came up with this is because I was under the impression that all the values except pointers, were passed by value, and pointers were passed by reference. See the following:
void f(int *x){
printf("x: %d\n", *x);
(*x)++;
}
void main(){
int x = 5;
int *px = &x;
f(px);
printf("x: %d",x);
}
would produce:
x: 5
x: 6
This made my think (for some reason) that pointers were passed by reference as we are passing in the pointer, manipulating it and then breaking out and printing the new value. If you can manipulate a pointer in a function... why have a pointer to a pointer in order to manipulate the pointer to begin with!
This seemed wrong to me, and rightly so because it would be silly to have a pointer to manipulate a pointer when you can already manipulate a pointer in a function. The thing with C though; is everything is passed by value, even pointers. Let me explain further using some pseudo values instead of the addresses.
//this generates a new pointer to point to the address so lets give the
//new pointer the address 0061FF28, which has the value 0061FF1C.
void f(int 0061FF1C){
// this prints out the value stored at 0061FF1C which is 5
printf("x: %d\n", 5);
// this FIRST gets the value stored at 0061FF1C which is 5
// then increments it so thus 6 is now stored at 0061FF1C
(5)++;
}
void main(){
int x = 5;
// this is an assumed address for x
int *px = 0061FF1C;
/*so far px is a pointer with the address lets say 0061FF24 which holds
*the value 0061FF1C, when passing px to f we are passing by value...
*thus 0061FF1C is passed in (NOT THE POINTER BUT THE VALUE IT HOLDS!)
*/
f(px);
/*this prints out the value stored at the address of x (0061FF1C)
*which is now 6
*/
printf("x: %d",6);
}
My main misunderstanding of pointers to pointers is the pass by value vs pass by reference. The original pointer was not passed into the function at all, so we cannot change what address it is pointing at, only the address of the new pointer (which has the illusion of being the old pointer as its pointing to the address the old pointer was pointing to!).
It is a pointer to a pointer. If you are asking why you would want to use a pointer to a pointer, here is a similar thread that answers that in a variety of good ways.
Why use double pointer? or Why use pointers to pointers?
For example, ** is a pointer to a pointer. char **argv is the same as char *argv[] and this is the same with char argv[][]. It's a matrix.
You can declare a matrix with 4 lines, for example, but different number of columns, like JaggedArrays.
It is represented as a matrix.
Here you have a representation in memory.
I would understand char **argv as char** argv. Now, char* is basically an array of char, so (char*)* is an array of arrays of char.
In other (loose) words, argv is an array of strings. In this particular example: the call
myExe dummyArg1 dummyArg2
in console would make argv as
argv[0] = "myExe"
argv[1] = "dummyArg1"
argv[2] = "dummyArg2"
In fact, in C arrays are pointers :
char* string = "HelloWorld!";
is equivalent to this : char string[] = "HelloWorld";
And this : char** argv is as you said a "pointer to a pointer".
It can be seen as an array of strings, i.e multiple strings. But remember that strings are char pointers!
See : in Java the main method is similar to the C main function. It's something like this :
public static void main(String[] args){}
I.e an array of strings. It works the same way in C, String[] args becomes char** args or char* args[].
To sum up : type* name = blablabla;
is potentially an array of "type".
And type** name = blabla; is potentially an array of arrays.
int s[4][2] = {
{1234, 56},
{1212, 33},
{1434, 80},
{1312, 78}
};
int (*p)[1];
p = s[0];
printf("%d\n", *(*(p + 0))); // 1234
printf("%d\n", *(s[0] + 0)); // 1234
printf("%u\n", p); // 1256433(address of s[0][0])
printf("%u\n", *p); // 1256433(address of s[0][0])
Can anyone explain why doing *(*(p + 0)) prints 1234, and doing *(s[0] + 0) also prints 1234, when p = s[0] and also why does p and *p gives the same result?
Thanking you in anticipation.
This is the way arrays work in C -- arrays are not first class types, in that you can't do anything with them other than declaring them and getting their size. In any other context, when you use an expression with type array (of anything) it is silently converted into a pointer to the array's first element. This is often referred to as an array "decaying" into a pointer.
So lets look at your statements one by one:
p = s[0];
Here, s has array type (it's an int[4][2] -- a 2D int array), so its silently converted into a pointer to its first element (an int (*)[2], pointing at the word containing 1234). You then index this with [0] which adds 0 * sizeof(int [2]) bytes to the pointer, and then dereferences it, giving you an int [2] (1D array of 2 ints). Since this is an array, its silently converted into a pointer to its first element (an int * pointing at 1234). Note that this is the same pointer as before the index, just the pointed at type is different.
You then assign this int * to p, which was declared as int (*)[1]. Since C allows assigning any pointer to any other pointer (even if the pointed at types are different), this works, but any reasonable compiler will give you a type mismatch warning.
p now points at the word containing 1234 (the same place the pointer you get from s points at)
printf("%d\n", *(*(p+0)));
This first adds 0*sizeof(int[1]) to p and dereferences it, giving an array (int[1]) that immediately decays to a pointer to its first element (an int * still pointing at the same place). THAT pointer is then dereferenced, giving the int value 1234 which is printed.
printf("%d\n", *(s[0]+0));
We have s[0] again which via the multiple decay and dereference process noted in the description of the first line, becomes an int * pointing at 1234. We add 0*sizeof(int) to it, and then dereference, giving the integer 1234.
printf("%u\n", p);
p is a pointer, so the address of the pointer is simply printed.
printf("%u\n",*p)
p is dereferenced, giving an int [1] (1D integer array) which decays into a pointer to its first element. That pointer is then printed.
s[0]points to a location in memory. That memory location happens to be the starting point of int s[4][2]. When you make the assignment p = s[0], p and p+0 also point to s[0]. So when you print any one of these with a "%d" specifier, you will get the value stored at that location which happens to be `1234'. If you would like to verify the address is the same for all of these, use a format specifier "%p" instead of "%d".
EDIT to address OP comment question...
Here is an example using your own int **s:
First, C uses pointers. Only pointers. No arrays. The [] notation gives the appearance of arrays, but any variable that is created using the [] notation (eg. int s[4][2]) is resolved into a simple pointer (eg. int **s). Also, a pointer to a pointer is still just a pointer.
int a[8]={0}; (or int *a then malloced)
will look the same in memory as will:
int a[2][4]; ( or in **a=0; then malloced)
The statment:
s[row][col] = 1;
creates the same object code as
*(*(s + row) + col) = 1;
It is also true that
s[row] == *(s + row)
Since s[row] resolves to a pointer, then so does *(s + row)
It follows that s[0] == *(s + 0) == *s
If these three are equal, whatever value is held at this address will be displayed when printing it.
It follows that in your code: given that you have assigned p = s[0]; and s[0] == *s
*(*(p + 0)) == *(s[0] + 0) == *s[0] == **s
printf("%d\n", >>>fill in any one<<<); //will result in 1234
Note, in the following printf statements, your comment indicates addresses were printed. But because you used the unsigned int format specifier "%u",
Consider p == s[0]; which is a pointer to the first location of s. Note that either s[0][0] or **s would give you the value held at the first location of s, but s[0] is the _address_ of the first memory location of s. Therefore, since p is a pointer, pointing to the address at s[0], the following will give you the address of p, or s[0] (both same):
printf("%p\n", *p); // 1256433(address of s[0][0])
As for *p, p was created as int (*p)[1]; and pointer array of 1 element. an array is resolved into a pointer, so again, in the following you will get the address pointing to s[0]:
printf("%u\n", **p);
In summary, both p and *p are pointers. Both will result in giving address when printed.
Edit 2 Answer to your question: So my question is what is the difference between a simple pointer and a pointer to an array?
Look toward the bottom of this tutorial download a pdf. It may explain it better...
But in short, C Does not implement arrays in the same way other languages do. In C, an array of any data type always resolves into a pointer. int a[10]; is just really int *a;, with memory set aside for space to hold 10 integers consecutively. In memory it would look like:
a[0] a[9]
|0|0|0|0|0|0|0|0|0|0| (if all were initialized to zero)
Likewise you would be tempted to think of float b[2][2][2]; as a 3 dimensional array: 2x2x2, it is not. It is really a place in memory, starting at b[0] that has room for 8 floating point numbers. Look at the illustrations HERE.
I wrote the following code in C:
#include<stdio.h>
int main()
{
int a[10][10]={1};
//------------------------
printf("%d\n",&a);
printf("%d\n",a);
printf("%d\n",*a);
//-------------------------
printf("%d",**a);
return 0;
}
With the above 3 printf statements I got the same value. On my machine it's 2686384. But with the last statement I got 1.
Isn't it something going wrong? These statements mean:
The address of a is 2686384
The value stored in a is 2686384
the value that is stored at address of variable pointed by a (i.e. at 2686384) is 2686384.
This means a must be something like a variable pointing towards itself...
Then why is the output of *(*a) 1? Why isn't it evaluated as *(*a)=*(2686384)=2686384?
#include<stdio.h>
int main()
{
// a[row][col]
int a[2][2]={ {9, 2}, {3, 4} };
// in C, multidimensional arrays are really one dimensional, but
// syntax alows us to access it as a two dimensional (like here).
//------------------------
printf("&a = %d\n",&a);
printf("a = %d\n",a);
printf("*a = %d\n",*a);
//-------------------------
// Thing to have in mind here, that may be confusing is:
// since we can access array values through 2 dimensions,
// we need 2 stars(asterisk), right? Right.
// So as a consistency in this aproach,
// even if we are asking for first value,
// we have to use 2 dimensional (we have a 2D array)
// access syntax - 2 stars.
printf("**a = %d\n", **a ); // this says a[0][0] or *(*(a+0)+0)
printf("**(a+1) = %d\n", **(a+1) ); // a[1][0] or *(*(a+1)+0)
printf("*(*(a+1)+1) = %d\n", *(*(a+1)+1) ); // a[1][1] or *(*(a+1)+1)
// a[1] gives us the value on that position,
// since that value is pointer, &a[i] returns a pointer value
printf("&a[1] = %d\n", &a[1]);
// When we add int to a pointer (eg. a+1),
// really we are adding the lenth of a type
// to which pointer is directing - here we go to the next element in an array.
// In C, you can manipulate array variables practically like pointers.
// Example: littleFunction(int [] arr) accepts pointers to int, and it works vice versa,
// littleFunction(int* arr) accepts array of int.
int b = 8;
printf("b = %d\n", *&b);
return 0;
}
An expression consisting the the name of an array can decay to a pointer to the first element of the array. So even though a has type int[10][10], it can decay to int(*)[10].
Now, this decay happens in the expression *a. Consequently the expression has type int[10]. Repeating the same logic, this again decays to int*, and so **a is an int, which is moreover the first element of the first element of the array a, i.e. 1.
The other three print statements print out the address of, respectively, the array, the first element of the array, and the first element of the first element of the array (which are of course all the same address, just different types).
First, a word on arrays...
Except when it is the operand0 of the sizeof, _Alignof, or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element in the array.
The expression &a has type "pointer to 10-element array of 10-element array of int", or int (*)[10][10]. The expression a has type "10-element array of 10-element array of int", which by the rule above decays to "pointer to 10-element array of int", or int (*)[10]. And finally, the expression *a (which is equivalent to a[0]) has type "10-element array of int", which again by the rule above decays to "pointer to int".
All three expressions have the same value because the address of an array and the address of its first element are the same: &a[0][0] == a[0] == *a == a == &a. However, the types of the expressions are different, which matters when doing pointer arithmetic. For example, if I have the following declarations:
int (*ap0)[10][10] = &a;
int (*ap1)[10] = a;
int *ip = *a;
then ap0++ would advance ap0 to point to the next 10x10 array of int, ap1++ would advance ap1 to pointer to the next 10-element array of int (or a[1]), and ip++ would advance ip to point to the next int (&a[0][1]).
**a is equivalent to *a[0] which is equivalent to a[0][0]. which is the value of the first element of a and has type int and the value 1 (note that only a[0][0] is initialized to 1; all remaining elements are initialized to 0).
Note that you should use %p to print out pointer values:
printf("&a = %p\n", &a);
printf(" a = %p\n", a);
printf("*a = %p\n", *a);
First of all, if you want to print out pointer values, use %p - if you're on a 64 bit machine int almost certainly is smaller than a pointer.
**a is double dereferencing what's effectively a int**, so you end up with what the first element of the first sub-array is: 1.
If you define a as T a[10] (where T is some typedef), then a simple unadorned a means the address of the start of the array, the same as &a[0]. They both have type T*.
&a is also the address of the start of the array, but it has type T**.
Things become trickier in the presence of multi-dimensional arrays. To see what is happening, it is easier to break things down into smaller chunks using typedefs. So, you effectively wrote
typedef int array10[10];
array10 a[10];
[Exercise to reader: What is the type of a? (it is not int**)]
**a correctly evaluates to the first int in the array a.
From C99 Std
Consider the array object defined by the declaration
int x[3][5];
Here x is a 3 × 5 array of ints; more precisely, x is an array of three element objects, each of which is an array of five ints. In the expression x[i], which is equivalent to (*((x)+(i))), x is first converted to a pointer to the initial array of five ints. Then i is adjusted according to the type of x, which conceptually entails multiplying i by the size of the object to which the pointer points, namely an array of five int objects. The results are added and indirection is applied to yield an array of five ints. When used in the expression x[i][j], that array is in turn converted to a pointer to the first of the ints, so x[i][j] yields an int.
so,
Initial array will be x[0][0] only.
all x, &x and *x will be pointing to x[0][0].
No, there's nothing wrong with your code. Just they way you are thinking about it... The more I think about it the harder I realize this is to explain, so before I go in to this, keep these points in mind:
arrays are not pointers, don't think of them that way, they are different types.
the [] is an operator. It's a shift and deference operator, so when I write printf("%d",array[3]); I am shifting and deferencing
So an array (lets think about 1 dimension to start) is somewhere in memory:
int arr[10] = {1};
//Some where in memory---> 0x80001f23
[1][1][1][1][1][1][1][1][1][1]
So if I say:
*arr; //this gives the value 1
Why? because it's the same as arr[0] it gives us the value at the address which is the start of the array. This implies that:
arr; // this is the address of the start of the array
So what does this give us?
&arr; //this will give us the address of the array.
//which IS the address of the start of the array
//this is where arrays and pointers really show some difference
So arr == &arr;. The "job" of an array is to hold data, the array will not "point" to anything else, because it's holding its own data. Period. A pointer on the other hand has the job to point to something else:
int *z; //the pointer holds the address of someone else's values
z = arr; //the pointer holds the address of the array
z != &z; //the pointer's address is a unique value telling us where the pointer resides
//the pointer's value is the address of the array
EDIT:
One more way to think about this:
int b; //this is integer type
&b; //this is the address of the int b, right?
int c[]; //this is the array of ints
&c; //this would be the address of the array, right?
So that's pretty understandable how about this:
*c; //that's the first element in the array
What does that line of code tell you? if I deference c, then I get an int. That means just plain c is an address. Since it's the start of the array it's the address of the array, thus:
c == &c;