views:

163

answers:

5

The following code manipulates pointers to point at the same location; I'm puzzled about why when I ran the code, the output didn't show value coinciding.

#include "stdio.h"  
main()  
{  
int i=3,*x;  
float j=1.5,*y;  
char k='c',*z;  

x=&i;  
y=&j;  
z=&k;  

printf("\nAddress of x= %u",x);  
printf("\nAddress of y= %u",y);  
printf("\nAddress of z= %u",z);  

x++;  
y++;y++;y++;y++;  
z++;  

printf("\nNew Address of x= %u",x);  
printf("\nNew Address of y= %u",y);  
printf("\nNew Address of z= %u",z);  

printf("\nNew Value of i= %d",i);  
printf("\nNew Value of j= %f",j);  
printf("\nNew Value of k= %c\n",k);  
}  

Output:

Address of x= 3219901868
Address of y= 3219901860
Address of z= 3219901875
New Address of x= 3219901872
New Address of y= 3219901876
New Address of z= 3219901876
New Value of i= 3
New Value of j= 1.500000
New Value of k= c

The new address of variable y and z are same. How can two variables have same address and et have different values? Note: I used gcc compiler on Ubuntu 9.04

+12  A: 

What you are printing is not the address of x/y/z, but rather the address they are pointing at. Then, by modifying the pointers (using ++) you eventually get y and z to point at the same address in memory.

Regarding the values - first thing you should notice that you don't actually change the values of j and k, and by the time you print those values the pointers no longer point to them.

Second thing is, even if you did print the value that the pointers point to, you would still get a different value since in one case the data would be interpreted as a float and in the other as a char.

Tal Pressman
Thanks a lot. Got the mistake I was commiting.
Mohit
A: 

Incrementing pointers this way is only useful if your pointer points to an element in an array.

In fact, incrementing a pointer just increases its value by the size indicated by the type of the pointer, so:

  • incrementing a char-pointer will add 1 to the address
  • incrementing a long-pointer will add 4 to the address (on systems where a long is 4 bytes)
  • and so on
Patrick
*the size the element is pointing to* - better, by the size indicated by the type of the pointer.
Charles Stewart
Thanks, I edited the answer to make this clearer.
Patrick
It may be valid (heck, even useful in extreme ciscumstances) if your pointer is part of a struct/union. But just incrementing the pointer past the boundaries of the object it points to will yield an undefined behaviour (ok, in most cases the pointer will be incremented like you say - but it is not *guaranteed* to do so! In fact, on certain embedded systems, some buffers may have a "modulo addressing" logic, where if you increment the pointer past the end of the buffer it will "wrap around" to the beginning).
Virgil
A: 

Ah. The dangers of pointer arithmatic.

So y = &j sets pointer y to tha current address of float "j"

then you say y++ as you have defined y as a float pointer this is interpreted as add the length of a float variable to pointer y.

However you have only defined one floating point "j" so y is now pointing at whatever has been allocated after "j" -- in this case it happens to be the address of the "k" variable which was defined immediatly after -- but in practice it could be anything or nothing.

Had you defined "j" as an array of floating points it would have pointed to the second entry in the array equivalent to j[1]. Incendently C will also allow you to use j[1] even though you have not defined j as an array!

James Anderson
C does not allow you to subscript values which are neither arrays nor pointers. Perhaps you were thinking of `1[x]` being the same as `x[1]` where `x` is a pointer or array.
Pete Kirkham
I think James Anderson is right. But for the last paragraphe I think your are mixing j and y. In C y[1] is allowed.But a cast is needed for j: ((int*)j)[] but it make no sense.
mathk
A: 

Also, while it is not the case in your examples, two variables may (appear to) have the same address but different values. Assuming that you did:

void display_addr_and_val(const int& var){
  printf("Addr:%p  Val:%d\n",&var, var);
}

void main(){
int x=0;
int y=1;

display_addr_and_val(x);
display_addr_and_val(y);
}

.. you could theoretically end up with the same address shown for both x and y (if you turn on optimization) . Because the parameter of "display_addr_and_val" is a const reference, the code can be rewritten as:

void display_addr_and_val(const int& var){
  printf("Addr:%p  Val:%d\n",&var, var);
}

void main(){
int x=0;
display_addr_and_val(x);

int y=1;
display_addr_and_val(y);
}

now, in this version of the code, you may see that there is no overlap in the lifetime of "x" and "y". Which means that in fact the compiler may choose to use the same stack slot for both of them.

Granted, this doesn't happen very often, but there's not theoretical reason why it shouldn't happen - so the bottom line is that you should use extreme caution when you assume anything about the address of variables - especially local ones (e.g. don't assume that their addresses will be allocated in a given order, or that all distinct variables will use distinct addresses)

Virgil
A: 

It's simple pointer math. the address of the float is incremented at least by sizeof(float), (it should be 4 but you have an increment of 16, it depends on the hardware and the real size used to store floats) while the address of char is incremented by sizeof(char) (1)

you have that y + 16 = z + 1 which is not surprising, remembering that "the next float" (the "things" y now points to) is not indeed a float, but the memory location after the float and so it is for z (it'll point not to a char);

it just means that the float location is 15 bytes "before" the char location. I.e. y + 15 = z.

EDIT: with y I always mean the address of the float taken with &, and so for z...: i.e. before you incrmented them. y+16 is the incremented value of y (after you did y++) and z+1 the incremented value of z after z++.

EDIT 2: dumb me, I did not note that you increment y 4 times! so sizeof(float) is 4, 4*4= 16 ... ! and it is 4 on your machine too (as expected by IEEE for single precision fp numbers...) and so it means that y + (sizeof(float)*4 = z + sizeof(char) ... it still means y location is 15 bytes before z (the address of the char)

ShinTakezou