通过指针访问结构

Posted

技术标签:

【中文标题】通过指针访问结构【英文标题】:accessing struct by a pointer 【发布时间】:2021-12-11 00:48:35 【问题描述】:

我目前正在试验指针,我的代码有几个问题

ps。这只是为了试验我不会在任何代码中使用它

#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;

    为什么 std::cout 会使我的程序崩溃?我不得不使用 printf 函数来解决这个问题

    我可以从我的主函数中删除 IntPtr 吗?像delete[] (long long int*)*Adress; 这样的东西然后创建新的?喜欢:

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

编辑:这只是一个关于如何在strcut obj 中访问int* IntPrt 的实验,当它是private: 时,我不会使用其他方法。

即使使用 delete[]new 的代码在我的编译器上也能正常工作

谢谢大家的解释

【问题讨论】:

为什么要投那么多?为什么要手动管理内存? &amp; MyStruct; //pointer to a struct - 是的 - 但是你转换成 long long* - 为什么?然后您取消引用该指针并使用它来形成您取消引用的另一个指针。 未定义的行为。丰富。 您的代码有强制转换。演员阵容很差。取下石膏。修复警告。 (*Adress + sizeof(int)) 不要这样做(除非你真的了解内存中字节的底层布局,即使那样通常还有更好更安全的方法) @TheUndeadFish 不,永远不要这样做。这是未定义的行为,即使做得“正确”。 long long int* Adress 不是指向结构或obj 的指针。它是一个指向 long long int 的指针。 【参考方案1】:

即使您的代码中的语法错误已修复,我怀疑您尝试做的事情的前提仍然存在根本缺陷。获取一个指针,将其转换为表示内存地址的数字,将其移动到另一个对象上并以这种方式访问​​它,这在 C++ 中根本不允许这样做。

编译器可以根据程序从不做这些事情的假设来积极优化代码。因此,即使 if 一个程序在执行此操作时似乎正在运行,但在使用不同的编译器、同一编译器的不同版本或同一编译器上的不同编译设置进行编译时,它也很可能会中断。

那么这对我们程序员意味着什么?指针是内存地址并不意味着我们可以将它们视为内存地址(有一些特定的例外)。

指针指向对象(提醒:即使是简单的int 也是一个对象)。指针指向内存这一事实是实现细节;除非您一次操作一个字节的底层存储的原始字节。

您必须将指针视为:

不指向一个对象,在这种情况下你只能分配、复制或比较它。

指向一个对象,在这种情况下,您也可以使用*-&gt; 取消引用它。

指向作为数组一部分的对象,此时,您可以 还可以使用[] 或指针算法(+- 等...)来访问同一数组中的其他对象。

就是这样。

考虑到这一点,您的代码应该是这样的。这主要是供参考。我知道这不是你想要做的。

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]);

编辑:为了完整起见,这里的代码符合我对您的解释:

#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;

【讨论】:

以上是关于通过指针访问结构的主要内容,如果未能解决你的问题,请参考以下文章

通过指针偏移访问结构变量值

修改矩阵后,通过内存指针(memptr)直接访问犰狳矩阵的条目不起作用

结构体指针

试图通过指针访问嵌套类的成员函数

通过指针的堆数据结构

c++中的多态——通过指针访问函数