-1

I am trying to cin a value to the birthMonth variable in my structure. My understanding is that structure members are stored sequentially. If that is the case, I cannot find out why using the line

cin >> *((short*)((people) + sizeof(Person::name)));

does not store the input value into the structure element. Am I wrong about the members of a structure being stored sequentially?

main.cpp

#include <iostream>
using namespace std;

struct Person {
    char name[15];
    short birthMonth;
};
int main() {
    Person people[2];
    cout << "Birth Month: ";
    cin >> *((short*)(people + sizeof(Person::name)));
    cout << people[0].birthMonth;
}

Sample Run:

Birth Month: 7
0
Program ended with exit code: 0
KhanKhuu
  • 177
  • 11
  • What is the goal? You can't really do this and I don't understand what the purpose is – UnholySheep Jul 13 '18 at 19:28
  • 3
    There might be padding between the members, especially if one member has an uneven size, like 15. Why not just `cin >> people[0].birthMonth;`? Also, `people + 15` moves 15 whole elements further in memory, not 15 bytes. Pointers are tricky! – Bo Persson Jul 13 '18 at 19:29
  • @Unholy Sheep Honestly, I just wanted to practice using pointers. I am a student so I thought it would be cool to apply my (still growing) understanding of pointers to this program. Could you explain what is wrong about it? I get that it is type punning but it brought up an interesting question about how variables are stored within a structure that led to this. – KhanKhuu Jul 13 '18 at 19:33
  • @Bo Persson Ah yes I see that now. Even so, when I put person in parens to prevent the pointer arithmetic I get the same issue. So the explanation of padding would make sense. Thank you for the insight Bo Persson. – KhanKhuu Jul 13 '18 at 19:35
  • Also note that `(people + sizeof(Person::name))` gives you a pointer to a non-existent 16th element of your `people` array (and not a pointer to after the `name` member. – UnholySheep Jul 13 '18 at 19:35
  • @UnholySheep I see that now. When I separate it like ((people) + sizeof(Person::name)) the value is still not stored, but thank you. – KhanKhuu Jul 13 '18 at 19:38
  • It's the same with or without the extra parentheses. You would need a cast to get a pointer after the `name` member: `reinterpret_cast(people) + sizeof(Person::name)` – Miles Budnek Jul 13 '18 at 19:49
  • @Miles Budneck I tried using reinterpret_cast in that way and same issue, but as many of the answers have pointed out the issue has to do with the alignment of the memory, padding, other things I am studying now. Thanks for the comment nonetheless – KhanKhuu Jul 13 '18 at 20:22

2 Answers2

3

Because of memory alignment and padding, C++ actually doesn't give any guarantee that a struct's member is located according to the cumulative size of previous members. If you're trying to write to the first Person's birthMonth, it's as simple as:

cin >> people[0].birthMonth;

EDIT: to actually address the question's title, if you want an int* pointer to a specific person's birthMonth, it's done using the address-of operator:

int* birthMonth_ptr = &people[0].birthMonth;

But if you want a pointer to any Person's birthMonth member, you can use a pointer-to-member:

// Note that no Person object is used when defining
int Person::*member_ptr = &Person::birthMonth;

// To use the pointer though, you need an object
int a_persons_birthdate = people[0].*member_ptr;

Also note that a pointer-to-member is typed differently from a regular pointer, and can't be cast to one.

alter_igel
  • 6,899
  • 3
  • 21
  • 40
1

To understand why your code does not work, add a few lines to print couple of addresses.

short* ptr1 = (short*)(people + sizeof(Person::name));
short* ptr2 = &(people[0].birthMonth);
std::cout << "ptr1: " << ptr1 << ", ptr2: " << ptr2 << std::endl;

You will notice that due to alignment requirements, ptr1 and ptr2 are different.

Further reading: https://en.wikipedia.org/wiki/Data_structure_alignment.

R Sahu
  • 204,454
  • 14
  • 159
  • 270