【笔试刷题训练】day_12

我想说

每天坚持一点点,坚持带来大改变
今天是刷题的第_12天,加油!


一、选择题

在这里插入图片描述
这道题存在多个错误

错误一:在析构函数中调用delete this

我们知道,使用delete会有两步:
1. 调用析构函数释放对象中的资源
2. 调用operator delete释放该对象

题目中,在myClass的析构函数中delete this,那么首先就会调用~myClass(),然后再释放空间。但是调用~myClass()又会去delete this,每次调用delete this都会去调用~myClass,~myClass()又会去调用delete,互相调用形成死循环,从而导致栈溢出,程序崩溃!

注意:只是在析构函数中delete this是可以通过编译的,但是运行的时候会形成死循环导致程序崩溃

错误二:对this进行更改
题目中,this = NULL这句代码是错误的,因为this的类型是类类型* const this,所以this是不能被更改的,this指向的内容可以被更改!所以因为this=NULL这句代码,会导致编译失败!

错误三:delete是对new出来的对象进行释放,并不是所有的对象都是从堆上new出来的

题目中,delete this,但是该对象并不一定是在堆上new出来的,对于myClass* ptr = new myClass,我们可以通过delete ptr进行释放。但是这个this所指的对象,可能就是在栈上创建的静态对象:myClass obj,采用delete对栈对象进行释放的话,首先会调用该对象的析构函数(这一步没问题),然后调用operator delete释放对象空间(这一步就会出现非法堆指针错误!)

综上所述,所以最后程序的运行结果是:无法通过编译

总结:
在成员函数中调用delete this,会导致指针错误
在析构函数中调用delete this,会导致堆栈溢出(死循环)

在这里插入图片描述

A: 对于一个类,如果我们不显式写构造函数,编译器会自动生成一个无参数的构造函数,但是如果我们自己显式定义了,这个无参数的默认构造函数就不会生成。所以有没有无参数的构造函数取决于我们自己。
B: 误区:并不是每一个类都有一个拷贝构造函数!虽然对于拷贝构造函数,我们不显式定义编译器会自动生成一个拷贝构造函数,但是我们可以人为的让其没有拷贝构造函数。看如下代码:
class A{
public:
  A(){};
  ~A();
   A(A&);  //声明一个拷贝构造函数,编译器也不会生成了!
}
在main函数中调用其拷贝构造,程序运行结果是:链接错误,无法找到拷贝构造函数!也就是说,编译器看到有用户显式写的拷贝构造的声明之后,便不会生成默认的拷贝构造函数了,我们可以通过声明但不定义拷贝构造,从而让该类没有拷贝构造

补充知识:C++11中有专门的方式可以让一个类没有拷贝构造:
A(A&) = delete; //即在函数声明后面加一个 =delete,告诉编译器不要生成他的默认函数!
此时如果在主函数中调用该类的拷贝构造,就会提示:尝试引用已删除的函数

总结:写一个没有拷贝构造的类:
1.构造函数只给声明不给定义
2.使用C++11的 =delete,不让编译器自动生成默认拷贝构造

C:拷贝构造也是一种构造函数,可以存在重载!所以每个类可以有多个拷贝构造函数!
D:析构函数没有参数,所以无法重载,每个类只能有一个析构函数!


在这里插入图片描述
A:堆的大小取决于操作系统给堆分配多少内存,栈的内存一般很小,正确√
B:new/delete是在堆上随机申请内存,所以频繁申请很容易产生内存碎片问题。而栈的是由编译器自动管理,对于使用完的变量会自动进行销毁,所以不存在此问题!
C:堆只能动态分配,×
D:堆只能动态分配,栈可以动态也可以静态 √

详细的请见我这篇文章:👉6堆栈那些事儿~

二、编程题

1.二进制插入

👉 题目链接

思路1:拿到m的每一位插入到n的对应位置

即对每一位利用 | 运算

class BinInsert {
public:
    int binInsert(int n, int m, int j, int i) {
        // write code here
        //把m插入到n的第j到i位
        int index = 0;
        for(int k = j;k<=i;++k)
        {
            //(m>>index)&1拿到m的每一位
            // <<k 就是移动到相应的位置
            // 然后|= 就是把m的对应位置插入到n的对应位置
            n |= ((1 & (m>>index)) << k);
            ++index;
        }
        return n;
    }
};

思路2:m直接左移j位,整体或运算

class BinInsert {
public:
    int binInsert(int n, int m, int j, int i) {
        // write code here
       return n | (m<<j);
    }
};

2. 查找组成一个偶数最接近的两个素数

👉 题目链接

给一个偶数n,我们要找组成该偶数的最接近的两个素数

我们可以从 n/2 处开始找,left为左半部分,right为右半部分

如果left和right都是素数,那么就输出这两个数

否则,–left,++right

#include<iostream>
#include<cmath>
using namespace std;
//判断是否为素数
bool ispri(int num)
{
    for(int i = 2;i<=sqrt(num);++i)
    {
        if(num%i==0)
        {
            return false;
        }
    }
    return true;
}
int main()
{
    int n;
    cin >> n;    //偶数
    //找到组成n的两个最小素数
    //24:12*2 -> 11 13
    //18:9*2 -> 8 10 -> 7 11 √
    
    //思路:从中间向左右找
    int left = n/2;
    int right = n/2;
    //有一个不是素数,就继续循环
    while(!ispri(left) || !ispri(right))
    {
        --left;
        ++right;
    }
    cout << left <<endl;
    cout << right << endl;
    
    
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

2021狮子歌歌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值