首页 > 试题广场 >

有以下代码: int arr[2]; int i; in

[单选题]
有以下代码:
struct A
{
    bool b;
    int arr[2];
    int i;
    int j;
};
int main()
{
    A a;
    a.b = false;
    a.arr[0] = 1;
    a.arr[1] = 2;
    a.i = 20;
    a.j = 30;
    *(a.arr + 1) = 40;
    A *p = 0;
    unsigned int q = (unsigned int)(&p->i);
    (*(int *)((char *)&a + q)) = -50;
     return 0;
}

main函数返回之前,请问以下哪些说法是错误的()

  • a.b的值是false
  • arr[0]的值是1
  • a.i的值是20
  • a.j的值是30
答:这里主要是最后几行代码怎么解释?
A*p = 0;
unsigned int q = (unsigned int)(&p->i));
(*(int*)((char*)&a +q)) = -50;
考点1:结构体指针,结构体指针的访问方式为(p->i)
考点2:->优先级大于&,故而这里是取对象的成员相对地址
考点3:考虑字节4对齐,bool b后面有3个空字节,所以i的地址就是12. 即q=12
考点4:(char*)&a +q 先把a的地址转换成指向char型(即1个Byte)指针,然后指针往后移动q个Byte。
所以最后得出的结果是a.i的值为-50。
发表于 2018-10-20 11:55:27 回复(4)
p的地址为0,那么&p->i的地址为12,相当于i相对于结构体头地址的偏移量为12个字节,(char*)&a +q自然就指向的a中i的地址,i被修改为-50
编辑于 2017-08-18 14:18:22 回复(15)
->优先级大于&,故而这里是取对象的成员相对地址,这种情况下,编译器并不去访问指针,所以指针可以为任意值,这算是一种应用技巧。。。
发表于 2017-08-24 18:41:00 回复(0)
#include <stdio.h>
#include <stdbool.h>

struct A{
    bool b;
    int arr[2];
    int i;
    int j;
};
int main(){
    struct A a;
    a.b = false;
    a.arr[0] = 1;
    a.arr[1] = 2;
    a.i = 20;
    a.j = 30;
    *(a.arr + 1) = 40;
    struct A*p = 0;
    printf("%p\n",p);
    printf("%p\n",&a);
    unsigned int q = (unsigned int)(&p->i);
    printf("%d\n",q);
    (*(int*)((char*)&a +q)) = -50;
    printf("%d\n",a.i);
    return 0;
}
输出结果:
	
(nil)
0x7ffc365d4f30
12
-50
解释一下:
首先如果A * p=NULL; 那么代码就是错的,无法执行
这里A *p 可以赋值任何地址,包括题目的0.
const A* p = x;//x任意
	
unsigned intq = (unsignedint)(&p->i));
这两句代码可以变成宏,貌似linux内核有这样的使用方式,来获取结构体任意成员的起始位置。

发表于 2018-06-04 11:53:12 回复(3)
1.是p的初始化为0的原因吧,此时q表示为成员变量i相对于结构体开始的偏移量:1+3+4+4=12。 2.如果p的初始化不是0,而是动态分配的,此时q就是绝对地址,则程序段错误,溢出。 3.对于p->i;如果不对其复制或者向其复制,编译器好像不会处理。
发表于 2022-03-08 16:32:19 回复(0)
为什么arr[0]的值是1,为什么不是a.arr[0]
发表于 2019-03-10 20:23:26 回复(0)
这个题错了,
发表于 2017-12-11 14:46:04 回复(0)

注意:-> * &优先级由高到低。
储备知识:成员相对于结构体起始地址的偏移量 = &成员 - &结构体变量;这里将0强制转为结构体类型的地址,此时成员相对于结构体起始地址的偏移量 = &成员(- 0)。减掉0相当于没减。
1、(unsigned int)(&p->i)得到i的地址,强转为整数,得到相对于结构体的起始地址的偏移量,即p = 12.
2、(char)&a + q,跳到偏移量为12的地址处,(int)((char)&a + q)将偏移量为12的地址类型强转为int*。
3、
(int)((char)&a + q),访问4个字节。即将成员i的四个字节赋值为-50.

编辑于 2022-11-24 23:22:22 回复(0)
有个疑问,声明一个指针,指向0,为什么不需要分配空间,就可以解引用了? 比如: p->i
发表于 2017-08-20 21:49:14 回复(5)
->优先级高于&,&p->i相当于&(p->i),考虑字节4对齐,bool b后面有3个空字节,所以i的地址就是12. 即q=12;
发表于 2017-08-18 15:06:32 回复(1)
a.i的值是-50
发表于 2017-08-15 15:38:41 回复(2)
这个题把p赋值为0,不会出错么?都没有实例化
发表于 2019-04-10 07:48:58 回复(2)
arr[0] = 1?  不是a.arr[0] = 1?
发表于 2018-03-01 15:10:58 回复(1)
p是空指针,null,而在定义中null=(void*)0,也就是说空指针的地址是0
发表于 2023-10-09 15:37:15 回复(0)
懒羊羊解析:
 *(a.arr + 1) = 40;
  1. 通过指针操作修改 a.arr[1] 的值为 40,相当于*(a.arr + 1) = 40;。
 unsigned int q = (unsigned int)(&p->i);  
2.将指向 i 成员的偏移量存储在变量 q 中
-> 运算符的优先级比 & 运算符的优先级高。
 (*(int *)((char *)&a + q)) = -50;
使用指针运算和偏移量计算,在 a 的内存地址上通过偏移量 q 找到 i 的地址,然后将其转换为 int 指针,并修改其值为 -50,相当于 *(int *)((char *)&a + q) = -50;



发表于 2023-06-13 13:57:04 回复(0)
这个题目算是把指针和结构体玩明白了
发表于 2022-07-13 20:27:40 回复(0)
取到i相对结构体的偏移,后面就可以给i赋值了
发表于 2021-04-28 08:16:47 回复(0)
这个char *怎么理解
发表于 2020-08-18 20:36:45 回复(0)
指针都没有指向对象,怎么可以解引用
发表于 2018-08-24 17:02:21 回复(1)
粗心了。
发表于 2017-11-09 15:16:32 回复(0)