Similarities and differences between arrays and pointers through a practical example - c

Given the following code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a[1];
int * b = malloc(sizeof(int));
/* 1 */
scanf("%d", &a);
printf("%d\n", a[0]);
/* 2 */
scanf("%d", &b);
printf("%d\n", b[0]);
return 0;
}
the following warnings are obtained when it is compiled (i686-apple-darwin9-gcc-4.0.1):
array.c: In function 'main':
array.c:9: warning: format '%d' expects type 'int *', but argument 2 has type 'int (*)[0u]'
array.c:14: warning: format '%d' expects type 'int *', but argument 2 has type 'int **'
but, why does an execution-error occur in the second printf, meanwhile it works for the first printf?
Even more, why it is obtained the same output if the first scanf is substituted by scanf("%d", a);?
Thank very much in advance

In most contexts, an expression of array type will be implicitly converted from an "N-element array of T" to "pointer to T" and its value will be set to point to the first element of the array. The exceptions to this rule are when the array is an operand of the & or sizeof operators, or if the array is a string literal being used to initialize another array in a declaration.
So how does all that relate to your code?
In the line
scanf("%d", &a);
You are applying the & operator to the array. This suppresses the implicit conversion from "array of T" to "pointer to T" and returns a value of type "pointer to array of T", or T (*)[N] (hence your first warning). Now it turns out that the value of a pointer to an array and the value of a pointer to the first element of the array are the same, they just have different types. So assuming that a is at address 0x0001000:
expression type value note
---------- ---- ----- ----
a int * 0x0001000 implicitly converted to pointer
&a int (*)[N] 0x0001000
&a[0] int * 0x0001000
That's why your first call to scanf() "works"; you're passing the right pointer value, but the compiler is complaining because the type of the expression doesn't match what the function expects. Had you written
scanf("%d", a);
you would not have received any warnings, since the type of a will be taken to be int *, which is what scanf() expects. Note that this is identical to calling
scanf("%d", &a[0]);
As for b...
You explicitly declare b as a pointer to int and assign a block of memory to it. When you apply the & operator to it, what you get back is the address of the variable b with type int ** (hence the second warning), not the address that b points to.
expression type value note
---------- ---- ----- ----
b int * 0x0040000 value contained in b
&b int ** 0x0001000 address of b
For that case, you just pass the undecorated b:
scanf("%d", b);

The array a is placed on the stack, the address for the first element is the same as the address of a. &a[0] and &a is the same address
The array b is allocated with malloc, the address for the storage is on the heap, whereas the address for the pointer b is on the stack. &b[0] is not the same address as &b.
That's why the first scanf and printf works but not the second.
The C-FAQ explains it in much greater detail.

In the first scanf you pass a reference to an array. In C arrays are pointers to a memory block of the allocated type, in your case int * and an expression like a[0] gets translated into *(a + 0) (which btw gives rise to the funny variant 0[a] which will actually compile.) This array is allocated on the stack. The second array is allocated on the heap and the stack contains the pointer variable to that array.
In both cases you do not pass a pointer to the first array entry, but to the array and the pointer to the array respectively.
Your first scanf overwrites that what is the array, as it is allocated on the stack, your value ends up (by luck) in the array.
Your second scanf overwrites the pointer to the array, thereby changing the pointer to a memory address that probably does not exist in your data segment. This results in the execution error.

That's normal ...
First, scanf requires a pointer. "a" and "b" already are pointers !
So :
/* 1 */
scanf("%d", a);
printf("%d\n", a[0]);
/* 2 */
scanf("%d", b);
printf("%d\n", b[0]);
Will work.
Normally /* 1 */ shouldn't work. But gcc transforms "&a" by "a" because "&a" doesn't have any sense.
printf("&a = %p\n", &a);
printf("a = %p\n", a);
printf("&b = %p\n", &b);
printf("b = %p\n", b);
&a = 0x7ffff6be67d0
a = 0x7ffff6be67d0
&b = 0x7ffff6be67c8
b = 0xb0b010
You can't take the adress of a. But b is a "normal variable" of type pointer, and thus you can take it's address by "&b".
On /* 2 */ you're putting the value entered by the user in b and thus, *b (or b[0]) will crash unless the user will enter a valid readable memory address.

In your case what is happening is that you are passing both variables a and b with the & operator to the scanf function. What this operator does is "ask" the memory address of the variable and pass that address to the scanf function. But, as both of your variables are pointers, what they have indeed is an memory address, so when you pass &a or &b you are passing the memory of the pointer, not the memory address that it holds.
Example:
int x;
int *ptr;
x = 10;
suppose the memory address of x is 1000. You are storing the number 10 at the memory address 1000. Now you do this:
ptr = &x;
You are storing the address 1000 in the pointer. But 1000, apart being an address, is a number itself, so the pointer, as does x, still needs a memory address to store that information. Suppose the pointer memory location is 1004. Now look the example:
*ptr == 10; //x content
ptr == 1000 //x memory address
&ptr == 1004 // ptr memory address.
So if you want to pass to scanf the variable x, but using the pointer, you need to pass the x address stored in it
scanf("%d", ptr);
Just to ilustrate another example of pointers and vectors
int main
{
int vet[5];
int *ptr;
ptr = vet;
for(int i = 0; i < 5; ++i)
{
scanf("%d", (ptr+i) );
}
}
Here you can read the vector using the pointer. Also, using pointer arithmetics you can iterate over the memory addresses of the vector.

Related

Where is a[0] pointing at?

Let's say we have an array char a[] = "abcd". When I print the following:
printf("%p\n", a);
printf("%p\n", &a);
printf("%p\n", &a[0]);
printf("%p\n", a[0]);
I am getting the following results:
0061FF1B
0061FF1B
0061FF1B
00000061
which means that a[0] is not pointing at the same memory address as either %a[0] or a. This is really confusing to me. I'd like someone to point out the difference between these pointers, and whether or not a[0] is / decays to a pointer.
a[0] is not pointing anywhere because it isn't a pointer but a char object. You lie to printf and tell it that it is a pointer, when it isn't. That's an undefined behavior bug in your program.
Now as it happens 0x61 is the ASCII code for 'a'.
Regarding the other lines in your code: whenever used in expressions or function calls, arrays "decay" into a pointer to their first element. There are very few exceptions when this decay doesn't happen - using the & address-of operator is one of them.
Therefore: printf("%p\n", a); decays to a pointer to the first element, which is 100% equivalent to printf("%p\n", &a[0]);.
In case of printf("%p\n", &a); the decay does not happen but you get the address of the array itself. In C, an array is nothing but a bunch of elements with no other overhead, so the address of the array will always be the same as the address of the first element.
char a[] = "abcd"
Array a, when used in an expression, will convert to pointer to first element of array i.e. &a[0] (there are few exceptions to this rule).
&a is address of array a which is numerically same as the address of first element of array &a[0] but the difference is in their type. The type of &a[0] is char * whereas the type of &a is char (*) [5].
&a[0] is address of first element of array a.
a[0] is first element of character array a.
which means that a[0] is not pointing at the same memory address as either %a[0] or a. ..........
whether or not a[0] is / decays to a pointer.
a[0] is not a pointer, it is first element of array a which is character 'a'. Note that decay happens when array name is used.
When printing a[0], you should use the format specifier %c. Wrong format specifier in printf() lead to undefined behaviour. Also, format specifier %p expect that the argument shall be a pointer to void. You should type cast pointer argument to void * - printf("%p\n", (void*)a);.
When you compile the code with g++, you will find the following warning
main.cpp: In function ‘int main()’:
main.cpp:7:21: warning: format ‘%p’ expects argument of type ‘void*’, but argument 2 has type ‘int’ [-Wformat=]
printf("%p\n", a[0]);
~~~~^
Here, a and &a[0] point to the address of first item of the string
while a[0] is a char. You print a[0] whose ascii is 0x00000061 with %p.
printf("%p\n", &a[0]);
printf("%p\n", a[0]);
In the first case you correctly print the address of the first element of a.
In the second case you ask printf to print a pointer but you pass it a char.
The char is automatically converted to an int (due to the signature of printf, that contains ...).
The ellipsis notation in a function prototype declarator
causes argument type conversion to stop after the last declared
parameter. The default argument promotions are performed on trailing
arguments
The fact that printf prints 61 (exactly the ASCII code) is because on your computer the pointer to object and the int have the same number of bits or because it has 0s next to integer, where printf reads the pointer value.
But it is undefined behavior to pass printf a type and instrument it print other type.
In C array variable is like address
char a[] = "abcd";
// it is all same
// a == &a == &a[0]
// &(a + 1) == &a[1]
// so roughly say 'a' is pointer to address of first element of array
// and a[0] or a[1] is a value.
// this is more appropriate way to express a[0]
printf("%c\n", a[0]);

Confused on examples of basic functions in C [duplicate]

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

what is the difference between accessing an array with a pointer and a non-array variable through a pointer

I am attempting to learn C in a little more depth. I have written the code displayed below.
#include "includes.h"
int main() {
char *array[1];
array[0] = "cloud";
char *ll[1];
ll[0] = array[0];
int n = 20, *pointer; // actual and pointer decaration
pointer = &n; // assign the memory address of int n to pointer
printf("the address of the variable in pointer is: %x\n", pointer);
printf("the value of *pointer is %d\n", *pointer);
printf("the value of &pointer is %x\n", &n);
//return 0;
// to access the value provided by a pointer, you would use *pointer
// accessing an array directly
printf("value of array[0] %s\n", array[0]);
printf("address of &array[0] %x\n", &array[0]);
// accessing array through the pointer ll
printf("value of *ll %s\n", *ll);
printf("address of ll %x\n", ll);
printf("pointer: %p\n", (void*) pointer); //inclusion from #chux
}
The header file "includes.h" contains the following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#define DEF1 20
#define DEF2 2
Here is the program output, as from my Bash Terminal:
[carl#sparknohss c]$ ./pointers.bin
the address of the variable in pointer is: 4a8c27dc
the value of *pointer is: 20
the value of &pointer is: 4a8c27dc
value of array[0]: cloud
address of &array[0]: 4a8c27f0
value of *ll: cloud
address of ll: 4a8c27e0
pointer: 0x7ffc4a8c27dc
[carl#sparknohss c]$
I see that there is a difference, at least I think, when accessing a pointer that points to a non-array and when accessing a pointer that points to an array. Is there anyone that can explain this in a little more detail?
Also, what is the difference between %x and %p, other than the '0x7ffc' prefix provided by %x? Are there any good resources that I can delve into for a better explanation?
I see that there is a difference, at least I think, when accessing a pointer that points to a non-array and when accessing a pointer that points to an array. Is there anyone that can explain this in a little more detail?
There are some differences when dealing with arrays and pointer objects.
Setting aside your code for a second, assume you have the declaration
int arr[10];
This creates an array arr large enough to hold 10 integers; it's laid out in memory like so:
+---+
arr: | | arr[0]
+---+
| | arr[1]
+---+
...
+---+
| | arr[9]
+---+
One thing becomes obvious here - the address of the first element of the array (&arr[0]) is going to be the same as the address of the whole array object (&arr). The expressions &arr[0] and &arr will have the same value, but their types will be different - the type of &arr[0] will be "pointer to int" (int *), while the type of &arr will be "pointer to 10-element array of int" (int (*)[10]).
Now here's where a wrinkle comes in - except when it is the operand of the sizeof or unary & operators, or is a string literal used to initialize another array in a declaration, an expression of type "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 of the array.
This means that the expression arr also evaluates to the address of the first element of the array, just like &arr[0] and &arr; it "decays" from type "10-element array of int" to "pointer to int" (same type as &arr[0]).
This is definitely different from how regular pointer variables behave. Given
int *ptr;
the expression ptr does not give you the same value as &ptr - it gives you the value of whatever is stored in ptr.
Going back to your code for a second, in the line
array[0] = "cloud";
the string literal "cloud" is itself an array expression - it has type "6-element array of char" (counting the 0 terminator). Since it is not the operand of the sizeof or unary & operators, nor is it being used to initialize another array in a declaration, the expression is converted from type "array of char" to "pointer to char", and the value of the expression is the address of the first character in the string. Since you declared array as an array of char *, this works; the type of array[0] is char *.
So, why do array expressions "decay" to pointer expressions?
The array indexing operation a[i] is defined as *(a + i) - given an address value, offset i elements (not bytes) from that address and dereference the result. This is a holdover from the B programming language from which C was derived, and which used pointers internally when setting up array objects. C got rid of the internal pointers, but kept the subscript semantics. So, for a[i] to work in C, a first has to be converted to a pointer value. Note that this means you can use the [] operator on pointer types - pointer[0] and *pointer will give you the same result (the value of the thing pointer is pointing to).
So, if you print out the following expressions:
printf( "&array[0] = %p\n", (void *) &array[0] );
printf( "array = %p\n", (void *) array );
printf( "&array = %p\n", (void *) &array );
you should see the same value for all three - the address of the first element of array. If you print out the expression
printf( "array[0] = %p\n", (void *) array[0] );
you should see the address of the first character of the "cloud" string literal.
If you print the expression
printf( "array = %s\n", array );
you should see the string cloud. Remember that the %s conversion specifier expects its corresponding argument to be a pointer to char, and it will print the sequence of characters starting at that address until it sees the 0 terminator.
If you print the expression
printf( "*array[0] = %c\n", *array[0] );
you will see the character c - the first letter in the "cloud" string. Note that *array[0] is the same as array[0][0]. To print l, you'd write
printf( "array[0][1] = %c\n", array[0][1] );
If you print the expressions
printf( "pointer = %p\n", (void *) pointer );
printf( "&pointer = %p\n", (void *) &pointer );
you should definitely see different values since pointer is not an array object.
Also, what is the difference between %x and %p
%x expects its corresponding argument to have type unsigned int, and formats the output in hexadecimal.
%p expects its corresponding argument to have type void *, and formats the output in an implementation-defined manner (often hex, but it doesn't have to be).
You do not want to use %x (or anything other than %p) to print out pointer values. For one thing, a pointer value may be wider than an unsigned int (that's true on my system), so the output will likely be garbled.

Why can't a c pointer be treated as an array?

In the question Find size of array without using sizeof in C the asker treats an int array like an array of int arrays by taking the address and then specifying an array index of 1:
int arr[100];
printf ("%d\n", (&arr)[1] - arr);
The value ends up being the address of the first element in the "next" array of 100 elements after arr. When I try this similar code it doesn't seem to do the same thing:
int *y = NULL;
printf("y = %d\n", y);
printf("(&y)[0] = %d\n", (&y)[0]);
printf("(&y)[1] = %d\n", (&y)[1]);
I end up getting:
y = 1552652636
(&y)[0] = 1552652636
(&y)[1] = 0
Why isn't (&y)[1] the address of the "next" pointer to an int after y?
Here:
printf("(&y)[1] = %d\n", (&y)[1]);
You say first: take address of y. Then afterwards you say: add 1 times so many bytes as the size of the thing which is pointed to - which is pointer to int, and hence probably 4 bytes are added - and dereference whatever is that on that address. But you don't know what is on that new memory address and you can't/shouldn't access that.
Arrays are not pointers, and pointers are not arrays.
The "array size" code calculates the distance between two arrays, which will be the size of an array.
Your code attempts to calculate the distance between two pointers, which should be the size of a pointer.
I believe the source of confusion is that (&y)[1] is the value of the "next" pointer to an int after y, not its address.
Its address is &y + 1.
In the same way, the address of y is &y, and (&y)[0] - or, equivalently *(&y) - is y's value.
(In the "array size" code, (&arr)[1] is also the "next" value, but since this value is an array, it gets implicitly converted to a pointer to the array's first element — &((&array)[1])[0].)
If you run this:
int *y = NULL;
printf("y = %p\n", y);
printf("&y = %p\n", &y + 0);
printf("&y + 1 = %p\n", &y + 1);
the output looks somewhat like this:
y = (nil)
&y = 0xbf86718c
&y + 1 = 0xbf867190
and 0xbf867190 - 0xbf86718c = 4, which makes sense with 32-bit pointers.
Accessing (&y)[1] (i.e. *(&y + 1)) is undefined and probably results in some random garbage.
Thanks for the answers, I think the simplest way to answer the question is to understand what the value of each expression is. First we must know the type, then we can determine the value
I used the c compiler to generate a warning by assigning the values to the wrong type (a char) so I could see exactly what it thinks the types are.
Given the declaration int arr[100], the type of (&arr)[1] is int [100].
Given the declaration int *ptr, the type of (&ptr)[1] is int *.
The value of a int[100] is the constant memory address of where the array starts. I don't know all the history of why that is exactly.
The value of a int * on the other hand is whatever memory address that pointer happens to be holding at the time.
So they are very different things. To get the constant memory address of where a pointer starts you must dereference it. So &(&ptr)[1] is int ** which the constant memory address of where the int pointer starts.

Is an array name a pointer?

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

Resources