一、选择题
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;
}