Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

starting address of array a and &a

Tags:

c

pointers

In the below two lines,

char a[5]={1,2,3,4,5};
char *ptr=(char *)(&a+1);
printf("%d",*(ptr-1));

This prints 5 on screen.Whereas when use a instead of &a,

char a[5]={1,2,3,4,5};
char *ptr=(char *)(a+1);
printf("%d",*(ptr-1));

This prints 1

Both a and &a are the starting address of the array.So Why is this difference?

Also char *ptr=&a+1;

shows a warning.

like image 717
prem Avatar asked May 01 '13 03:05

prem


People also ask

What is the start address of an array?

Both a and &a are the starting address of the array.So Why is this difference? Also char *ptr=&a+1; shows a warning. @user13267 - a is most definitely not a pointer.

What is the base address of an array in Java?

Element address = b + i*s. // Java Program to Find Address of an Array Element Given the Base Address.

What is meant by base address of an array in C++?

The address of the first element of an array is called the base address of an array. In C++, the first element is always the zero-th element of the array, so in C++ the address of the element at zero subscript is the base element of the array.


3 Answers

Arrays aren't pointers! Read section 6 of the comp.lang.c FAQ for more information.

Let's look at your second case first, since it's the more "normal" and idiomatic looking. Line by line:

  1. You declare an array a containing 5 char elements.
  2. The name of the array (a) decays into a pointer to its first element in this context. You add 1 to that and assign the result to ptr. ptr points to the 2. No cast is necessary, though you have one.
  3. You subtract 1 from ptr and then dereference and print - hence you get the 1.

Now, let's address the first case, again line by line:

  1. You declare an array a containing 5 char elements.
  2. You take the address of a, yielding a char (*)[5] type pointer. You then add 1 to this pointer - because of pointer arithmetic this new pointer pasts to the byte just after 5 in memory. Then you typecast (required, this time) and assign this value to ptr.
  3. You subtract 1 from ptr and then dreference and print. ptr is a char *, so this subtraction simply moves the pointer back by one from "one past the end of a" to point to the last element of a. Hence you get the 5.

Finally, the reason char *ptr=&a+1; gives a warning is because C requires conversions between pointer types to have an explicit cast. As mentioned above, &a is of type char (*)[5], not char *, so to assign that value to a char * variable, you'll need the explicit cast.

like image 145
Carl Norum Avatar answered Nov 06 '22 06:11

Carl Norum


Since you seem totally new to it let me explain it to you in simple terms instead of going for the rigorous explanation.

You see, for your program above, a and &a will have the same numerical value,and I believe that's where your whole confusion lies.You may wonder that if they are the same,the following should give the next address after a in both cases,going by pointer arithmetic:

(&a+1) and (a+1)

But it's not so!!Base address of an array (a here) and Address of an array are not same! a and &a might be same numerically ,but they are not the same type. a is of type char* while &a is of type char (*)[5],ie , &a is a pointer to (address of ) and array of size 5.But a as you know is the address of the first element of the array.Numerically they are the same as you can see from the illustration using ^ below.

But when you increment these two pointers/addresses, ie as (a+1) and (&a+1), the arithmetic is totally different.While in the first case it "jumps" to the address of the next element in the array, in the latter case it jumps by 5 elements as that's what the size of an array of 5 elements is!.Got it now?

  1 2 3 4 5  
  ^               // ^ stands at &a

  1 2 3 4 5
           ^     // ^ stands at (&a+1)

  1 2 3 4 5
  ^              //^ stands at a

  1 2 3 4 5
    ^            // ^ stands at (a+1)

The following will give an error about unspecified bound for array as not explicitly specifying the size as below means the program won't know how many elements to "jump" to when something like (&a+1) is encountered.

char a[]={1,2,3,4,5};
char *ptr=(char *)(&a+1);  //(&a+1) gives error as array size not specified.

Now to the part where you decrement the pointers/addresses as (ptr-1).In the first case, before you come to the decrement part, you should know what happens in the statement above it where it is cast to type char*:

char *ptr=(char *)(&a+1);

What happens here is that you "strip off" the original type of (&a+1) which was type char (*)[5] and now cast it to type char* which is the same as that of a,ie, the base address of the array.(Note again the difference between base address of an array and address of an array.So after the cast and assignment in the above statement,followed by the decrement in printf(), ptr now gives the memory location right after the last element of the array, which is 5.

  1 2 3 4 5
          ^     // ^ stands at location of 5, so *ptr gives 5

So when you dereference the pointer ptr after decrementing it as *(ptr-1) it prints the value of 5 as expected.

Now finally, contrast it with the second case where 1 is printed.Look at the illustration I have given using the symbol ^. When you had incremented a as a+1, it points to the second element of the array, ie 2 and you had assigned this address to ptr.So when you decrement ptr it as (ptr-1), it jumps back one element and now points to the first element of the array ,ie 1.So dereferencing ptr in second case gives 1.

  1 2 3 4 5
  ^            // ^ stands at address of 1, so *ptr gives 1

Hope this made it all clear.

like image 42
Rüppell's Vulture Avatar answered Nov 06 '22 08:11

Rüppell's Vulture


The difference is in the type of the pointer that you get:

  • Array name a by itself represents a pointer to the initial element of the array. When interpreted in that way, e.g. in an expression a+1, the pointer is considered to point to a single character.
  • When you take &a, on the other hand, the pointer points to an array of five characters.

When you add an integer to a pointer, the number of bytes the pointer is moved is determined by the type of the object pointer to by the pointer. In case the pointer points to char, adding N advances the pointer by N bytes. In case the pointer points to an array of five chars, adding N advances the pointer by 5*N bytes.

That's precisely the difference that you are getting: your first example advances the pointer to the element one past the end of the array (which is legal), and then move it back to the last element. Your second example, on the other hand, advances the pointer to the second element, and then moves it back to point to the initial element of the array.

like image 25
Sergey Kalinichenko Avatar answered Nov 06 '22 06:11

Sergey Kalinichenko