3

i am a litte confused by the location in memory of a pointer which points to the beginning of an array. From my understanding arrays and pointers can use the same functions like *, & and []. So if i create a char array, i understand that: buffer == &buffer[0].

So the arrayname without brackets is like a pointer which contains the address of the first entry of the array, right?

But when i try to find out the address of the pointer(the adress where &buffer[0] is stored in) it will give me the same value which is stored in the pointer(&arrayname[0]). How can that be? How can the same address in virtual ram contain a address and the value of buffer[0] (which is in the code below equal to 'H')?

#include <stdio.h>
#include <windows.h>

void main() {

  char buffer[] = "Hello";

  printf("Address buffer: %d\n", &buffer);
  printf("Value buffer: %d\n", buffer);
  printf("Address buffer[0]: %d\n", &buffer[0]);
  printf("Value buffer[0]: %c\n", buffer[0]);
  printf("Address buffer[1]: %d\n", &buffer[1]);

  system("pause");
}

So basically i am confused by the first output. Shouldn't it be diffrent from the second one? Thank you very much for your explanation...

Regards

alk
  • 69,737
  • 10
  • 105
  • 255
user2352375
  • 55
  • 1
  • 6
  • 4
    Please read a good C (or C++) programming book. They explain all the details. (basically, arrays can be decayed to pointers). And use `%p` to `printf` pointers. – Basile Starynkevitch Nov 19 '13 at 21:02
  • @BasileStarynkevitch That's not what he's asking. – SwiftMango Nov 19 '13 at 21:03
  • To print out addresses use the `%p` conversion specifier. – alk Nov 19 '13 at 21:03
  • 2
    possible duplicate of [Isn't an array/arrayname always a pointer to the first element in C?](http://stackoverflow.com/questions/1845594/isnt-an-array-arrayname-always-a-pointer-to-the-first-element-in-c) – SwiftMango Nov 19 '13 at 21:05
  • 1
    Already answered here: http://stackoverflow.com/questions/2528318/how-come-an-arrays-address-is-equal-to-its-value-in-c – Kissiel Nov 19 '13 at 21:07
  • Ok thank you all, so in short & operator does not work as expected with the array itself, but what can i do then if am interested in the address where the adress of the first entry is stored in? Is there a way to find out? – user2352375 Nov 19 '13 at 21:33

2 Answers2

9

Except when it is the operand of the sizeof 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 of the array.

Assume the following code:

char buffer[] = "Hello";
...
printf( "%s\n", buffer );

In the call to printf, the expression buffer has type "6-element array of char"; 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 ("decays") to an expression of type "pointer to char" (char *), and the value of the expression is the address of the first element in the array.

Now, change the printf call to

printf( "%p", (void *) &buffer );

This time, buffer is the operand of the unary & operator; the automatic conversion to type "pointer to char" doesn't occur. Instead, the type of the expression &buffer is "pointer to 6-element array of char", or char (*)[6]1 (the parentheses matter).

Both expressions yield the same value -- the address of the array is the same as the address of the first element of the array -- but the types of the two expressions are different. This matters; char * and char (*)[6] are not interchangeable.

So, why does this funky conversion magic exist in the first place?

When Dennis Ritchie was initially designing C, he was basing his design on an earlier language named B (go figure). When you allocated an array in B, like so:

auto arr[N];

the compiler would set aside N elements for the array contents, along with an additional cell that stored an offset to the first element of the array (basically a pointer value, but without any sort of type semantics; B was a "typeless" language). This additional cell would be bound to the variable arr, giving you something like the following:

          +---+
arr:      |   | --+
          +---+   |
           ...    |
          +---+   |
arr[0]:   |   | <-+
          +---+
arr[1]:   |   |
          +---+
arr[2]:   |   |
          +---+
 ...       ...
          +---+
arr[N-1]: |   |
          +---+

Ritchie initially kept these semantics, but ran into issues when he started adding struct types to C. He wanted struct types to encode their bytes directly; IOW, given a type like

struct {
  int inode;
  char name[14];
};

he wanted a 2-byte integer immediately followed by a 14-byte array; there wasn't a good place to stash the pointer to the first element of the array.

So he got rid of it; instead of setting aside storage for a pointer to the first element of the array, he designed the language so that the location of the array would be computed from the array expression itself. Hence the rule at the beginning of this post.


1. The %p conversion specifier expects a void * expression as its corresponding argument, hence the cast.
John Bode
  • 119,563
  • 19
  • 122
  • 198
  • WOW your answer really impressed me, very well explained, thank you very much for taking the time to answer. Regarding the whole "compute from array expression" thing, can you give me please a link or name literature regarding this point? – user2352375 Nov 20 '13 at 00:04
  • @user2352375: Well, you can start with the [latest standard](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf) (online draft); section 6.3.2.1 is the most relevant. There's also [this paper](http://cm.bell-labs.com/cm/cs/who/dmr/chist.html) by Ritchie describing how he developed C. – John Bode Nov 20 '13 at 14:59
-2

This is wrong:

printf("Address buffer: %d\n", &buffer);
printf("Value buffer: %d\n", buffer);

Correct code assuming array as a pointer would be:

printf("Address buffer: %p\n", (void*) buffer); 
printf("Value buffer: %d\n", *buffer);

You can translate array[x] as *(array + x) that means:

read the memory zone pointed by array + x of its element size

Johan
  • 3,728
  • 16
  • 25
  • 1
    No you should use `%p` to `printf` pointers (and then it is better to explicitly cast them to `void*`) – Basile Starynkevitch Nov 19 '13 at 21:04
  • Sorry maybe my output was a bit misleading: By "value buffer:" i meant the value buffer by itself is equal to, so in this case a address, not the value the address is pointing to. – user2352375 Nov 19 '13 at 21:29