Home > Software engineering >  accessing struct by a pointer
accessing struct by a pointer

Time:10-26

Im currently experimenting with pointers and i have several questioins to my code

ps. this is just for experimenting Im not going to use this in any code

#include <iostream>
#include <stdlib.h>
#include <stdio.h>

struct obj
{
    int* IntPtr;
    obj()
    {
        IntPtr = new int[2];
        IntPtr[0] = 123;
        IntPtr[1] = 456;
    }
};

int main()
{
    obj MyStruct;
    long long int* Adress = (long long int*) & MyStruct; //pointer to a struct

    //change value in struct
    *(long long int*)(*Adress   sizeof(int)) = 789;

    std::cout << "get value by pointer: " << (int)*(long long int*)(*Adress   sizeof(int)) << std::endl; //std::cout crashes my program
    printf("get value by pointer: %d\n", (int)*(long long int*)(*Adress   sizeof(int)));
    printf("get value from struct: %d\n", MyStruct.IntPtr[1]);

    return 0;
}
  1. why does std::cout crashes my program? I had to use printf function to fix this issue

  2. can i delete IntPtr from from my main function? something like delete[] (long long int*)*Adress; and then create new ? like:

    int* Itemp = new int[5]; *Adress = (long long int)Itemp;

EDIT: this was just an experiment on how to access int* IntPrt in strcut obj when it is private: i wouldnt use this method othersise.

the code even with the delete[] and new worked fine on my compiler

thanks everyone for the explanation

CodePudding user response:

Even if the syntax errors in your code were fixed, the premise of what I suspect you are trying to do would still be fundamentally flawed. Taking a pointer, converting it to a number representing a memory address, shifting it around to land on another object and accessing it this way is simply not something you are allowed to do in C .

Compilers are allowed to, and actively do, optimize code based on the assumption that the program never does such things. So even if a program appears to be working while doing this, it could very well break when compiled with a different compiler, a different version of the same compiler, or different compilation settings on the same compiler.

So what does that mean to us as programmers? Pointers being memory addresses does not mean that we are allowed to treat them like memory addresses (with a few specific exceptions).

Pointers point to objects (reminder: even a simple int is an object). the fact that a pointer points into memory is an implementation detail; unless you are manipulating the raw bytes of the underlying storage a single byte at a time.

You must treat a pointer as either:

  • Not pointing at an object, in which case you can only assign, copy, or compare it.

  • Pointing at an object, in which case you can also dereference it with * or ->.

  • Pointing at an object that is part of an array, at which point, you can also use [] or pointer arithmetic ( , -, etc...) to access other objects in the same array.

That's all.

Taking this into consideration, here's what your code should be looking like. This is mostly for reference. I know that's not what you were trying to do.

struct obj
{
    int* IntPtr;
    obj()
    {
        IntPtr = new int[2];
        IntPtr[0] = 123;
        IntPtr[1] = 456;
    }

    ~obj() 
    {
      // Btw. If you have a new, ALWAYS have a delete, even in throwaway code.
      delete IntPtr[];
    }
};

int main()
{
    obj MyStruct;
    
    // Get a pointer to the struct
    obj* Adress = &MyStruct;
 
    // Change value in struct via the pointer
    obj->IntPtr[1] = 789;
    (*obj).IntPtr[1] = 789;

    std::cout << "get value by pointer: " <<  obj->IntPtr[1] << std::endl; 
    printf("get value by pointer: %d\n", obj->IntPtr[1]);
    printf("get value from struct: %d\n", obj.IntPtr[1]);
}

Edit: For completeness' sake, here's code that does what I interpreted you were going for:

#include <iostream>
#include <cstdint>
#include <cassert>

struct obj {
    int IntData[2];
};

int main()
{
    obj MyStruct;

    // Get a number containing the memory address associated with MyStruct.
    // std::uintptr_t is the integer type of the same size as a pointer
    std::uintptr_t AdressOfMyStruct = (std::uintptr_t)&MyStruct;
    std::cout << "MyStruct lives at: " << AdressOfMyStruct << std::endl;

    // Do the same thing for IntData[1]
    std::uintptr_t AdressOfIntData1 = (std::uintptr_t)&MyStruct.IntData[1];
    std::cout << "MyStruct.IntData[1] lives at: " << AdressOfIntData1 << std::endl;

    // recalculate the address of IntData1 as an offset from MyStruct
    std::uintptr_t AdressOfIntData1Calculated = AdressOfMyStruct   sizeof(int);
    std::cout << "MyStruct.IntData[1] lives at (alt): " << AdressOfIntData1 << std::endl;

    // Verify that IntData[1] is where we expect it to be.
    assert( AdressOfIntData1Calculated == AdressOfIntData1 );

    // ...Everything up to here is valid code...

    // WARNING: this may looks like it works, but it is, in fact, Undefined Behavior.
    int* PtrToIntData1 = reinterpret_cast<int*>(AdressOfIntData1); 
    *PtrToIntData1 = 789;

    // WARNING: This is also undefined behavior.
    std::cout << "get value by pointer: " << *PtrToIntData1 << std::endl; 

    // This is fine, obviously.
    std::cout << "get value from struct: " << MyStruct.IntData[1] << std::endl; 

    return 0;
}
  • Related