C++(二) 容器、類(lèi)型轉(zhuǎn)換、異常與文件流操作

容器

容器,就是用來(lái)存放東西的盒子。

常用的數(shù)據(jù)結(jié)構(gòu)包括:數(shù)組array, 鏈表list, 樹(shù)tree, 棧stack, 隊(duì)列queue, 散列表hash table, 集合set、映射表map 等等。容器便是容納這些數(shù)據(jù)結(jié)構(gòu)的。這些數(shù)據(jù)結(jié)構(gòu)分為序列式與關(guān)聯(lián)式兩種,容器也分為序列式容器和關(guān)聯(lián)式容器。

STL 標(biāo)準(zhǔn)模板庫(kù),核心包括容器、算法、迭代器。

序列式容器/順序容器

元素排列次序與元素?zé)o關(guān),由元素添加到容器的順序決定

容器 說(shuō)明
vector 支持快速隨機(jī)訪問(wèn)
list 支持快速插入、刪除
deque 雙端隊(duì)列 允許兩端都可以進(jìn)行入隊(duì)和出隊(duì)操作的隊(duì)列
stack 后進(jìn)先出LIFO(Last In First Out)堆棧
queue 先進(jìn)先出FIFO(First Input First Output)隊(duì)列
priority_queue 有優(yōu)先級(jí)管理的queue

向量(vector)

連續(xù)存儲(chǔ)的元素

列表 (list)

由節(jié)點(diǎn)組成的雙向鏈表,每個(gè)結(jié)點(diǎn)包含著一個(gè)元素

雙端隊(duì)列(deque)

連續(xù)存儲(chǔ)的指向不同元素的指針?biāo)M成的數(shù)組

以上三種容器操作基本一樣

基本操作:

#include <vector>
using namespace std;

vector<int> vec_1;
//1個(gè)元素
vector<int> vec_2(1);
//6個(gè)值為 1 的元素
vector<int> vec_3(6,1);
//使用容器初始化
vector<int> vec_4(vec_3);

//通過(guò)下標(biāo)操作元素
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();

//釋放
//可以單個(gè)清除,也可以清除一段區(qū)間里的元素
vec_3.erase(vec_3.begin(),vec_3.end())
//清理容器 即erase所有
vec_3.clear(); 

//容量大小
vec_3.capacity();
//在容器中,其內(nèi)存占用的空間是只增不減的,
//clear釋放元素,卻不能減小vector占用的內(nèi)存
//所以可以對(duì)vector 收縮到合適的大小 
vector< int >().swap(vec_3);  

//在vec是全局變量時(shí)候
//建立臨時(shí)vector temp對(duì)象,swap調(diào)用之后對(duì)象vec占用的空間就等于默認(rèn)構(gòu)造的對(duì)象的大小
//temp就具有vec的大小,而temp隨即就會(huì)被析構(gòu),從而其占用的空間也被釋放。

迭代器

//獲得指向首元素的迭代器  模板類(lèi),不是指針,當(dāng)做指針來(lái)使用
vector<int>::iterator it = vec.begin();
//遍歷元素
for (; it < vec.end(); it++)
{
 cout << *it << endl;
}
//begin和end   分別獲得 指向容器第一個(gè)元素和最后一個(gè)元素下一個(gè)位置的迭代器
//rbegin和rend 分別獲得 指向容器最后一個(gè)元素和第一個(gè)元素前一個(gè)位置的迭代器

//注意循環(huán)中操作元素對(duì)迭代器的影響
vector<int>::iterator it = vec.begin();
for (; it < vec.end(); )
{
 //刪除值為2的元素 
 if (*it == 2) {
 vec.erase(it);
 }
 else {
 it++;
 }
}

棧(stack)

后進(jìn)先出的值的排列

stack<int> s;
//入棧
s.push(1);
s.push(2);
//彈棧
s.pop();
//棧頂
cout << s.top() << endl;

隊(duì)列(queue)

先進(jìn)先出的值的排列

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

優(yōu)先隊(duì)列(priority_queue )

元素的次序是由所存儲(chǔ)的數(shù)據(jù)的某個(gè)值排列的一種隊(duì)列

//最大的在隊(duì)首
priority_queue<int>;
//在vector之上實(shí)現(xiàn)的
priority_queue<int, vector<int>, less<int> >; 
//vector 承載底層數(shù)據(jù)結(jié)構(gòu)堆的容器
//less 表示數(shù)字大的優(yōu)先級(jí)高,而 greater 表示數(shù)字小的優(yōu)先級(jí)高
//less       讓優(yōu)先隊(duì)列總是把最大的元素放在隊(duì)首
//greater    讓優(yōu)先隊(duì)列總是把最小的元素放在隊(duì)首

//less和greater都是一個(gè)模板結(jié)構(gòu)體 也可以自定義

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;

關(guān)聯(lián)式容器

關(guān)聯(lián)容器和大部分順序容器操作一致

關(guān)聯(lián)容器中的元素是按關(guān)鍵字來(lái)保存和訪問(wèn)的 支持高效的關(guān)鍵字查找與訪問(wèn)

集合(set)

由節(jié)點(diǎn)組成的紅黑樹(shù),每個(gè)節(jié)點(diǎn)都包含著一個(gè)元素,元素不可重復(fù)

set<string> a;  
set<string> a1={"fengxin","666"};
a.insert("fengxin");  // 插入一個(gè)元素
a.erase("123");  //刪除

鍵值對(duì)(map)

由{鍵,值}對(duì)組成的集合

map<int, string> m;
map<int, string> m1 = { { 1,"aa" },{ 2,"bb" } };
//插入元素
m1.insert({ 3,"dd" });
//pair=鍵值對(duì)
pair<int, string> p(4, "gg");
m1.insert(p);
//insetrt 返回 map<int, string>::iterator : bool 鍵值對(duì)
//如果 插入已經(jīng)存在的 key,則會(huì)插入失敗 
//multimap:允許重復(fù)key
//使用m1[3] = "xx" 能夠覆蓋


//通過(guò)【key】操作元素
m1[5] = "yihan";
cout << m1[5].c_str() << endl; 
//通過(guò)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(哈希表實(shí)現(xiàn),無(wú)序)

哈希表實(shí)現(xiàn)查找速度會(huì)比RB樹(shù)實(shí)現(xiàn)快,但rb整體更節(jié)省內(nèi)存

需要無(wú)序容器,高頻快速查找刪除,數(shù)據(jù)量較大用unordered_map;

需要有序容器,查找刪除頻率穩(wěn)定,在意內(nèi)存時(shí)用map。

類(lèi)型轉(zhuǎn)換

除了能使用c語(yǔ)言的強(qiáng)制類(lèi)型轉(zhuǎn)換外,還有:轉(zhuǎn)換操作符 (新式轉(zhuǎn)換)

const_cast

修改類(lèi)型的const或volatile屬性

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

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

static_cast

  1. 基礎(chǔ)類(lèi)型之間互轉(zhuǎn)。如:float轉(zhuǎn)成int、int轉(zhuǎn)成unsigned int等
  1. 指針與void之間互轉(zhuǎn)。如:float轉(zhuǎn)成void、Bean轉(zhuǎn)成void、函數(shù)指針轉(zhuǎn)成void*等
  1. 子類(lèi)指針/引用與 父類(lèi)指針/引用 轉(zhuǎn)換。
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

主要 將基類(lèi)指針、引用 安全地轉(zhuǎn)為派生類(lèi).

在運(yùn)行期對(duì)可疑的轉(zhuǎn)型操作進(jìn)行安全檢查,僅對(duì)多態(tài)有效

//基類(lèi)至少有一個(gè)虛函數(shù)
//對(duì)指針轉(zhuǎn)換失敗的得到NULL,對(duì)引用失敗  拋出bad_cast異常 
Parent  *p = new Parent;
Child  *c = dynamic_cast<Child*>(p);
if (!c) {
 cout << "轉(zhuǎn)換失敗" << endl;
}


Parent  *p = new Child;
Child  *c = dynamic_cast<Child*>(p);
if (c) {
 cout << "轉(zhuǎn)換成功" << endl;
}

reinterpret_cast

對(duì)指針、引用進(jìn)行原始轉(zhuǎn)換

float i = 10;

//&i float指針,指向一個(gè)地址,轉(zhuǎn)換為int類(lèi)型,j就是這個(gè)地址
int j = reinterpret_cast<int>(&i);
cout  << hex << &i << endl;
cout  << hex  << j << endl;

cout<<hex<<i<<endl; //輸出十六進(jìn)制數(shù)
cout<<oct<<i<<endl; //輸出八進(jìn)制數(shù)
cout<<dec<<i<<endl; //輸出十進(jìn)制數(shù)

char*與int轉(zhuǎn)換

//char* 轉(zhuǎn)int float
int i = atoi("1");
float f = atof("1.1f");
cout << i << endl;
cout << f << endl;

//int 轉(zhuǎn) char*
char c[10];
//10進(jìn)制
itoa(100, c,10);
cout << c << endl;

//int 轉(zhuǎn) char*
char c1[10];
sprintf(c1, "%d", 100);
cout << c1 << endl;

異常

void test1()
{
 throw "測(cè)試!";
}

void test2()
{
 throw exception("測(cè)試");
}

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";
 }
};

//隨便拋出一個(gè)對(duì)象都可以

文件與流操作

C 語(yǔ)言的文件讀寫(xiě)操作

頭文件:stdio.h

函數(shù)原型:FILE * fopen(const char * path, const char * mode);

path: 操作的文件路徑

mode:模式

模式 描述
r 打開(kāi)一個(gè)已有的文本文件,允許讀取文件。
w 打開(kāi)一個(gè)文本文件,允許寫(xiě)入文件。如果文件不存在,則會(huì)創(chuàng)建一個(gè)新文件。在這里,您的程序會(huì)從文件的開(kāi)頭寫(xiě)入內(nèi)容。如果文件存在,則該會(huì)被截?cái)酁榱汩L(zhǎng)度,重新寫(xiě)入。
a 打開(kāi)一個(gè)文本文件,以追加模式寫(xiě)入文件。如果文件不存在,則會(huì)創(chuàng)建一個(gè)新文件。在這里,您的程序會(huì)在已有的文件內(nèi)容中追加內(nèi)容。
r+ 打開(kāi)一個(gè)文本文件,允許讀寫(xiě)文件。
w+ 打開(kāi)一個(gè)文本文件,允許讀寫(xiě)文件。如果文件已存在,則文件會(huì)被截?cái)酁榱汩L(zhǎng)度,如果文件不存在,則會(huì)創(chuàng)建一個(gè)新文件。
a+ 打開(kāi)一個(gè)文本文件,允許讀寫(xiě)文件。如果文件不存在,則會(huì)創(chuàng)建一個(gè)新文件。讀取會(huì)從文件的開(kāi)頭開(kāi)始,寫(xiě)入則只能是追加模式。
FILE *f = fopen("xxxx\\t.txt","w");
//寫(xiě)入單個(gè)字符
fputc('a', f);
fclose(f);


FILE *f = fopen("xxxx\\t.txt","w");
char *txt = "123456";
//寫(xiě)入以 null 結(jié)尾的字符數(shù)組
fputs(txt, f);
//格式化并輸出
fprintf(f,"%s",txt);
fclose(f);

//========================================================================
fgetc(f); //讀取一個(gè)字符

char buff[255];
FILE *f = fopen("xxxx\\t.txt", "r");
//讀取 遇到第一個(gè)空格字符停止
fscanf(f, "%s", buff);
printf("1: %s\n", buff);

//最大讀取 255-1 個(gè)字符
fgets(buff, 255, f);
printf("2: %s\n", buff);
fclose(f);

//二進(jìn)制 I/O 函數(shù)
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、寫(xiě)入/讀取數(shù)據(jù)緩存區(qū)
//2、每個(gè)數(shù)據(jù)項(xiàng)的大小
//3、多少個(gè)數(shù)據(jù)項(xiàng)
//4、流
//如:圖片、視頻等以二進(jìn)制操作:
//寫(xiě)入buffer 有 1024個(gè)字節(jié)
fwrite(buffer,1024,1,f);

C++ 文件讀寫(xiě)操作

<iostream> 和 <fstream>

數(shù)據(jù)類(lèi)型 描述
ofstream 輸出文件流,創(chuàng)建文件并向文件寫(xiě)入信息。
ifstream 輸入文件流,從文件讀取信息。
fstream 文件流,且同時(shí)具有 ofstream 和 ifstream 兩種功能。
char data[100];
// 以寫(xiě)模式打開(kāi)文件
ofstream outfile;
outfile.open("XXX\\f.txt");
cout << "輸入你的名字: ";
//cin 接收終端的輸入
cin >> data;
// 向文件寫(xiě)入用戶輸入的數(shù)據(jù)
outfile << data << endl;
// 關(guān)閉打開(kāi)的文件
outfile.close();

// 以讀模式打開(kāi)文件
ifstream infile;
infile.open("XXX\\f.txt");

cout << "讀取文件" << endl;
infile >> data;
cout << data << endl;

// 關(guān)閉
infile.close();
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容