C++ day06 new/delete只能生成栈对象和只能生成堆对象、统计词频习题(有答案)

一、选择题

1、执行以下程序

char *str;//野指针
cin >> str;
cout << str;
若输入abcd 1234,则输出(D)
A. abcd        B. abcd 1234         C.1234         D. 输出乱码或错误

2、执行以下程序

char a[200];
cin.getline(a, 200, ' ');//按空格截断
cout << a;
若输入abcd 1234,则输出(A )
A. abcd      B. abcd 1234      C.1234      D. 输出乱码或错误

二、编程题

1、实现new/delete表达式中只能生成栈对象的代码和只能生成堆对象的代码。
1)operator new/delete设置为private,实现只能生成栈上的对象

// 只能生成栈对象
#include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::cin;
using std::string;
class Student{
public:
  Student();
  Student(int id = 0, string name = "");
  ~Student();
  void show();
private:
  //将operator new设置为私有,在类外用new创建一个新对象时就无法调用operator new了
  //从而使得该类只能在栈上创建对象
  void* operator new(size_t sz);
  void operator delete(void *ptr);
private:
  int _id;
  string _name;
};
Student::Student()
 :_id(0)
  ,_name("")
{
  cout << "Student()" << endl;
}
Student::Student(int id, string name)
 :_id(id)
 ,_name(name)
{
  cout << "Student(int, string)" << endl;
}
Student::~Student(){
  cout << "~Student()" << endl;
}
void* Student::operator new(size_t sz){
  //使用new创建对象时,会调用该函数
  void *ptr = malloc(sz);
  return ptr;
}
void Student::operator delete(void *ptr){
  //使用delete回收new创建的对象时,会调用该函数
  if(ptr == nullptr){
    return;
 }
  delete &ptr;
}
void Student::show(){
  //打印对象的数据成员
  cout << "id = " << _id << ", name = " << _name << endl;
}
void test(){
  //只能在栈上创建对象
  Student stu1(1001, "liubei");
  stu1.show();
  //不能在堆上创建对象
  /* //'operator new' is a private member of 'Student' */
  /* Student *stu2 = new Student(); */
}
int main()
{
  test();
  return 0;
}

在这里插入图片描述

2)把析构函数设为private,实现只能创建堆上的对象
在这里插入图片描述

// 只能生成堆上的对象
#include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::cin;
using std::string;
class Student{
public:
  Student();  //构造函数必须为public,否则也无法使用new创建对象了
  Student(int id = 0, string name = "");
  void* operator new(size_t sz);
  void operator delete(void *ptr);
  void destroy();  //用来回收堆上的对象
  void show();
private:
  //把析构函数设置为private,破坏创建栈上对象的条件
  ~Student();
private:
  int _id;
  string _name;
};
Student::Student()
 :_id(0)
  ,_name("")
{
  cout << "Student()" << endl;
}
Student::Student(int id, string name)
 :_id(id)
 ,_name(name)
{
  cout << "Student(int, string)" << endl;
}
Student::~Student(){
  cout << "~Student()" << endl;
}
void* Student::operator new(size_t sz){
//使用new创建对象时,会调用该函数
  void *ptr = malloc(sz);
  return ptr;
}
void Student::destroy(){
  //由于把operator delete被设置为private,没办法使用delete回收资源了
  //需要再定义一个函数来回收
  this->~Student();
  free(this);
}
void Student::operator delete(void *ptr){
  //使用delete回收new创建的对象时,会调用该函数
  if(ptr == nullptr){
    return;
 }
  delete &ptr;
}
void Student::show(){
  //打印对象的数据成员
  cout << "id = " << _id << ", name = " << _name << endl;
}
void test(){
  //无法在栈上创建对象
  /* Student stu1(1001, "liubei"); */
  /* stu1.show(); */
  //只能在堆上创建对象
  //'operator new' is a private member of 'Student'
  Student *stu2 = new Student(1002, "caocao");
  stu2->show();
  stu2->destroy();
  stu2 = nullptr;  //避免悬空指针
}
int main()
{
  test();
  return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TDmAR6Q2-1621141255917)(C:\Users\kachi\AppData\Roaming\Typora\typora-user-images\image-20210511204650891.png)]2、统计一篇英文(The_Holy_Bible.txt)文章中出现的单词和词频,
输入:某篇文章的绝对路径
输出:词典(词典中的内容为每一行都是一个“单词 词频”)

词典的存储格式如下

|   a 66          |
|   abandon 77    |
|   public 88     |
|    ......	      |
|_________________|

struct Record
{
	string _word;
	int _frequency;
};

class Dictionary
{
public:
	//......
    void read(const std::string &filename);
    void store(const std::string &filename);
private:
	vector<Record> _dict;
};

提示:因为我们需要统计圣经文件中单词以及该单词在文件中出现的次数,所以可以看去读圣经文件,然后将单词存到数据结构中,并记录单词的次数,如果单词第二次出现的时候,只需要修改单词的次数(也就是这里说的单词的频率),这样当统计完整个圣经文件后,数据都存在数据结构vector了。接着遍历vector数据结构就可以将单词以及单词次数(也就是频率)存储到另外一个文件。(当然如果不存到另外一个文件,就只能打印到终端了)

注意:在读圣经文件的时候,有可能字符串是不合法的,比如:abc123 abc?这样的字符串,处理方式两种:直接不统计这样的字符串或者将非法字母去掉即可。

#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <iomanip>
#include <algorithm>
#include <string.h>


using namespace std;


struct Record
{
    string _word;
    int _frequency;
};

//大写变小写的函数
void allToLower(const char *path, const char *newpath);
//根据频次排序
bool greaterSort(Record a, Record b){
    //作为sort的第三个参数,用来对保存了结构体的vector排序
    return (a._frequency > b._frequency);
}

class Dictionary{
public:
    Dictionary();
    ~Dictionary();
    void read(const string &filename);  // 从文件中读取内容,并保存在_dict中
    void store(const string &filename); // 把_dict中保存的内容写入文件中
private:
    vector<Record> _dict;
    int _count;
};

//构造函数
Dictionary::Dictionary()
    :_dict()
    //初始化_cout为0
    ,_count(0){}

//析构函数
Dictionary::~Dictionary(){}

//类成员函数,read用来从文件中读取数据,读到容器
void Dictionary::read(const string &filename){
    //打开文件,将单词读取出来
    ifstream ifs(filename);
    //若打开失败,打印失败直接退出
    if(!ifs.good()){
        cerr << "open failed!" << endl;
        return;
    }
    ifs >> noskipws;    //输入运算符读取空白符,读取字符的时候不跳过空白
    char buf;
    string word;
    bool flag = false;
    while(ifs >> buf){
        //如果是字母,拼接到word后面
        if(isalpha(buf)){
            word += buf;
        }
        //如果是字母以外的内容,说明读取到一个单词了
        else{
            flag = false;   //重置标志位
            if(word.size()){
                //如果word有内容,说明读完了一个单词,
                //遍历_dict,如果单词在里面,计数+1,如果不在,插入
                for(auto &item:_dict){
                    //要修改内容所以用引用
                    //找到了容器中的单词
                    if(item._word == word){
                        ++item._frequency;
                        flag=true;
                    }
                }
                //旧单词的标志位已经置为true
                //若是新单词,塞入容器中
                if(!flag){
                    //定义新结构体
                    Record buf;
                    buf._word=word;
                    buf._frequency=1;
                    _dict.push_back(buf);
                }
                //记单词数量
                ++_count;
                //清空word,为读取下一个单词做准备
                word.clear();
            }
            //如果word没有内容,继续读取下一个字符
            else{
                continue;
            }
        }
    }
}

void Dictionary::store(const string &filename){
    //根据_dict中的_frequency进行降序排序
    //调用sort函数,对vector进行降序排序
    sort(_dict.begin(), _dict.end(), greaterSort);
    //把_dict中的内容写入新文件
    ofstream ofs(filename);
    ofs << "单词总数为:" << _count << endl;
    //setiosflags(ios::left)左右对齐输出,一般和setw设置宽度同时使用。
    //setw(16)表示空16格
    //先打印一行数据word            frequency
    ofs << setiosflags(ios::left) << setw(16) << "word" << setw(7) <<"frequency" << endl;
    //正式开始打印单词和频次
    for(auto item:_dict){
        ofs << " " << setiosflags(ios::left) << setw(16) << item._word
            << " " << setw(7) << item._frequency << endl;
    }
    ofs.close();
}


int main()
{
    Dictionary *dict=new Dictionary();
    dict->read("The_Holy_Bible.txt");
    dict->store("33.txt");
    return 0;
}

//大写变小写的函数
void allToLower(const char *path, const char *newpath){
    //打开文件,读出内容,大写变小写
    ifstream ifs(path);
    ifs>>std::noskipws; //读取字符时遇到空白(空格、换行)不跳过
    if(!ifs.good()){
        cerr << "open failed!\n" << endl;
        ifs.close();
    return;
    }
    ofstream ofs(newpath);  
    char buf, obuf;
    while(ifs >> buf){
        if(isupper(buf)){
            obuf = tolower(buf);
        }
        else{
            obuf = buf;
        }
        ofs << obuf;
    }    
    ifs.close();
    ofs.close();
}

最终得到结果类似:

a 10
public 20
welcome 30

while(ifs >> buf){
    if(isupper(buf)){
        obuf = tolower(buf);
    }
    else{
        obuf = buf;
    }
    ofs << obuf;
}    
ifs.close();
ofs.close();

}


最终得到结果类似:

a    10
public   20
welcome   30
.......

另外一种方法

#include <time.h>
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <sstream>
#include <algorithm>

using std::cout;
using std::endl;
using std::string;
using std::vector;
using std::ifstream;
using std::ofstream;
using std::istringstream;
using std::sort;

struct Record
{
    Record(const string &word, int fre)
    : _word(word)
    , _frequency(fre)
    {

    }
    string _word;
    int _frequency;
};

bool operator<(const Record &lhs, const Record &rhs)
{
    return lhs._word < rhs._word;
}
class Dictionary
{
public:
    Dictionary(int capa)
    {
        _dict.reserve(capa);
    }
    void read(const std::string &filename);
    void store(const std::string &filename);
    string dealWord(const string &word);
    void insert(const string &word);
private:
    vector<Record> _dict;
};

void Dictionary::read(const std::string &filename)
{
    //打开输入流
    ifstream ifs(filename);
    if(!ifs)
    {
        std::cerr << "open " << filename << " error"<< endl;
        return;
    }

    //创建字符串
    string line;
    //按行读入字符串
    while(getline(ifs, line))
    {
        //将每个字符串拆分出来,将line内转成流形式
        istringstream iss(line);
        //创建字符串用来存单词
        string word;
        //将iss流输出为单个单词,当输出的单词还有内容
        while(iss >> word)
        {
            //dealWord()将函数中每个单词判断以下是否为字符,不是的话返回空字符串
            string newWord = dealWord(word);//处理非法单词
            //把单词插入到容器中
            insert(newWord);
        }
    }
    //对容器内的词语字典序排序
    sort(_dict.begin(), _dict.end());
    //关闭输入流
    ifs.close();
}

//容器输出到输出流的操作
void Dictionary::store(const std::string &filename)
{
    //打开输出流
    ofstream ofs(filename);
    //若打开输出流失败,直接返回
    if(!ofs)
    {
        std::cerr << "ostream is not good" << endl;
        return;
    }

    //打开输出流成功
    for(size_t idx = 0; idx != _dict.size(); ++idx)
    {
        //依次从容器输出到输出流
        ofs << _dict[idx]._word << "   " << _dict[idx]._frequency << endl;
    }
    //关闭输出流
    ofs.close();
}

//dealWord()将函数中每个单词判断以下是否为字符,不是的话返回空字符串
string Dictionary::dealWord(const string &word)
{
    for(size_t idx = 0; idx != word.size(); ++idx)
    {
        if(!isalpha(word[idx]))//abc123
        {
            return string();//返回的是临时对象
        }
    }

    return word;
}

//把单词插入到容器中
void Dictionary::insert(const string &word)
{
    //若单词字符串为空,直接返回
    if(word == string())
    {
        return;
    }

    size_t idx  = 0;
    for(idx = 0; idx != _dict.size(); ++idx)
    {
        //要是单词已经在容器中,直接增加该单词的词频,然后break返回
        if(word == _dict[idx]._word)
        {
            ++_dict[idx]._frequency;
            break;//当单词词频统计之后,就不需要进行循环操作了
        }
    }
    //若过在容器中没找到,直接把单词放到容器中,词频记为1
    if(idx == _dict.size())
    {
        _dict.push_back(Record(word, 1));
    }

}
int main(int argc, char **argv)
{
    Dictionary dictionary(13000);
    cout << "start reading...." << endl;
    //开始计时
    time_t beg = time(NULL);
    dictionary.read("The_Holy_Bible.txt");
    //结束计时
    time_t end = time(NULL);
    cout << "cost " << (end - beg) << "s" << endl;
    cout << "finish reading...." << endl;
    //存在本地的dic.dat文件
    dictionary.store("dic.dat");
    return 0;
}

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值