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..