繁体   English   中英

使用结构中的指针访问数组

[英]Accessing an array using a pointer in a struct

我想使用 struct 属性访问数组元素。 我可以使用结构指针 ( nameptr) 打印第一个和第二个元素,而必须使用本身是“结构名称”属性的 (uint8_t ptr) 访问剩余的 3 个元素

#include <iostream>

struct name{

    uint8_t b0;
    uint8_t b1;
    uint8_t* ptr;

}*nameptr;

int main()
{
    
    uint8_t arr[]= {1,2,3,4,5};
    nameptr = (name *)arr;
    nameptr->ptr = arr+2;
    printf("%d ", nameptr->b0);           //prints 1
    printf("%d ", nameptr->b1);           //prints 2
    for (int i=2; i<5; i++){
        printf("%d ",*(nameptr->ptr+i));  //expecting to print 3 4 5
    }

    return 0;
}

编译时出现以下错误,请帮助我解决此错误。

*** 检测到堆栈粉碎 ***: ./a.out 终止

1 2 5 0 56 中止(核心转储)

该答案基于问题修订版 6 中的修改后的代码。

如果你有一个name类型的结构,而不仅仅是一个指针,你可以像这样将数组地址分配给指针元素ptr

#include <cstdio>
#include <cstdint>

struct name{

    uint8_t b0;
    uint8_t b1;
    uint8_t* ptr;

}*nameptr;

int main()
{

    uint8_t arr[]= {1,2,3,4,5};
    name name_struct; // actual memory where you can access the structure fields
    nameptr = &name_struct; // pointer now points to a real structure of the correct type
    nameptr->ptr = arr; // assign array to pointer inside structure

    /* For this loop you must know the size of the array the pointer is pointing to.
     * Your code cannot automatically derive this information from the
     * pointer element `ptr` or from the structure like you could with
     * sizeof(arr)/sizeof(arr[0]). */
    for (int i=2; i<5; i++){
        printf("%d ",*(nameptr->ptr+i));  //expecting to print 3 4 5
        // printf("%d ",nameptr->ptr[i]);  // same, but easier to understand
    }

    return 0;
}

问题第 7 版中的代码在几个方面是错误的:

struct name{
    uint8_t b0;
    uint8_t b1;
    uint8_t* ptr;
}*nameptr;

/* Depending on your platform, the structure might be something like this */
struct name_with_padding {
    uint8_t b0; // 1st byte
    uint8_t b1; // 2nd byte
    // uint8_t padding[2]; // 3rd and 4th byte 
    uint8_t* ptr; // 5th to 8th byte
}*nameptr;

uint8_t arr[]= {1,2,3,4,5};

/* This cast is the main error. It will interpret the memory of the array
 * as a structure as shown above which is undefined behavior (and 
 * implementation dependent).
 * It might result in:
 * b0 = 1
 * b1 = 2
 * padding = {3, 4}
 * ptr = value 5 + some (3) bytes after it
 * But it may as well result in other (undefined) behavior.
 */
nameptr = (name *)arr;

/* This may (depending on your implementation) overwrite
 * overwrite the value 5 and the following (3) bytes
 * with the address arr+2
 * so it will change the value of arr[4] and the memory after it
 * This may (or may not) result in a segmentation fauult or stack corruption.
 */ 
nameptr->ptr = arr+2;

该答案基于问题第一版中的原始代码以及我对错误代码背后意图的解释。

另请参阅我基于问题修订版 6 中的代码的其他答案。

结构元素uint8_t* ptr; 是指针,不是数组。 这就是为什么,当做nameptr = (name *)arr; 并取消引用nameptr->ptr ,您将 memory 中的数据解释为地址并尝试访问此地址的 memory。 该地址可能由字节 3、4、5 以及 memory 中的任何内容构成。 (取决于实现)

原始代码的此修改版本可能会执行您想要的操作,但是将数组指针arr转换为结构指针并访问结构元素是未定义的行为,并且高度取决于您的实现。 (数组元素之间可能有填充。)

#include <cstdio>
#include <cstdint>

struct name{

    uint8_t b0;
    uint8_t b1;
    uint8_t array[3];

} name1, *nameptr;

int main()
{
    
    uint8_t arr[]= {1,2,3,4,5};
    nameptr = (name *)arr;
    printf("%d\n",(int)nameptr->b0);
    printf("%d\n",(int)nameptr->b1);
    printf("%d\n",(int)nameptr->array[0]); //should print 3
    printf("%d\n",(int)nameptr->array[1]); //should print 4
    printf("%d\n",(int)nameptr->array[2]);

    return 0;
}

在我测试程序的特定平台上,output 是

1
2
3
4
5

https://onlinegdb.com/HyY8BDUz _

但实际上它是未定义的行为,可能会根据您的实现产生不同的结果。

除了通过将数组转换为结构调用的未定义行为之外,还有一个大小问题。

这是您的代码的轻微变化,仍然调用 UB,至少在 gcc 上没有运行时错误:

...

int main()
{

    uint8_t arr[sizeof(name)]= {1,2,3,4,5};
    nameptr = (name *)arr;
    nameptr->ptr = arr+2;
    for (int i=0; i<3; i++){  // SB: starting at 2 so only 0 to 3...
        printf("%d ",*(nameptr->ptr+i));  //expecting to print 3 4 5
    }

    return 0;
}

当我在调试器下执行这段代码时,我可以看到arr现在的大小为 8(在我的 32 位环境中)。 因为name的实际层是:

* b0
* b1
* padding bytes size 2
* ptr (size 4)

所以在你的原始代码中,当你执行nameptr->ptr = arr+2; 你写的已经过了声明的数组,这是 SIGSEGV 或其他奇怪错误的一个很好的方法。


但无论如何,我的代码不会打印 3、4、5。即使它调用未定义的行为,我的实现也会在 5 的位置写入ptr的第一个字节(请参阅上面的层以了解原因......)。 所以我得到 3、4 和一个随机字节!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM