1

In the following C code:

char test[] ={'T','e','s','t'};

printf("%d\n",test == &test[0]); // Returns 1 - Okay as array varaible holds address of first element

So shouldn't the following should print the same?:

printf("value of test %c\n", test); // prints - '|' not even in the array
printf("value of test[0] %c\n", test[0]); // prints - 'T'

Not even that, even these prints different values:

printf("value of test %p\n", test); // contains a address 0x7ffee9b22b7c
printf("value of test[0] %p\n", test[0]); // also conatains 0x100

What is happening?

thanks

lynxx
  • 544
  • 3
  • 18
  • 3
    An array variable *does not* hold the address of its first element. An array variable holds the values of all its elements. An array *expression*, in most but not all context, "decays" to a pointer expression that yields the address of its first (0th) element. Read section 6 of the [comp.lang.c FAQ](http://www.c-faq.com/). – Keith Thompson Mar 08 '20 at 04:51
  • Does this answer your question? [Is an array name a pointer?](https://stackoverflow.com/questions/1641957/is-an-array-name-a-pointer) – Avi Berger Mar 08 '20 at 04:55

3 Answers3

2

You sort of answered your own question in the first example:

test == &test[0]

test != test[0] // otherwise, test[0] would have to be equal to &test[0]

I.e., the value of test (interpreted as pointer) equals the address of test[0]. Therefore, your following examples can't be true, since that would mean that for either of those its value would equal its own address, which doesn't make sense!

(Note: The following addresses are examples of course.)

Expression Type Value interpreted as character %c Value interpreted as pointer %p
test char* nonsensical 0x1000
&test char** nonsensical 0x2000
test[0] char T nonsensical
&test[0] char* nonsensical 0x1000
test[1] char e nonsensical
&test[1] char* nonsensical 0x1001
test[2] char s nonsensical
&test[2] char* nonsensical 0x1002
test[3] char t nonsensical
&test[3] char* nonsensical 0x1003

Note: For the purpose of understanding your initial problem, it's OK to look at test as char*, and therefore &test as char**. However, in reality it is a little bit more complex, and test is actually of type char(*)[4]. This makes a difference with sizeof for example.

CherryDT
  • 25,571
  • 5
  • 49
  • 74
  • Is test[0] equivalent to *(test + 0)? So test[0] is the value while test is an address. – lynxx Mar 08 '20 at 05:09
  • Yes. That's right. (Technically, `test` is an array name, but for _most_ intents and purposes it can be interpreted as a pointer, i.e. an address. See "pointer decay" in Louen's answer.) – CherryDT Mar 08 '20 at 05:11
1

you might be confusing yourself with how you are printing. Try this and see if it's easier to follow.

#include <stdio.h>


int main(){

    char test[] = "Test\n\0"; // an array that contains char values
    char *testptr; // a pointer that can point to a place in memory that contains a char value


    printf(test); // by default it will print all of the char values starting with test[0]

    testptr = &test[2]; // the pointer now points to the third position in the char array

    printf(testptr); // print the test array starting with the pointers position

}
0

Pointer decay

While pointers and arrays are different types of variables, the array variable is often implicitly converted as pointer to its first element. This is called array to pointer decay.

This is what is happening in the comparison you make between test and &test[0]: test decays to a pointer which can be compared to &test[0], and their value are equal

What is happening in your printf calls ?

printf("value of test %c\n", test); // prints - '|' not even in the array
printf("value of test[0] %c\n", test[0]); // prints - 'T'

The first ones with the conversion specifier %c converts the argument to unsigned char and prints the character. In the first line you print test as a character and in the second line you print test[0] as a character.

The type of test[0] is indeed a char so the correct character (the T) gets printed. However the type of test is an array of char, which in this case, also decays to a pointer. In your execution of the test this pointer happens have the value of 0x7ffee9b22b7c. This value is then converted to unsigned char so the last byte of your pointer is kept, in that case that's 7c which happens to be the ASCII code for character |.

Note that since it depends on the value of the pointer it is very likely that you will get a different character printed every time you run the program (some of them might even not be printable characters).

The two results are different because they are different things : one is a character and the other is a pointer (in this case a pointer to a character).

test[0] is the value that is contained at the beginning of the array, while test is evaluated as a pointer to the first element (and then forcibly converted to a character). As you noted earlier, the test is equivalent to &test[0] and not to test[0].

test[0] is equivalent to *test (or to *(test + 0)). In general in an array, array[i] will be equivalent to *(array +i).

Louen
  • 3,617
  • 1
  • 29
  • 49
  • Mismatched argument and specifier types in `printf()` lead to undefined behavior, so attempting to print `test` here with `%c` is UB. Note also that _conversion specifiers_ convert values to printed representations, but do not convert the types of the arguments. The lone exception to this rule is the `%c` specifier, which does, as you say, convert its argument to `unsigned char`, but this is after the argument has already been converted to `int` by the _default argument promotions_ (applied to arguments of variadic functions). – ad absurdum Mar 08 '20 at 07:04