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



我想使用struct属性访问数组元素。我能够使用结构指针(nameptr)打印第1和第2个元素,而其余3个元素必须使用(uint8_tptr)访问,这本身就是"结构名称"的属性。

#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。出终止

1 2 5 0 56 Aborted (core dumps)

这个答案是基于修改后的代码,如修订版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;
}

本题第七版的代码在几个方面是错误的:

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时,将内存中的数据解释为地址并尝试访问该地址的内存。地址可能是由字节3,4,5和内存中它后面的任何东西构造的。(实现依赖)

原始代码的修改版本可以做你想要的,但是将数组指针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("%dn",(int)nameptr->b0);
printf("%dn",(int)nameptr->b1);
printf("%dn",(int)nameptr->array[0]); //should print 3
printf("%dn",(int)nameptr->array[1]); //should print 4
printf("%dn",(int)nameptr->array[2]);
return 0;
}

在测试程序的特定平台上,输出是

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和一个随机字节!

最新更新