0

I came across this very strange thing in this code.

#include <stdio.h>

int main()
{
    float d = 12.432;
    float *pd = &d;
    printf("Value of d is %f\n", *pd);
    printf("Address of d is %p\n", pd);
    printf("Address of d+1 is %p\n", (pd + 1));
    printf("Value at d+1 is %f\n", *(pd + 1));

    int c = 1;
    int *yh = &c;
    printf("Value of c is %d\n", *yh);
    printf("Address of c is %p\n", yh);
    printf("Address of c+1 is %p\n", (yh + 1));
    printf("Value at c+1 is %d\n", *(yh + 1));

    return 0;
}

When I run this snippet in my machine the addresses of d+1 and c come out to be the same When I run on repl.it or some online compiler, I get different addresses as it should give. What is the issue?

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • 1
    A pointer to a single object and a pointer to an array of objects looks the same. The programmer has the burden to keep straight if a pointer is to an object or if a pointer is to an array (...and the length of that array). – Eljay May 27 '21 at 12:24
  • 3
    `printf("Value at d+1 is %f\n", *(pd + 1));` is UB. – Sourav Ghosh May 27 '21 at 12:24
  • 3
    They could be same or they could not. It depends at which addresses your compiler puts the variables. – Jabberwocky May 27 '21 at 12:24
  • 1
    Why do you think they should be different? `d + 1` is not a valid pointer to `float` but in practice might be the place where the compiler allocates `int c`, although you can't rely on that (can't dereference said pointer). So don't ;-) – underscore_d May 27 '21 at 12:24
  • 3
    Does this answer your question? [Order of local variable allocation on the stack](https://stackoverflow.com/questions/1102049/order-of-local-variable-allocation-on-the-stack) – Lanting May 27 '21 at 12:25
  • 7
    `(pd + 1)` is a valid address to report, as *one element past the storage allocation* is permitted. But dereferencing that address with `*(pd + 1)` is *undefined*. – Weather Vane May 27 '21 at 12:25
  • pointer in diffrent systems has diffrent size. in 64 bit systems it has size 8 bytes. but int and double has fixed size i think because of that you receive different address. and also all of this variables are in top of stack. – N0ll_Boy May 27 '21 at 12:25
  • 2
    To lower the "noise" you should delete the last printf in both blocks as they are invalid. And they have nothing to do with your question – Support Ukraine May 27 '21 at 12:26
  • What is also undefined is comparing pointers to *different objects*. – Weather Vane May 27 '21 at 12:29
  • 2
    @WeatherVane For relational operators yes, for equality operators no. – dbush May 27 '21 at 12:32
  • See also: https://stackoverflow.com/questions/45966762/can-an-equality-comparison-of-unrelated-pointers-evaluate-to-true – dbush May 27 '21 at 12:50
  • @WeatherVane It's worth noting that `std::less<>()` _et al._ have special magical powers to provide a total ordering for pointers for use in containers, _etc._, even if in general it isn't well-defined to compare unrelated pointers with plain `operator<` and co. – underscore_d May 27 '21 at 14:04
  • @underscore_d perhaps, but this is a C question. – Weather Vane May 27 '21 at 14:08
  • With (pd + 1) and *(pd + 1) you are accessing the memory location that you didn't allocate for your program. But because pd is on the stack of your function frame typically the pd+1 could also be on the same stack frame. But your function doesn't own it in the form of a variable, so leave it alone or otherwise it has the power to crash your program – Jay D May 27 '21 at 20:50

2 Answers2

2

Note: The C standard does not require that pointers are directly related to memory addresses. However, it's how most modern systems work. This answer assumes such a system

in my machine the addresses of d+1 and c come out to be the same

I assume you mean: (the addresses of d)+1 and the address of c come out to be the same.

There is nothing strange about that.

When pd + 1 is equal to yh, it simply means that the integer c is placed in memory just after the float d.

+---------+ <------- pd
|    d    |
+---------+ <------- pd+1 and also yh
|    c    |
+---------+ <------- yh+1

On another system it could be:

+---------+ <------- pd
|    d    |
+---------+ <------- pd+1
| unused  |
+---------+ 
| unused  |
+---------+
| unused  |
+---------+ <------- yh
|    c    |
+---------+ <------- yh+1

in which case pd+1 differs from yh

... I get different addresses as it should give

Both cases are legal. One system may do the first case and another system the second case. So NO, it's not correct that it "should give" different addresses.

BTW:

While it's legal to do pd+1 it's illegal to dereference it like *(pd+1) because there is no float located there. So delete the line printf("Value at d+1 is %f\n", *(pd + 1)); It's illegal and also irrelevant for the question.

The same applies to: printf("Value at c+1 is %d\n", *(yh + 1));

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
  • Ok so if I do something like `*(pd+1)=2.1;` after the 1st block, without declaring a specific variable for it, the value at the address `pd+1` gets re-written by `c`, rendering the 2.1 as useless – Suhel Kapadia May 27 '21 at 13:39
  • @SuhelKapadia Well... In principle yes but... `*(pd+1)=whatever` is illegal because there is no float variable at that address. It is called "undefined bahavior". – Support Ukraine May 27 '21 at 15:19
0

float is a type whose size is 4 bytes.

When you perform pointer arithmetic, you calculate an address shifted from the original address by a number of times the size of the type.

i.e. pd+1 points to an address one float after the variable d.

Typically your compiler may successiveily put all your declared variables in sequence in memory: d, pd, c and yh as they're declared in that order; but there is no guarantee there, it may chose to do otherwise.

If your compiler elects to place the variable d, then the variable c in two contiguous 32-bits space in memory, then typically, the following assertion will be true:

(pd+1) == &c

This seems to be your case. There is no problem with that.