首页 > 试题广场 >

阅读以下代码,则son s; ::memset(&s , 0

[单选题]
以下代码执行结果是()
#include <iostream>
using namespace std;

class Parent {
public:
    virtual void output();
};

void Parent::output() {
    printf("Parent!");
}

class Son : public Parent {
public:
    virtual void output();
};

void Son::output() {
    printf("Son!");
}

int main() {

    Son s;
    memset(&s, 0, sizeof(s));
    Parent& p = s;
    p.output();

	return 0;
}
  • Parent!
  • Son!
  • 编译出错
  • 没有输出结果,程序运行出错
推荐
答案: d
解释:
memset 将s所指向的某一块内存中的每个字节的内容全部设置为ch指定的ASCII值,
本代码中, 不虚函数链表地址也清空了, 所以p.output调用失败。 output函数的地址编程0
编辑于 2015-02-09 10:08:06 回复(9)
memset()函数的使用。
发表于 2016-05-22 16:41:57 回复(0)
1. memset是以字节为单位,初始化内存块。
当初始化一个字节单位的数组时,可以用memset把每个数组单元初始化成任何你想要的值,比如,
char data[10];
memset(data, 1, sizeof(data));    // right
memset(data, 0, sizeof(data));    // right
而在初始化其他基础类型时,则需要注意,比如,
int data[10];
memset(data, 0, sizeof(data));    // right
memset(data, -1, sizeof(data));    // right
memset(data, 1, sizeof(data));    // wrong, data[x] would be 0x0101 instead of 1
2. 当结构体类型中包含指针时,在使用memset初始化时需要小心。
比如如下代码中,
struct Parameters {
          int x;
          int* p_x;
};
Parameters par;
par.p_x = new int[10];
memset(&par, 0, sizeof(par));
当memset初始化时,并不会初始化p_x指向的int数组单元的值,而会把已经分配过内存的p_x指针本身设置为0,造成内存泄漏。同理,对std::vector等数据类型,显而易见也是不应该使用memset来初始化的。

3. 当结构体或类的本身或其基类中存在虚函数时,也需要谨慎使用memset。
这个问题就是在开头项目中发现的问题,如下代码中,
class BaseParameters
{
public:
    virtual void reset() {}
};

class MyParameters : public BaseParameters
{
public: 
    int data[3];
    int buf[3];
};

MyParameters my_pars;
memset(&my_pars, 0, sizeof(my_pars));
BaseParameters* pars = &my_pars;

//......

MyParameters* my = dynamic_cast<MyParameters*>(pars);
程序运行到dynamic_cast时发生异常。原因其实也很容易发现,我们的目的是为了初始化数据结构MyParameters里的data和buf,正常来说需要初始化的内存空间是sizeof(int) * 3 * 2 = 24字节,但是使用memset直接初始化MyParameters类型的数据结构时,sizeof(my_pars)却是28字节,因为为了实现多态机制,C++对有虚函数的对象会包含一个指向虚函数表(V-Table)的指针,当使用memset时,会把该虚函数表的指针也初始化为0,而dynamic_cast也使用RTTI技术,运行时会使用到V-Table,可此时由于与V-Table的链接已经被破坏,导致程序发生异常。

发表于 2017-07-08 10:59:59 回复(6)
void *memset(void *s, int ch, size_t n);  
函数解释:将s中前n个字节 (typedef unsigned int size_t )用ch替换并返回s.
作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法,通常为新申请的内存做初始化工作.

发表于 2015-10-16 21:12:01 回复(0)

答案:D。

被virtual关键字修饰的成员函数,就是虚函数,虚函数的作用是实现多态性(Polymorphism)。当类中定义了虚函数后,在实例化的对象中会有一个额外的指针vptr指向一个虚函数表vtable,虚函数表中存放了实际调用函数的地址。

对于本题而言,由于output是一个虚函数,在调用的时候,需要首先根据vptr找到vtable,然后在vtable中查找实际要调用的output函数的地址。但是,调用memset函数会把vptr指针的值改为0,因此,通过vptr无法找到vtable,程序运行会出错。所以,选项D正确。


发表于 2018-07-13 09:03:52 回复(0)
一个类所占的存储空间包括类成员和虚函数指针。使用memset后将son类型的s对应的空间全部初始化为0,即对应的函数指针也丢失了,因此无法调用.
发表于 2019-02-16 21:09:59 回复(0)
因为为了实现多态机制,C++对有虚函数的对象会包含一个指向虚函数表(V-Table)的指针,当使用memset时,会把该虚函数表的指针也初始化为0,而dynamic_cast也使用RTTI技术,运行时会使用到V-Table,可此时由于与V-Table的链接已经被破坏,导致程序发生异常。如果将virtual去掉,则会输出parent!
发表于 2017-10-07 15:47:18 回复(1)
答案:D。 被virtual关键字修饰的成员函数,就是虚函数,虚函数的作用是实现多态性(Polymorphism)。当类中定义了虚函数后,在实例化的对象中会有一个额外的指针vptr指向一个虚函数表vtable,虚函数表中存放了实际调用函数的地址。 对于本题而言,由于output是一个虚函数,在调用的时候,需要首先根据vptr找到vtable,然后在vtable中查找实际要调用的output函数的地址。但是,调用memset函数会把vptr指针的值改为0,因此,通过vptr无法找到vtable,程序运行会出错。所以,选项D正确。
发表于 2018-09-06 16:04:16 回复(0)

当引用遇上虚函数

#include "iostream"

using namespace std;

class A {
public:
	virtual void fun() {
		cout << "A" << endl;
	}
};

class B : public A {
public:
	void fun() {
		cout << "B" << endl;
	}
};

int main() {
	B b;
	A &a = b;
	/*A * const a = &b;*/
	a.fun();
	return 0;
}
输出B

发表于 2020-08-03 16:00:33 回复(0)
可以画出内存分布图,由于内存中的虚函数指针,被清0了,所以什么也不输出。
发表于 2015-09-07 16:56:51 回复(0)

在代码中,使用了memset(&s, 0, sizeof(s))将对象 s 的内存全部置为0。这样做会导致对象的虚函数表指针被破坏,从而导致程序出现未定义的行为。

在调用p.output()时,由于虚函数表指针已经被破坏,无法正确找到虚函数的实现,因此会导致程序运行出错,而且不会有任何输出结果。

发表于 2023-10-19 17:18:38 回复(0)
纠错
发表于 2016-10-06 11:26:47 回复(0)
memset函数将s内存指针清零了
编辑于 2024-03-11 15:49:43 回复(0)
子类对象的虚函数地址也被清空了
发表于 2022-06-28 17:46:31 回复(0)
猜测考点是针对多态生效场景;
当vfptr被memset破坏后,任意通过指针/引用方式以进行虚函数调用的代码,都失效,且运行异常;如:
Son s;
memset(&s, 0, sizeof(s));
Parent& p = s;
p.output();  // 引用,调用失效
(&s)->output();// 指针,调用失效
s.output(); // 正常

 

发表于 2022-01-13 21:14:32 回复(0)
如果创建的对象中存在虚函数表指针,则该变量存储在对象的首地址,题中将首地址重新赋值,不会再根据虚函数表指针找到相应的虚函数表
发表于 2020-08-09 18:16:45 回复(0)

memset清空虚函数地址

发表于 2019-10-09 08:33:46 回复(0)
vptr被置零了
发表于 2019-07-21 11:11:01 回复(0)
这是多态的使用,只需要在基类的声明前加上virtual就好,派生类不需要加。
发表于 2018-09-21 20:53:17 回复(0)
对类对象进行内存覆盖时,如果类存在虚函数,会把类对象的虚函数表也覆盖掉,调用虚函数的时候就会迷路了!我只考虑到了引用可以实现多态,却没想到虚函数表被覆盖
编辑于 2018-05-22 11:46:02 回复(0)
我能理解p.output();没法输出,,但是为什么改成s.output()能输出son!????
不是说虚函数指针被赋值成0了吗
son s; 
memset(&s , 0, sizeof(s)); 
parent& p = s; 
s.output(); 
发表于 2018-03-16 10:16:19 回复(1)