1
struct Student{

    int roll;
    char name[8];
    float marks;
};

void main(){

    struct Student stu[5] = {{10,"xyz",30},{15,"abc",50},{20,"lmn",70}};
    
    printf("%d \n", (*stu).roll);
    printf("%d \n", (*(stu+1)).roll);

    printf("%x %x\n", (*stu), (*(stu+1))); // <- here (a)
    printf("%x \n", (*(stu+1))); // <-here (b)
    printf("%x \n", (stu));
    printf("%x \n", (stu+1));

}
  1. why (*(stu+1)) printing different addresses in (a) and (b)?
  2. why address of (*(stu+1)) in (b) and address of (*stu) same ?

// --------------------

here is output i am getting

10
15
351ff8c0 351ff8b0
351ff8c0
351ff8d0 
351ff8e0
yogesh
  • 19
  • 3
  • 3
    (1) This can't be your actual code (missing a `{` in the structure definition). (2) `*stu` is not an address of a structure ... it is a structure. – Adrian Mole Jul 16 '22 at 07:14
  • 1
    Can't reproduce: this isn't your actual code. You are using the wrong format spec for a pointer anyway, so the result is undefined. – Weather Vane Jul 16 '22 at 07:14
  • 2
    (3) As soon as you pass the wrong type of argument to `printf` for the given format specifier(s), then you have undefined behaviour. After that, all bets are off. And there is no format specifier that expects a `struct Student` as its corresponding argument. – Adrian Mole Jul 16 '22 at 07:17
  • 1
    This codes outputs at (a) 10 from `*(stu)` and at (b) 15 from `*(stu+1)` the first data of each element, not addresses. – Weather Vane Jul 16 '22 at 07:19
  • @WeatherVane Hmm. In the third and fourth calls to `printf`, the arguments passed will be whole structures. Serious UB ensues ... – Adrian Mole Jul 16 '22 at 07:21
  • @AdrianMole, yes I already modified the comment, and mentioned UB earlier. – Weather Vane Jul 16 '22 at 07:22
  • Others have already pointed out a couple of things. I request you to please modify your question & add more clarity. Also, in your code if you want to print memory addresses, you will need to use '&' (ampersand) operator. I'm able to get same memory addresses employing it, considering that's the desired result. – Rahul Jul 16 '22 at 07:24
  • 1
    @Rahul subject to certain things. When passing an array to a function it automatically decays to a pointer to its first element. – Weather Vane Jul 16 '22 at 07:25
  • what I actually want to do is print address of elements of stu as stu is an array – yogesh Jul 16 '22 at 07:30
  • The address of the first member of the second struct is `&stu[1].roll`. – Weather Vane Jul 16 '22 at 07:33
  • @WeatherVane yes. It's a pointer to first element. Hence it's printing 10 and 15 as you said earlier. If we want their memory addresses, we'll need to employ ampersand to fetch memory addresses. e.g., (&(*(stu + 1))) – Rahul Jul 16 '22 at 07:34
  • 1
    Rahul passing `stu` to printf passes the address of the first element without using the `&`. Passing `stu+1` passes the address of the second array element without using `&`. – Weather Vane Jul 16 '22 at 07:36
  • @WeatherVane yes. But in the posted code, dereferencing operator (*) has been used first already in the concerned statements. I replied in that context & hence suggested for question modifications. – Rahul Jul 16 '22 at 07:40
  • @Rahul, sorry, I was taking up your comment "in your code if you want to print memory addresses, you will need to use '&' (ampersand) operator" which is incorrect. You don't always need to. You need to when you want the address of a specific member, which the OP does not do. – Weather Vane Jul 16 '22 at 07:43

2 Answers2

2

Because those printf calls aren't printing the addresses of stu elements, they're printing the addresses of struct Student copies which have been made on the call stack for argument-passing.

Here's why:

  1. printf and the "%x" format do not tell the language to take the address of their argument. They just take whatever they got, and interpret it as an integer, and print that integer as hex.

  2. *stu is not an address, it is the first struct Student in stu. stu is an array, which for most purposes is an address, and * goes the other way: it gets the value at an address, not the address of a thing.

  3. So per the second point, when you do *stu, you get the first struct Student. When you do *(stu+1), you get the second struct Student.

    But per the first point, you aren't getting their addresses, you're just getting the structs themselves, and passing those structs - all their contents to printf.

    So why do they still look like addresses?

  4. Well, how is a struct type passed to printf?

    Turns out there are multiple possible ways, and the exact way depends on your computer, operating system, and compiler.

    One way, the way your system seems to be doing, is to make a new copy of each struct argument onto the stack, and then pass the address of that copy to the function as the "actual" machine-level argument. Then the function, which is presumed to know what to do with that argument of that type, is expected to be compiled to look through that address to get the "actual" C-level struct argument.

  5. But of course printf doesn't know what to do with your struct type argument - your compiler knows, because it sees the call to printf, that it needs to do this copy-to-stack-and-pass-the-address-of-copy trick - but the printf function doesn't know that its machine-level argument is actually an internal address argument, it just knows that you told it (by writing "%x") that this argument is an integer. So printf prints that internal implicit incidental copy's address.

  6. So why are the addresses between calls different?

    Because each call gets new copies, but the stack space is reused, and nothing changes the stack layout between the two calls, so the first argument to both printf calls gets the same address, then if there's a second argument it gets an adjacent address, and so on.

    So printf("%x %x\n", *stu, *(stu+1)) gives the first address to the copy of *stu, and the second address to the copy of *(stu+1).

    But printf("%x\n", *(stu+1)) gives the first address to its copy of *(stu+1).

(Notice also that the addresses from those two printf lines in your example are different by the same small amount from the addresses in the next two printf lines. This is because the next two lines are correctly getting the addresses of elements in stu like you wanted, and stu is also allocated on the stack, as is typical for function-scoped variables. This was a big clue for me in figuring out what's happening.)

mtraceur
  • 3,254
  • 24
  • 33
1

The printf() functions aren't printing the actual addresses of the structure rather the copies of struct student which have been made on the call stack to service the printf() function

So, the line

printf("%x %x\n", (*stu), (*(stu+1)));

Simply prints the first 2 created addresses on the stack.

To better illustrate if we consider the statement

printf("%x %x\n", (*(stu+5)), (*(stu+4)));
printf("%x %x\n", (*(stu+3)), (*(stu+2)));

These two should print the same addresses as they are simply the first 2 copies created on the stack to service the printf() function

The output I got was

225ffae0 225ffad0
225ffae0 225ffad0