C++容器、类型转换、异常与文件流操作

容器

容器,就是用来存放东西的盒子。

常用的数据结构包括:数组array, 链表list, 树tree, 栈stack, 队列queue, 散列表hash table, 集合set、映射表map 等等。容器便是容纳这些数据结构的。这些数据结构分为序列式与关联式两种,容器也分为序列式容器和关联式容器。

STL 标准模板库,核心包括容器、算法、迭代器。

序列式容器/顺序容器

元素排列次序与元素无关,由元素添加到容器的顺序决定

容器 说明
vector 支持快速随机访问
list 支持快速插入、删除
deque 双端队列 允许两端都可以进行入队和出队操作的队列
stack 后进先出LIFO(Last In First Out)堆栈
queue 先进先出FIFO(First Input First Output)队列
priority_queue 有优先级管理的queue

向量(vector)

连续存储的元素

向量(Vector)是一个封装了动态大小数组的顺序容器(Sequence Container)。跟任意其它类型容器一样,它能够存放各种类型的对象。可以简单的认为,向量是一个能够存放任意类型的动态数组。

列表 (list)

由节点组成的双向链表,每个结点包含着一个元素

双端队列(deque)

连续存储的指向不同元素的指针所组成的数组

以上三种容器操作基本一样

基本操作:

#include <vector>
using namespace std; vector<int> vec_1;
//1个元素
vector<int> vec_2(1);
//6个值为 1 的元素
vector<int> vec_3(6,1);
//使用容器初始化
vector<int> vec_4(vec_3); //通过下标操作元素
int i = vec_3[1];
int j = vec_3.at(1);
//首尾元素
vec_3.front()//返回第一个元素
vec_3.back()//返回最后一个元素 //插入元素
//vector不支持 push_front list,deque可以
vec_1.push_back(1);
//删除元素 vector不支持 pop_front
vec_1.pop_back(); //释放
//可以单个清除,也可以清除一段区间里的元素
vec_3.erase(vec_3.begin(),vec_3.end())
//清理容器 即erase所有
vec_3.clear(); //容量大小
vec_3.capacity();
//在容器中,其内存占用的空间是只增不减的,
//clear释放元素,却不能减小vector占用的内存
//所以可以对vector 收缩到合适的大小
vector< int >().swap(vec_3); //在vec是全局变量时候
//建立临时vector temp对象,swap调用之后对象vec占用的空间就等于默认构造的对象的大小
//temp就具有vec的大小,而temp随即就会被析构,从而其占用的空间也被释放。

迭代器


for (int i = 0; i < vec.size(); ++i) {
cout<< "vec["<<i<<"]=" <<vec[i] <<endl;
} //获得指向首元素的迭代器 模板类,不是指针,当做指针来使用
vector<int>::iterator it = vec.begin();
//遍历元素
for (; it < vec.end(); it++)
{
cout << *it << endl;
}
//begin和end 分别获得 指向容器第一个元素和最后一个元素下一个位置的迭代器
//rbegin和rend 分别获得 指向容器最后一个元素和第一个元素前一个位置的迭代器 //注意循环中操作元素对迭代器的影响
vector<int>::iterator it = vec.begin();
for (; it < vec.end(); )
{
//删除值为2的元素
if (*it == 2) {
vec.erase(it);
}
else {
it++;
}
}

栈(stack)

后进先出的值的排列

#include<stack>

stack<int> s;
//入栈
s.push(1);
s.push(2);
//弹栈
s.pop();
//栈顶
cout << s.top() << endl;

队列(queue)

先进先出的值的排列

#include<queue>

queue<int> q;
q.push(1);
q.push(2);
//移除最后一个
q.pop();
//获得第一个
q.front();
//最后一个元素
cout << q.back() << endl;

优先队列(priority_queue )

元素的次序是由所存储的数据的某个值排列的一种队列

//最大的在队首
priority_queue<int>;
//在vector之上实现的
priority_queue<int, vector<int>, less<int> >;
//vector 承载底层数据结构堆的容器
//less 表示数字大的优先级高,而 greater 表示数字小的优先级高
//less 让优先队列总是把最大的元素放在队首
//greater 让优先队列总是把最小的元素放在队首 //less和greater都是一个模板结构体 也可以自定义 class Student {
public:
int grade;
Student(int grade):grade(grade) {
}
};
struct cmp {
bool operator ()(Student* s1, Student* s2) {
// > 从小到大
// < 从大到小
return s1->grade > s2->grade;
}
bool operator ()(Student s1, Student s2) {
return s1.grade > s2.grade;
}
};
priority_queue<Student*, vector<Student*>, cmp > q1;
q1.push(new Student(2));
q1.push(new Student(1));
q1.push(new Student(3));
cout << q1.top()->grade << endl;

关联式容器

关联容器和大部分顺序容器操作一致

关联容器中的元素是按关键字来保存和访问的 支持高效的关键字查找与访问

集合(set)

由节点组成的红黑树,每个节点都包含着一个元素,元素不可重复

#include<set>

set<string> a;
set<string> a1={"zhangsan","666"};
a.insert("zhangsan"); // 插入一个元素
a.erase("123"); //删除,erase的返回值总是0和1,若返回0,表示删除的元素不在set中 //find 返回一个迭代器,如果查找失败会返回end()元素,否则成功
if(a.find("zhangsan")!=a.end()) //遍历
set<string>::iterator it = a.begin();
while (it != a.end()) {
cout << *it << endl;
it++;
}
for(set<int>::iterator it=numSet.begin() ;it!=numSet.end();it++){
cout<<*it<<endl;
}

键值对(map)

由{键,值}对组成的集合

#include<map>

map<int, string> m;
map<int, string> m1 = { { 1,"张三" },{ 2,"李四" } };
//插入元素
m1.insert({ 3,"王五" });
//pair=键值对
pair<int, string> p(4, "dongnao");
m1.insert(p);
//insetrt 返回 map<int, string>::iterator : bool 键值对
//如果 插入已经存在的 key,则会插入失败
//multimap:允许重复key
//使用m1[3] = "xx" 能够覆盖 //通过【key】操作元素
m1[5] = "yihan";
cout << m1[5].c_str() << endl;
//通过key查找元素
map<int, string>::iterator it = m1.find(3);
cout << (*it).second.c_str()<< endl;
// 删除
m1.erase(5);
//遍历
for (it = m1.begin(); it != m1.end(); it++)
{
pair<int, string> item = *it;
cout << item.first << ":" << item.second.c_str() << endl;
} //其他map================================

unordered_map c++11取代hash_map(哈希表实现,无序)

哈希表实现查找速度会比RB树实现快,但rb整体更节省内存

需要无序容器,高频快速查找删除,数据量较大用unordered_map;

需要有序容器,查找删除频率稳定,在意内存时用map。

谓词

如何最简单、通俗地理解C++的谓词?

C++ 谓词(predicate) 与 仿函数 ( functor (function object))

基本概念

① 返回bool类型的仿函数称为谓词。

② 如果operator()接受一个参数,那么叫做一元谓词。

③ 如果operator()接受两个参数,那么叫做二元谓词。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm> //仿函数 返回值类型是bool数据类型,称为谓词
//一元谓词
class GreaterFive
{
public:
bool operator()(int val)
{
return val > 5;
}
}; void test01()
{
vector<int>v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
} //查找容器中,有没有大于5的数字
//GreaterFive() 匿名函数对象
vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive());
if (it == v.end())
{
cout << "未找到" << endl;
}
else
{
cout << "找到大于5的数字为:" << *it << endl;
}
} int main() { test01(); system("pause"); return 0; }

运行结果:

找到大于5的数字为:6

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm> //仿函数 返回值类型是bool数据类型,称为谓词
//二元谓词
class MyCompare
{
public:
bool operator()(int val1,int val2)
{
return val1 > val2;
}
}; void test01()
{
vector<int>v;
v.push_back(10);
v.push_back(40);
v.push_back(50);
v.push_back(20);
v.push_back(30); sort(v.begin(), v.end());
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl; //使用函数对象,改变算法策略,变为排序规则为从大到小
sort(v.begin(), v.end(), MyCompare()); //MyCompare()为函数对象,是匿名函数 cout << "----" << endl;
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
} int main() { test01(); system("pause"); return 0; }

运行结果:

10 20 30 40 50
----
50 40 30 20 10

类型转换

除了能使用c语言的强制类型转换外,还有:转换操作符 (新式转换)

const_cast

修改类型的const或volatile属性

const char *a;
char *b = const_cast<char*>(a); char *a;
const char *b = const_cast<const char*>(a);

static_cast

  1. 基础类型之间互转。如:float转成int、int转成unsigned int等
  2. 指针与void之间互转。如:float*转成void*、Bean*转成void*、函数指针转成void*等
  3. 子类指针/引用与 父类指针/引用 转换。
class Parent {
public:
void test() {
cout << "p" << endl;
}
};
class Child :public Parent{
public:
void test() {
cout << "c" << endl;
}
};
Parent *p = new Parent;
Child *c = static_cast<Child*>(p);
//输出c
c->test(); //Parent test加上 virtual 输出 p

dynamic_cast

主要 将基类指针、引用 安全地转为派生类.

在运行期对可疑的转型操作进行安全检查,仅对多态有效

//基类至少有一个虚函数
//对指针转换失败的得到NULL,对引用失败 抛出bad_cast异常
Parent *p = new Parent;
Child *c = dynamic_cast<Child*>(p);
if (!c) {
cout << "转换失败" << endl;
} Parent *p = new Child;
Child *c = dynamic_cast<Child*>(p);
if (c) {
cout << "转换成功" << endl;
}

reinterpret_cast

对指针、引用进行原始转换

float i = 10;

//&i float指针,指向一个地址,转换为int类型,j就是这个地址
int j = reinterpret_cast<int>(&i);
cout << hex << &i << endl;
cout << hex << j << endl; cout<<hex<<i<<endl; //输出十六进制数
cout<<oct<<i<<endl; //输出八进制数
cout<<dec<<i<<endl; //输出十进制数

char*与int转换

//char* 转int float
int i = atoi("1");
float f = atof("1.1f");
cout << i << endl;
cout << f << endl; //int 转 char*
char c[10];
//10进制
itoa(100, c,10);//itoa并不是一个标准的C函数,它是Windows特有的
cout << c << endl; //int 转 char*
char c1[10];
sprintf(c1, "%d", 100);
cout << c1 << endl;

异常

void test1()
{
throw "测试!";
} void test2()
{
throw exception("测试");
} try {
test1();
}
catch (const char *m) {
cout << m << endl;
}
try {
test2();
}
catch (exception &e) {
cout << e.what() << endl;
} //自定义
class MyException : public exception
{
public:
virtual char const* what() const
{
return "myexception";
}
}; //随便抛出一个对象都可以

文件与流操作

C 语言的文件读写操作

头文件:stdio.h

函数原型:FILE * fopen(const char * path, const char * mode);

path: 操作的文件路径

mode:模式

模式 描述
r 打开一个已有的文本文件,允许读取文件。
w 打开一个文本文件,允许写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会从文件的开头写入内容。如果文件存在,则该会被截断为零长度,重新写入。
a 打开一个文本文件,以追加模式写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会在已有的文件内容中追加内容。
r+ 打开一个文本文件,允许读写文件。
w+ 打开一个文本文件,允许读写文件。如果文件已存在,则文件会被截断为零长度,如果文件不存在,则会创建一个新文件。
a+ 打开一个文本文件,允许读写文件。如果文件不存在,则会创建一个新文件。读取会从文件的开头开始,写入则只能是追加模式。
//========================================================================
FILE *f = fopen("xxxx\\t.txt","w");
//写入单个字符
fputc('a', f);
fclose(f); FILE *f = fopen("xxxx\\t.txt","w");
char *txt = "123456";
//写入以 null 结尾的字符数组
fputs(txt, f);
//格式化并输出
fprintf(f,"%s",txt);
fclose(f); //========================================================================
fgetc(f); //读取一个字符 char buff[255];
FILE *f = fopen("xxxx\\t.txt", "r");//This is testing for fputs...
//读取 遇到第一个空格字符停止
fscanf(f, "%s", buff);
printf("1: %s\n", buff);//1: This //最大读取 255-1 个字符
fgets(buff, 255, f);
printf("2: %s\n", buff);//2: is testing for fprintf... fgets(buff, 255, (FILE*)fp);
printf("3: %s\n", buff );//3: This is testing for fputs...
fclose(f);
//首先,fscanf() 方法只读取了 This,因为它在后边遇到了一个空格。其次,调用 fgets() 读取剩余的部分,直到行尾。最后,调用 fgets() 完整地读取第二行。 //二进制 I/O 函数
size_t fread(void *ptr, size_t size_of_elements,
size_t number_of_elements, FILE *a_file);
size_t fwrite(const void *ptr, size_t size_of_elements,
size_t number_of_elements, FILE *a_file);
//1、写入/读取数据缓存区
//2、每个数据项的大小
//3、多少个数据项
//4、流
//如:图片、视频等以二进制操作:
//写入buffer 有 1024个字节
fwrite(buffer,1024,1,f);

C++ 文件读写操作

<iostream> 和 <fstream>

数据类型 描述
ofstream 输出文件流,创建文件并向文件写入信息。
ifstream 输入文件流,从文件读取信息。
fstream 文件流,且同时具有 ofstream 和 ifstream 两种功能。
char data[100];
// =====以写模式打开文件=======
ofstream outfile;
outfile.open("XXX\\f.txt");
cout << "输入你的名字: ";
//cin 接收终端的输入
cin >> data;
// 向文件写入用户输入的数据
outfile << data << endl;
// 关闭打开的文件
outfile.close(); // =======以读模式打开文件=======
ifstream infile;
infile.open("XXX\\f.txt"); //这一句等于上面两句
//ifstream inFile("XXX\\f.txt"); cout << "读取文件" << endl;
infile >> data;
cout << data << endl; //读取一行,放入到data中
inFile.getline(data,100);
cout << data << endl; //读取一行,放入string中
#include <string>
string s;
getline(inFile,s);
cout << s <<endl; // 关闭
infile.close();

C++容器、类型转换、异常与文件流操作的更多相关文章

  1. ndk学习之c++语言基础复习----C++容器、类型转换、异常与文件流操作

    继续来复习C++,比较枯燥,但是这是扎实掌握NDK开发的必经之路,不容小觑. 容器: 容器,就是用来存放东西的盒子. 常用的数据结构包括:数组array, 链表list, 树tree, 栈stack, ...

  2. delphi 基础之三 文件流操作

    文件流操作 Delphi操作流文件:什么是流?流,简单来说就是建立在面向对象基础上的一种抽象的处理数据的工具.在流中,定义了一些处理数据的基本操作,如读取数据,写入数据等,程序员是对流进行所有操作的, ...

  3. (C/C++学习)2.C语言中文件流操作基本函数总结

    函数所在头文件:stdio.h 说明:前半部分主要为对各个文件流操作函数的例举,后半部分着重于上机运行分析.文中部分引用自王桂林老师的C/C++课件. 1.FIELE *fopen(const cha ...

  4. c++ ofstream & ifstream文件流操作

    ofstream是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间; //ofstream & ifstream inherit from istream class ...

  5. c#基础语言编程-文件流操作

    引言 在System.IO 命名空间下提供了一系列的类,我们可以通过相应的类进行文件.目录.数据流的操作. 1.File类:提供用于创建.复制.删除.移动和打开文件的静态方法.File类 2.File ...

  6. C++中输入输出流及文件流操作笔记

    1.流的控制 iomanip          在使用格式化I/O时应包含此头文件.    stdiostream   用于混合使用C和C + +的I/O机制时,例如想将C程序转变为C++程序 2.类 ...

  7. C++文件编程(文件流操作)

    给出了比较常见的文件操作,包括二进制文件操作.代码如下: #include<iostream> #include<cstdio> #include<cstring> ...

  8. (十四)QFile操作,QByteArray,文件流操作,QTextStream,QDataStream,QFileInfo, QIODevice

    QFile f 1.readall #include "widget.h" #include "ui_widget.h" #include <QFileD ...

  9. C++学习7-面向对象编程基础(多态性与虚函数、 IO文件流操作)

    多态 多态性是指对不同类的对象发出相同的消息将返回不同的行为,消息主要是指类的成员函数的调用,不同的行为是指不同的实现: 函数重载 函数重载是多态性的一种简单形式,它是指允许在相同的作用域内,相同的函 ...

  10. C++中文件流操作

    一.C++中流和流操作符 C++中把数据之间的传输操作称为流,流既可以表示数据从内存传送到某个载体或设备中,即输出流,也可以表示数据从某个载体或设备传送到内存缓冲区变量中,即输入流.C++输入输出除了 ...

随机推荐

  1. Vue +Spring Boot 前后端分离 的 项目 笔记

    Vue +Spring Boot 前后端分离 的 项目 笔记 前端部分 Vue 脚手架的搭建 1.在创建目录的上一目录执行命令 命令为 vue init webpack 项目名 再创建项目的时候会自动 ...

  2. RabbitMQ基础学习Full版

    RabbitMQ 消息队列在软件中的应用场景 异步处理上(优于原先的方式) 为什么优于呢? 首先,通常情况下,如上图我们其实不用消息队列的情况下,其实也可以不用100ms,不用allof即可 那么优势 ...

  3. 借助 .NET 开源库 Sdcb.DashScope 调用阿里云灵积通义千问 API

    在昨天的博文中,我们通过 Semantic Kernel 调用了自己部署的通义千问开源大模型,但是自己部署通义千问对服务器的配置要求很高,即使使用抢占式按量实例,每次使用时启动服务器,使用完关闭服务器 ...

  4. CF1795

    A 先判断初始行不行,再模拟加入. B 题意:数轴上给定一些线段,和点 \(t\).问能否删去一些线段,使得 \(t\) 变成唯一的覆盖次数最多的点. 差分 + 贪心. C 有 \(n\) 杯水,\( ...

  5. Executors.newFixedThreadPool(int nThreads)存在的缺陷

    一般来讲是不推荐直接使用JAVA提供的Executors类来初始化线程池,如果有需要可以自行通过ThreadPoolExecutor来封装进行初始化. 可以用newFixedThreadPool(in ...

  6. 延时队列 DelayQueue

    当用户超时未支付时,给用户发提醒消息.另一种场景是,超时未付款,订单自动取消.通常,订单创建的时候可以向延迟队列种插入一条消息,到时间自动执行.其实,也可以用临时表,把这些未支付的订单放到一个临时表中 ...

  7. js获取格式化日期方法

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. 一键部署Home Assistant ubuntu 20.4.3 树莓派3b+脚本

      树莓派3b+安装好 Ubuntu Server 20.04.3 LTS 32bit 后即可适用此脚本,其他版本树莓派/系统可能需要微调脚本*为方便一些未知/已知错误排查 脚本存在冗余部分,足够了解 ...

  9. redis7源码分析:redis 启动流程

    1. redis 由 server.c 的main函数启动 int main(int argc, char **argv) { ... // 上面的部分为读取配置和启动命令参数解析,看到这一行下面为启 ...

  10. 项目实战:Qt编译Qt库以及使用C#调用Qt库,并实现C#集成Qt的tcp客户端

    需求   1.Qt已经开发了应用,封装成Qt库,以供C#调用.  2.Qt的tcp客户端封装,以供C#调用,双向传递数据.   原理   1.使用QtCreator编译msvc版本的Qt库:  2.使 ...