is the array name is actually like typing the address of the first element of the array ?
based on my understanding of the array name
the array name variable isn't a pointer that has it's own memory address and it's content is the address of the first element of the array
but it's a way of typing the address of first element in a plain english name
i will try now to explain it now visually
consider the following code it will be related to the image i'm about to show you
char[] text = "Hey";
char *ptr = text;
and now look at the image
the *ptr variable has it's own memory address and the content of the pointer is the memory address of H which is 0101
now the text variable doesn't have it's own memory address when we type text C interprets it to the memory address 0101
so basically text is 0101
am i right ?
Well, almost but not quite.
text is a variable of type char [4], it's an array of chars. Now, as per the spec, chapter 6.3.2.1/P3
Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ''array of type'' is converted to an expression with type ''pointer to type'' that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.
That means,
char * ptr = text;
is the same as writing
char * ptr = &text[0];
That said,
now the text variable doesn't have it's own memory address when we type text C interprets it to the memory address 0101
No, this is wrong. The variable text has an address (try doing &text, it'll be of type char (*) [4]). Now, since an array is a collection of same objects (member object type) in contiguous memory locations, the address of the array is the address of the first element of the array, so while printing the address of the array and the address of the first element of the array will turn out to be same - but remember, they certainly do differ in type.
For starters this declaration
char[] text = "Hey";
is not a valid C construction.:) It seems you mean
char text[] = "Hey";
An array type and a pointer type are two different types. Consider the following demonstrative program.
#include <stdio.h>
int main(void)
{
char text[] = "Hello World!";
char *ptr = "Hello World!";
printf( "sizeof( text ) = %zu\n", sizeof( text ) );
printf( "sizeof( ptr ) = %zu\n", sizeof( ptr ) );
return 0;
}
Its output might look like
sizeof( text ) = 13
sizeof( ptr ) = 8
Or if you will apply the address of operator & to the variable text like &text then the type of the expression will be char ( * )[13]. While applying the operator to the variable ptr like &ptr then the type of the expression will be char **.
Indeed according to the C Standard an array designator is implicitly converted in expressions (except the expressions mentioned above) to a pointer to its firs element.
So you may write
char text[] = "Hey";
char *ptr = text;
The values of the expressions &text and ptr (though they have different types) will be equal because they both point to the initial address of the extent of the memory occupied by the array.
The fact that an array designator is converted to a pointer to its first element is related to how the compiler adjusts a function parameter having an array type to the type of pointer to the array element type. That is for example these two function declarations declare the same one function
void f( char s[] );
and
void f( char *s );
Related
This question may seems quite duplicated; however, I indeed have had a serious survey on this site and still cannot quite understand.
char str[] = "test";
printf("%p\n", str);
printf("%p\n", &str);
I know str itself is a pointer which points to the starting location that stores "t". Therefore I expect that printf("%p\n", str); shows this address (say 000000FFE94FFC34). Next, I wish to know in my OS, at what memory location that stores the exact information 000000FFE94FFC34. (i.e. the address of str itself.)
However, the output of the third line is the same as the previous one. It seems quite a weird behavior. And how can I figure out the address of str itself? I guess this can be achieved by using another new pointer that points to the pointer I want, i.e. char **super_pointer = str; but I think it is an unnecessarily complicated way.
Lets draw it out with the pointers added, to hopefully make it simpler to understand:
+--------+--------+--------+--------+--------+
| str[0] | str[1] | str[2] | str[3] | str[4] |
+--------+--------+--------+--------+--------+
^
|
&str[0]
|
&str
As you can see the pointer to the first element (&str[0] which is what plain str decays to) points to the same location as the array itself (&str).
But (and it's an important but): The type are very different!
The type of &str[0] is char *.
The type of &str is char (*)[5].
On another note you say that
... str itself is a pointer...
This is wrong. str itself is the array, which can decay to a pointer to its first element.
I know str itself is a pointer which points to the starting location
that stores "t".
As you wrote "str itself" is not a pointer it is an array. But used in expressions array designators with rare exceptions are converted to pointers to their first elements.
From the C Standard (6.3.2.1 Lvalues, arrays, and function designators)
3 Except when it is the operand of the sizeof operator or the unary &
operator, or is a string literal used to initialize an array, an
expression that has type ‘‘array of type’’ is converted to an
expression with type ‘‘pointer to type’’ that points to the initial
element of the array object and is not an lvalue. If the array object
has register storage class, the behavior is undefined.
In this call
printf("%p\n", str);
the array designator str used as an argument expression is converted to a pointer to its first element. In fact this call is equivalent to
printf("%p\n", &str[0]);
That is this call outputs the starting address of the extent of memory occupied by the array.
This call
printf("%p\n", &str);
that is better to write as and the previous call like
printf("%p\n", ( void * )&str);
also outputs the starting address of the extent of the memory occupied by the array.
What is the difference?
The expression str used in the call of printf has the type char * while the expression &str has the type char ( * )[5].
The both expressions is interpreted by the call as expressions of the type void *.
To make this more clear consider a two dimensional array
char str[2][6] = { "test1", "test2" };
The addresses of the array as whole and of its first "row" and of its first character of the first "row" are coincide.
That is the expression &sgtr that has the type char ( * )[2][6] and the expression &str[0] that has the type char ( * )[6] and the expression &str[0][0] that has the type char * yield the same value: hhe starting address of the extent of memory occupied by the array..
I am trying to understand the significance of these two operators, so I wrote this code just for that purpose.
#include <stdio.h>
#include <string.h>
int main()
{
char *mnemonic, *operands;
mnemonic = "add";
operands = "five to two";
analyse_inst(mnemonic, operands);
}
void analyse_inst(char mnemonic, char operands)
{
printf("%s", mnemonic);
printf("%s", operands);
}
However, I noticed that it wouldn't work unless I change the arguments of analyse_inst() function to analyse_inst(char * mnemonic, char * operands), which means that I will be passing pointers to the function. But why is that required?
Also, I looked up about "passing by reference." And according to tutorialspoint.com, its definition:
The call by reference method of passing arguments to a function copies
the address of an argument into the formal parameter. Inside the
function, the address is used to access the actual argument used in
the call. It means the changes made to the parameter affect the passed
argument.
From that, I got that passing a variable by reference and then modifying that value would mean that the same variable outside the function would be changed as well; whereas for passing a variable by value would not change the same variable located outside the function.
Am I going wrong anywhere?
How can I can modify my code such that I am passing the two variables by reference?
(P.S. I have read other Stack Overflow threads on the same topic, but I would appreciate it if anyone could explain it in the context of the code I wrote)
which means that I will be passing pointers to the function. But why is that required?
Because what you have in main are pointers, and what printf("%s" expects is a char*.
"Pass by reference" is a broad term in programming, meaning passing along an address rather than a copy of the object. In your case, you pass a pointer to the first element of each string, rather than making a copy of the whole string, since that would waste execution time and memory.
So while the strings themselves could be said to be "passed by reference", strictly speaking C actually only allows parameters to be passed by value. The pointers themselves are passed by value. Your function parameters will be copies of the pointers you have allocated in main(). But they point at the same strings as the pointers in main() do.
From that, I got that passing a variable by reference and then modifying that value would mean that the same variable outside the function would be changed as well;
Indeed, you could change the string from inside the function through the pointer and then it would affect the string in main(). But in this case, you haven't allocated any memory to modify - you would attempt to modify a string literal "...", which would have been a bug. If you were to modify the strings, you should have declared them as arrays in main(): char mnemonic[] = "add";
Now as it turns out, whenever you use an array like the one in my example inside an expression, it "decays" into a pointer to the first element. So we wouldn't actually be able to pass the array by value to the function, as the C language would have changed it between the lines to a pointer to the first element.
You can play around with this code:
#include <stdio.h>
#include <string.h>
void analyse_inst(char* mnemonic, char* operands);
int main()
{
char mnemonic[] = "add";
char operands[] = "five to two";
analyse_inst(mnemonic, operands);
printf("%s\n", mnemonic);
}
void analyse_inst(char* mnemonic, char* operands)
{
printf("%s ", mnemonic);
printf("%s\n", operands);
strcpy(mnemonic, "hi");
}
When you write something like char *mnemonic that means you are creating a pointer variable (variable that will hold the address of another variable) but since the data type of the mnemonic is char it will hold the address of variable with char datatype only.
Now, inside your code you have written mnemonic = "add" so here "add" is the string that is array of characters and mnemonic is pointing to the base address of that array.
and while calling the function you are passing the references of these char arrays, so you need to change void analyse_inst(char mnemonic, char operands) to void analyse_inst(char *mnemonic, char *operands) to get the references in these respective pointer variables. Reason is same We need pointer variables to hold the references.
And the & returns the address of the variable, that means the reference to the memory location in which the variable is stored.
Hope this will help.
Strings in C are stored as arrays of characters, terminated by a character with the value '\0' ("NIL"). You cannot directly pass around arrays, so instead a pointer to the first character is used, which is why you must pass char *s to the function in order to access strings.
A character is typically much smaller than a pointer (think 8 vs 32/64 bits), so you cannot squeeze a pointer value into a single character.
C does not have pass by reference; it's pass by value only. Sometimes that value is as close to a reference as the language can come (i.e. a pointer), but then that pointer is in turn passed by value.
Consider this:
static void put_next(const char *s)
{
putchar(*s++);
}
int main(void)
{
const char *string = "hello";
put_next(string);
put_next(string);
}
This will print hh, since it's being passed the same value string every time, the fact that s, which is a different variable holding a copy of the same value, is incremented inside the function doesn't matter. The incremented value is local to the function, and thrown away once it goes out of scope.
I will discuss things in the context of your code, but I want to get some basics out of the way first.
In a declaration, the unary * operator indicates that the thing being declared has pointer type:
T *p; // for any type T, p has type "pointer to T"
T *p[N]; // for any type T, p has type "N-element array of pointer to T"
T (*p)[N]; // for any type T, p has type "pointer to N-element array of T"
T *f(); // for any type T, f has type "function returning pointer to T"
T (*f)(); // for any type T, f has type "pointer to function returning T"
The unary * operator has lower precedence then the postfix [] subscript and () function operators, so if you want a pointer to an array or a function, the * must be explicitly grouped with the identifier.
In an expression, the unary * operator dereferences the pointer, allowing us to access the pointed-to object or function:
int x;
int *p;
p = &x; // assign the address of x to p
*p = 10; // assigns 10 to x via p - int = int
After the above code has executed, the following are true:
p == &x // int * == int *
*p == x == 10 // int == int == int
The expressions p and &x have type int * (pointer to int), and their value is the (virtual) address of x. The expressions *p and x have type int, and their value is 10.
A valid1 object pointer value is obtained in one of three ways (function pointers are also a thing, but we won't get into them here):
using the unary & operator on an lvalue2 (p = &x;);
allocating dynamic memory via malloc(), calloc(), or realloc();
and, what is relevant for your code, using an array expression without a & or sizeof operator.
Except when it is the operand of the sizeof or unary & operator, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T" is converted ("decays") to an expression of type "pointer to T", and the value of the expression is the address of the first element of the array3. So, if you create an array like
int a[10];
and pass that array expression as an argument to a function like
foo( a );
then before the function is called, the expression a is converted from type "10-element array of int" to "pointer to int", and the value of a is the address of a[0]. So what the function actually receives is a pointer value, not an array:
void foo( int *a ) { ... }
String literals like "add" and "five to two" are array expressions - "add" has type "4-element array of char" and "five to two" has type "12-element array of char" (an N-character string requires at least N+1 elements to store because of the string terminator).
In the statements
mnemonic = "add";
operands = "five to two";
neither string literal is the operand of the sizeof or unary & operators, and they're not being used to initialize a character array in a declaration, so both expressions are converted to type char * and their values are the addresses of the first element of each array. Both mnemonic and operands are declared as char *, so this is fine.
Since the types of mnemonic and operands are both char *, when you call
analyse_inst( mnemonic, operands );
the types of the function's formal arguments must also be char *:
void analyse_inst( char *mnemonic, char *operands )
{
...
}
As far as the "pass by reference" bit...
C passes all function arguments by value. That means the formal argument in the function definition is a different object in memory from the actual argument in the function call, and any changes made to the formal argument are not reflected in the actual argument. Suppose we write a swap function as:
int swap( int a, int b )
{
int tmp = a;
a = b;
b = tmp;
}
int main( void )
{
int x = 2;
int y = 3;
printf( "before swap: x = %d, y = %d\n", x, y );
swap( x, y );
printf( "after swap: x = %d, y = %d\n", x, y );
...
}
If you compile and run this code, you'll see that the values of x and y don't change after the call to swap - the changes to a and b had no effect on x and y, because they're different objects in memory.
In order for the swap function to work, we have to pass pointers to x and y:
void swap( int *a, int *b )
{
int tmp = *a;
*a = *b;
*b = tmp;
}
int main( void )
{
...
swap( &x, &y );
...
}
In this case, the expressions *a and *b in swap refer to the same objects as the expressions x and y in main, so the changes to *a and *b are reflected in x and y:
a == &x, b == &y
*a == x, *b == y
So, in general:
void foo( T *ptr ) // for any non-array type T
{
*ptr = new_value(); // write a new value to the object `ptr` points to
}
void bar( void )
{
T var;
foo( &var ); // write a new value to var
}
This is also true for pointer types - replace T with a pointer type P *, and we get the following:
void foo( P **ptr ) // for any non-array type T
{
*ptr = new_value(); // write a new value to the object `ptr` points to
}
void bar( void )
{
P *var;
foo( &var ); // write a new value to var
}
In this case, var stores a pointer value. If we want to write a new pointer value to var through foo, then we must still pass a pointer to var as the argument. Since var has type P *, then the expression &var has type P **.
A pointer value is valid if it points to an object within that object's lifetime.
An lvalue is an expression that refers to an object such that the object's value may be read or modified.
Believe it or not there is a good reason for this rule, but it means that array expressions lose their "array-ness" under most circumstances, leading to much confusion among people first learning the language.
Say we have the following array:
char *names[]={"Abc", "Def", "Ghi", "Klm", "Nop"};
If we want to create a pointer that points to the array above, why should we use a two-level pointer as follows?
char **p1 = names;
Thanks.
Your names is an array [], of char *, i.e., an array of pointers to char.
Meanwhile p1 is a pointer which points to a pointer to char, i.e., a pointer to char *. You can assign names to it because the array decays to a pointer to its first element, and the first element of names is a pointer to char, hence names decays to a pointer to char *. This is the same type – char ** – as p1, therefore they are compatible.
(On another note, the element type of names is incorrect; the string literals are constant, and thus it should be const char *names[], and similarly p1 should be const char** – pointer to pointer to const char.)
You can see it this way, when you need to point to an integer array, you need to use a pointer to int.
int arr[];
int* a;
a = arr;
So, in this context, you need a pointer to the elements in the array names[]. What are the elements in that array. Its char*. So you would need a pointer to char*. Which translates to pointer to pointer to char.
That is
char *names[]={"Abc", "Def", "Ghi", "Klm", "Nop"};
char **p1 = names;
You did not create a pointer to array of pointers .It actually is pointer to first pointer of array.
If you want to create a pointer to array of pointers write something like this -
char *names[MAX];
char* (*p1)[MAX] = &names;
If you want to create a pointer that points to array
char *names[]={"Abc", "Def", "Ghi", "Klm", "Nop"};
then you have to write
char * ( *p1 )[sizeof( names ) / sizeof( *names )] = &names;
If you want to create a pointer that points to the elements of the array then you indeed should write
char **p1 = names;
In this case pointer p1 is initialized by the address of the address of the first character of string literal "Abc".
So for example expression *p1 will contain the value of the first element of array names that in turn (the value) is the address of the first character of string literal "Abc" and has type char *.
If you will apply dereferencing the second time **p1 you will get the first character of the string literal itslef that is 'A'.
For example
printf( "%c\n", **p1 );
To make it more clear let's consider a general situation.
If you have an array with elements of type T like this
T a[N];
then this array in expressions is converted to pointer to its first element that will have type T *. So if you want to declare such a pointer yourself you should write
T *p1 = a;
This record is equivalent to
T *p1 = &a[0];
In your original example type T corresponds to type char * - the type of the elements ofarray names. So after substitution char * for T you will get
char * *p1 = names;
^^^^^^
T
EDIT: Thanks to the comment, the array is actually bound here: because the compiler can deduce its size from the initializers.
From its declaration, names is: an array of pointers to char. A bound array decays to a pointer to its first element. Elements of names being pointer to char, when used in an expression names is implicitly converted to a pointer to a pointer to char.
This is why you can assign names in your second line:
char **p1 = names;
So p1 points to the first element in names, which for most practical purposes is like pointing to the array (in memory, an array being juxtaposed objects). Technically, you are pointing to the first element though.
Im new to C programming and I'd like to know how does a pointer constant differ from a constant variable in this case:
#include <stdio.h>
int main(void)
{
int cnt = 0;
char val;
char mystr[20] = “hello there!”;
char *p_str2, str2[20] = “zzzzzzzzzzzzzzzz”;
char* p_mystr = mystr;
p_str2 = str2;
while (*p_mystr != 0x00)
{
val=*p_mystr++;
cnt++;
}
return 0;
}
also, how does mystr differ from mystr[2] (what data type is each variable) and is there anything wrong with p_mystr = mystr[2]; could this be written better (ie: why is *p_mystr= mystr[2]; correct)?
Except when it is the operand of the sizeof or unary & operators, an expression of type "N-element array of T" will be converted 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. The result is not an lvalue, meaning it cannot be the target of an assignment.
So, given the declaration
char mystr[20] = "hello there!";
the following are all true:
Expression Type Decays to Result
---------- ---- --------- ------
mystr char [20] char * address of mystr[0]
&mystr char (*)[20] n/a address of mystr
*mystr char n/a value of mystr[0], or 'h'
mystr[i] char n/a i'th character
&mystr[i] char * n/a address of mystr[i]
sizeof mystr size_t n/a 20 (number of bytes in array)
The address of the array is the same as the address of the first element of the array (no storage is set aside for a mystr variable separate from the array elements themselves), so the expressions mystr, &mystr and &mystr[0] all return the same value, but the types of the expressions are different; mystr and &mystr[0] both have type char *, but &mystr has type char (*)[20], or "pointer to 20-element array of char".
The results for str2 are the same.
Given the declaration
char *p_mystr;
we get the following
Expression Type Result
---------- ---- ------
p_mystr char * value in p_mystr
*p_mystr char value of character pointed to by p_mystr
&p_mystr char ** address of p_mystr variable
sizeof p_mystr size_t number of bytes in pointer value
The table for p_str2 is the same.
Now it's a matter of matching up types. p_mystr = mystr works because both expressions have type char *; p_mystr winds up pointing to mystr[0]. Similarly, *p_mystr = mystr[2] works1 because both expressions have type char. Same for val = *p_mystr++, although note in this case that *p_mystr++ is parsed as *(p_mystr++); the increment will be applied to the pointer value, not the character value.
Note that an expression like p_mystr = &mystr; should get you a diagnostic to the effect that the types don't match.
Your question title mentions const pointers and variables, although that doesn't appear in the question body. Basically, for any type T:
T *p0; // p0 is a non-const pointer to non-const T
const T *p1; // p1 is a non-const pointer to const T
T const *p2; // p2 is a non-const pointer to const T
T * const p3; // p3 is a const pointer to non-const T
const T * const p4; // p4 is a const pointer to const t
T const * const p5; // p5 is a const pointer to const t
Which breaks down as:
You can write to p0 (change it to point to something else) and *p0 (change the thing being pointed to);
You can write to p1 and p2 (change them to point to something else), but you cannot write to *p1 or *p2 (cannot change the thing being pointed to);
You cannot write to p3 (cannot change it to point to something else), but you can write to *p3 (change the thing being pointed to);
You cannot write to p4 or p5 (cannot change them to point to something else), nor can you write to *p4 or *p5 (cannot change the thing being pointed to).
So, if you declared something like
const char *cptr = mystr;
you could not modify the contents of mystr through the cptr variable, even though mystr is not declared const itself.
Note that trying to go the other way, such as
const int foo = 5;
int *fptr = (int *) &foo;
*fptr = 6;
invokes undefined behavior; it may or may not work, depending on the implementation (the language definition allows implementations to put const-qualified objects in read-only memory).
1. If p_mystr is pointing somewhere valid, that is.
Both your variables mystr and str2 are character arrays stored on the stack. There's nothing "constant" here, except the string literals used to initialize your character arrays.
p_mystr is a pointer, mystr[2] is a character. Where is your *p_mystr= mystr[2]; supposed to be? It better not be before p_mystr's initialization to a valid address.
You just asked a mouthful!
A pointer is a very different type to a simple data type (a char * compared to a char). A char just has a single value e.g. 'a'. You can think of a pointer as a memory address - it means, go to the memory address 0x0123F1A and treat what you find there as a char. Pointers can be tricky to get your head around so it's worth reading up on e.g. here
mystr is an array of characters. In some ways it will behave like a pointer to the first item in the array, but it is genuinely a distinct type. mystr[2] has type char - it is the char found at index 2 in the array (i.e. the third char since array indices start at 0).
There is nothing wrong with p_mystr = mystr - it is safe to assign from a char-array to a char-pointer, and the meaning is to make the pointer point to the first item in the array.
*p_mystr=mystr[2] means something else. The * operator means "the value pointed to", so what this means is "in the memory address where p_mystr is pointing, copy the character mystr[2]"
I read this in my book (and many sources on the internet):
The array variable points to the first element in the array.
If this true, then the array variable and the first element are different. Right?
It means by below code, it will produce two different results:
int main(){
char msg[] = "stack over flow";
printf("the store string is store at :%p\n",&msg);
printf("First element: %p\n",&msg[0]);
}
But I receive the same results for the two cases. So, by this example, I think we should say: the array variable is the first element. (because it has the same address)
I don't know if this true or wrong. Please teach me.
The array variable signifies the entire memory block the array occupies, not only the array's first element. So array is not the same as array[0] (cf. sizeof array / sizeof array[0]). But the array's first element is located at the same memory address as the array itself.
Saying the array points to the first element is also incorrect, in most circumstances, an array expression decays into a pointer to its first element, but they are different things (again cf. sizeof for example).
They point to the same address, i.e. printf will show the same value but they have different types.
The type of &msg is char(*)[16], pointer to array 16 of char
The type of &msg[0] is char *, pointer to char
A cheap way to test this is to do some pointer arithmetic. Try printing &msg + 1.
This C FAQ might prove useful.
The array variable is the whole array. It decays into a pointer to the first element of the array.
If you look at the types:
msg is of type char [16]
&msg is of type char (*)[16]
&msg[0] is of type char *
So in a context where msg can decay into an array, for example when passed as an argument, its value would be equal to &msg[0].
Let me draw this:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+--+
|s|t|a|c|k| |o|v|e|r| |f|l|o|w|\0|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+--+
Imagine the starting point of this array, where 's' is located is address 0x12345678.
msg itself, refers to the whole 16 bytes of memory. Like when you say int a;, a refers to 4 bytes of memory.
msg[0] is the first byte of that 16 bytes.
&msg is the address where array begins: 0x12345678
&msg[0] is the address of first element of array: 0x12345678
This is why the values of &msg and &msg[0] are the same, but their types are different.
Now the thing is, msg by itself is not a first class citizen. You cannot for example assign arrays. That is why, in most of the cases, the array will decay into its pointer.
If you know function pointers, this is very similar:
int array[10];
int function(int);
In int *var = array, array decays to a pointer (&array)
In void *var = function, function decays to a pointer (&function)
Note that, in case of function pointers, we like to keep the type, so we write:
int (*var)(int) = function;
Similarly, you can do with arrays:
int (*var)[10] = array;
char myChar = 'A'
char msg[] = 'ABCDEFGH'
When you type myChar you get value.
But with msg you get pointer to first char(for values you have to use msg[x])
msg = &msg[0]
This can help you to understand, I think.
Look at it this way:
&msg = 0x0012
&msg[0] = 0x0012
&msg[1] = 0x0013
In this case &msg[1] is pointing to msg+1. When you reference &msg or &msg[0] you are referring to the same address of memory because this is where the pointer starts. Incrementing the array variable will increment the pointer by +1 since a char variable is only 1 byte in size.
If you do the same trick with say an integer you will increment the pointer by +4 bytes since an integer is 4 bytes in size.
When you use an array expression, the compiler converts it to a pointer to the first element. This is an explicit conversion specified by the 1999 C standard, in 6.3.2.1 3. It is a convenience for you, so that you do not have to write &array[0] to get a pointer to the first element.
The conversion happens in all expressions except when an array expression is the operand of sizeof or the unary & or is a string literal used to initialize an array.
You can see that an array and its first element are different by printing sizeof array and sizeof array[0].
In most circumstances, an expression of array type ("N-element array of T") will be replaced with / converted to / "decay" to an expression of pointer type ("pointer to T"), and the value of the expression will be the address of the first element in the array.
So, assuming the declaration
int a[10];
the type of the expression a is "10-element array of int", or int [10]. However, in most contexts, the type of the expression will be converted to "pointer to int", or int *, and the value of the expression will be equivalent to &a[0].
The exceptions to this rule are when the array expression is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration.
So, based on our declaration above, all of the following are true:
Expression Type Decays to Value
---------- ---- --------- -----
a int [10] int * address of the first element of a
&a int (*)[10] n/a address of the array, which is the
same as the address of the first
element
&a[0] int * n/a address of the first element of a
*a int n/a value of a[0]
sizeof a size_t n/a number of bytes in the array
(10 * sizeof (int))
sizeof &a size_t n/a number of bytes in a pointer to
an array of int
sizeof *a size_t n/a number of bytes in an int
sizeof &a[0] size_t n/a number of bytes in a pointer to int
Note that the expressions a, &a, and &a[0] all have the same value (address of the first element of a), but the types are different. Types matter. Assume the following:
int a[10];
int *p = a;
int (*pa)[10] = &a;
Both p and pa point to the first element of a, which we'll assume is at address 0x8000. After executing the lines
p++;
pa++;
however, p points to the next integer (0x8004, assuming 4-byte ints), while pa points to the next 10-element array of integers; that is, the first integer after the last element of a (0x8028).