首页 > 试题广场 >

下面程序的执行结果是?

[单选题]
下面程序的执行结果:
class A{ 
    public: 
        long a; 
}; 
class B : public A { 
    public: 
        long b; 
}; 
void seta(A* data, int idx) { 
    data[idx].a = 2; 
} 
int main(int argc, char *argv[]) { 
    B data[4]; 
    for(int i=0; i<4; ++i){ 
        data[i].a = 1; 
        data[i].b = 1; 
        seta(data, i); 
    } 
    for(int i=0; i<4; ++i){ 
         std::cout << data[i].a << data[i].b; 
    } 
    return 0; 
}
  • 11111111
  • 12121212
  • 11112222
  • 21212121
  • 22221111
推荐
这道题应该注意 指针类型加减 时步长的问题。
A 大小为 4
B 大小为 8
那么:
void seta(A* data, int idx) {
    data[idx].a = 2;
}
由于传入的实参为B类型,大小为8,而形参为A类型,大小为4
data[idx] 取 data + idx 处的元素,这时指针 data加1 的长度不是一个B长度,而是一个A长度,或者说是1/2个B长度。这时该函数中 data[0~3] 指向的是原 data[0].a,data[0].b,data[1].a,data[1].b,
由于隐式类型转换的缘故,data[0].a, data[0].b,data[1].a,data[1].b 处的值全部由于 data[idx].a = 2; 操作变为 2
这道题如果改为void seta(B* data, int idx),那么形参中data指针加1步长为8,结果就是21212121。但是由于步长为4,所以结果就是 22221111。



编辑于 2016-03-07 13:28:12 回复(34)
data[idx].a = 2,这里不是.a么?怎么能改变.b的值啊?
发表于 2016-06-12 19:41:23 回复(1)
seta方法中已经将data数组退化成A类型的数组,因此下标已经不是针对B类型进行
发表于 2015-03-16 15:51:19 回复(0)
注意seta函数的形参是A类型,A类型只有一个long型a,所以是4个字节,B类型包含a和b,是8个字节,形参是A,实参是B,data[i]就是A类型的
发表于 2016-07-23 19:12:36 回复(0)
data[idx].a 取地址的方式是data+idx*4+a在类中的偏移量(0),data+idx*4+a=date+idx*4,所以虽然data[0].b里面并没有成员a,也能修改对应地址处的值。这样的解释是对的吗?
编辑于 2019-03-22 22:07:18 回复(0)

首先明确, A类 大小为 4字节;B 类大小为 8字节
因为B继承自A,基类A有一个long,4字节,派生类B继承A的long加上自身定义了一个long,4+4=8个字节。

所以,A类指针+1移动4字节,B类指针+1移动8字节,所以A类指针和B类指针的移动步长不相同

void seta(A* data, int idx)  { data[idx].a = 2;  } 

由代码可知,此处传入的实参为B类,而形参却为A类,所以这里就是使用基类A类指针来操作,子类B类的数据。
因为A类和B类指针步长不同的原因,就会出现指针实际操作的目标地址,与想象中的目标地址不相同

下面展示,此例题中,因为指针步长不同的原因,所对应的操作地址

在这里插入图片描述

因此每执行一次此函数,就会进行4字节对应地址的数据替换。

seta(data, i); 

所以答案就为22221111
因此类推,若将此函数void seta(A* data, int idx);中的A类改为B类,就不会存在指针步长不同的问题,答案就会是21212121


编辑于 2022-01-11 17:06:31 回复(1)
程序执行过程:
data[0]     data[1]     data[2]     data[3]
1->2   1
2      1->2  1      1
2    2          1->21     1      1
2    2          2   1->2   1       1     1     1

因此,最终输出的结果是22221111
发表于 2015-11-08 14:45:27 回复(0)
因为seta函数参数为类A的指针,所以每当指针+1,指向的是下一个long类型数据,不是data[1].a,而是data[0].b的地址,所以前面4个数据被赋值为2
发表于 2014-10-13 14:17:35 回复(0)
如图:

发表于 2019-08-16 13:38:10 回复(1)
发表于 2019-03-10 16:19:56 回复(0)
基类指针和子类指针的步长在子类中添加新的数据成员后就不一致了,用基类指针操作子类对象的数组就会达不到效果。
刚学过就忘了。。。
发表于 2016-07-23 16:26:06 回复(0)
很好的题,刚开始data[4]8个元素的存储是11111111
当传入参数时,因为传入的是基类的指针,所以运算时指针是以基类的长度作为移动单元的
比如当传入i=1时,data[1]=*(data+1),基类四个字节,所以指针右移四个单元,本来应该指向的是
子类data[0].b,但是因为是基类的指针,会误以为这是基类的数据成员,当做基类data[1].a来处理。
所以最后是变成了22221111
发表于 2017-08-07 20:13:47 回复(0)

 这个题考的比较好,考察指针的运算问题;指针运算过程中,加的值idx实际上是按照指向的元素的倍数进行运算处理的,即指针中加1的值,在计算地址时,相当于是加了1*sizeof(*p);
                                                                                    
发表于 2015-08-19 19:22:56 回复(0)
基类指针的操作步长为4,而把子类对象数组赋给基类指针后,索引符的操作以基类为准,失去了正常操作子类对象的能力。
发表于 2016-11-16 14:41:22 回复(0)
本身看来应该是21212121,但是A的大小是B 的一半,所以每次给B 赋2的时候,只会走一半大小,到达A,所以最后赋值结果是22221111。
发表于 2015-08-14 15:57:16 回复(0)
通过数组访问实际是通过在首地址上偏移来达到的,A占4字节,一次只能偏移4字节,而偏移8字节才能移到下一个B
发表于 2021-03-13 15:58:52 回复(0)
因为seta函数参数为类A的指针,所以每当指针+1,指向的是下一个long类型数据,不是data[1].a,而是data[0].b的地址,所以前面4个数据被赋值为2
发表于 2016-09-25 22:20:17 回复(0)
#include<stdio.h>
int main(){
    int a[2][2]={{1,2},{3,4}};
    int * b;
    b=a[0];
    printf("%d\n",*(b+3));
}
道理和上面这个应该差不多
发表于 2016-04-03 16:21:13 回复(0)
对于类A的对象,其大小为4,而B对象的大小为8,所以传入是存在类型隐式转换,单从字节上看,
A data[4]为aaaa
B data[4]为abababab
所以操作seta会把前4个abab变为2,而后四位abab仍保持为1
发表于 2018-04-25 17:30:31 回复(0)
基类与派生类,基类指针解引用,则使用基类。
发表于 2020-06-20 17:39:22 回复(0)
牛逼的题,涨知识了
发表于 2019-04-28 14:58:25 回复(0)