C++常用總結
author@jason_ql(lql0716)
http://blog.csdn.net/lql0716
1 std:vector
- 學習C++ 向量(vector)
http://www.cnblogs.com/mr-wid/archive/2013/01/22/2871105.html
size()指 目前存在的元素數。 元素個數
capacity()指 容器能存儲 數據的個數 容器 容量
reserve()指定 容器 能存儲數據的個數
resize() 重新 指定 有效元素的個數 ,區別與reserve()指定 容量的大小
1.1 向量vector的複製、拷貝
1、vector是一個構造對象,不能直接使用=符號進行復制,必須迭代每個元素來複制。或者重載=操作符。
2、大致有一下幾種方法實現用於把一個vector複製給另一個vector:
方法1:
vector<int > v1(v2); //聲明
方法2:使用swap進行賦值:
vector<int > v1();v1.swap(v2);//將v2賦值給v1,此時v2變成了v1
方法3:使用函數assign進行賦值:
vector<int > v1;//聲明v1
v1.assign(v2.begin(), v2.end());//將v2賦值給v1
方法4:使用循環語句賦值,效率較差
vector<int >::iterator it;//聲明迭代器
for(it = v2.begin();it!=v2.end();++it){//遍歷v2,賦值給v1
v1.push_back(it);
}
1.2 二維向量初始化
vector<vector<int> > array(m); //這個m一定不能少
//初始化一個m*n的二維數組
for(int i=0;i<m;i++) {
array[i].resize(n);
}
1.3 向量的其他操作
1 a.size() //獲取向量中的元素個數
2 a.empty() //判斷向量是否爲空
3 a.clear() //清空向量中的元素
4 複製
a = b ; //將b向量複製到a向量中
5 比較
保持 ==、!=、>、>=、<、<= 的慣有含義 ;
如: a == b ; //a向量與b向量比較, 相等則返回1
6 插入 - insert
a.insert(a.begin(), 1000); //將1000插入到向量a的起始位置前
a.insert(a.begin(), 3, 1000) ; //將1000分別插入到向量元素位置的0-2處(共3個元素)
vector<int> a(5, 1) ;
vector<int> b(10) ;
b.insert(b.begin(), a.begin(), a.end()) ; //將a.begin(), a.end()之間的全部元素插入到b.begin()前
7 刪除 - erase
1、 b.erase(b.begin()) ; //將起始位置的元素刪除
2、 b.erase(b.begin(), b.begin()+3) ; //將(b.begin(), b.begin()+3)之間的元素刪除
8 交換 - swap
b.swap(a) ; //a向量與b向量進行交換
- 示例
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main(){
std::vector<int> a(5);
for(int i = 0; i < 5; i++){
a[i] = i;
std::cout << "a[" << i << "] = " << i << std::endl;
}
a.erase(a.begin());
std::cout << "\n" << std::endl;
for(int i = 0; i < 5; i++){
std::cout << "a[" << i << "] = " << a[i] << std::endl;
}
}
#輸出結果
a[0] = 0
a[1] = 1
a[2] = 2
a[3] = 3
a[4] = 4
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 4
a[4] = 4
- 刪除操作
.erase()
#include <opencv2\opencv.hpp>
#include <fstream>
#include <vector>
using namespace cv;
using namespace std;
void select(std::vector<int> & vec){
for (int r = 0; r < vec.size(); r++){
if (vec[r] % 2 == 0){
std::vector<int>::iterator it = vec.begin() + r;
vec.erase(it);
select(vec);
}
}
}
int main(){
std::vector<int> vec(20);
for (int i = 0; i < 20; i++){
vec[i] = i;
std::cout << vec[i] << std::endl;
}
select(vec);
return 0;
}
1.4 輸出向量到txt文件
#include <fstream>
std::vector<Point> kp;
ofstream out("vector.txt", ios::out);
for (int r = 0; r < 20; r++){
out << kp[r] << "\n" << endl;
}
2 struct 和 typedef struct
3 類型轉換
- C++數值類型與string的相互轉換
http://blog.csdn.net/k346k346/article/details/50927002
3.1 類型初始化
int a = 0;
float a = 0.0f;
double a = 0.0;
string a = "good";
4 隊列容器 queue
queue在
<queue>
頭文件中queue與stack非常類似,queue也需要定義兩個模板參數,一個是容器類型,一個是元素類型,元素類型是必要的。
queue定義:
queue<int> q;
或queue<double> q2;
- queue操作:
#include <queue>
int main(){
queue<int> q;
q.push(x); //將x存入隊列末端
q.pop(); //彈出隊列的第一個元素,並且不會返回元素的值
q.front(); //訪問隊首的元素
q.back(); //訪問隊尾的元素
q.size(); //訪問隊列的元素個數
q.empty(); //當隊列爲空時,返回true
}
5 堆棧 stack
stack在
<stack>
頭文件中stack需要定義兩個模板參數,一個是容器類型,一個是元素類型,元素類型是必要的,在不指定容器類型時,默認的容器類型爲deque
stack定義:
stack<int> s;
或stack<double> s2;
- stack操作:
#include <stack>
int main(){
stack<int> s;
s.push(x); //將x存入棧
s.pop(); //出棧,刪除棧頂元素,並且不會返回元素的值
s.top(); //訪問棧頂的元素
s.size(); //訪問棧的元素個數
s.empty(); //當棧爲空時,返回true
}
6 unsigned int
整型的每一種都分有無符號(unsigned)和有符號(signed)兩種類型(float和double總是帶符號的),在默認情況下聲明的整型變量都是有符號的類型(char有點特別),如果需聲明無符號類型的話就需要在類型前加上unsigned。無符號版本和有符號版本的區別就是無符號類型能保存2倍於有符號類型的正整數數據,比如16位系統中一個int能存儲的數據的範圍爲-32768~32767,而unsigned能存儲的數據範圍則是0~65535。由於在計算機中,整數是以補碼形式存放的。根據最高位的不同,如果是1,有符號數的話就是負數;如果是無符號數,則都解釋爲正數。另外,unsigned若省略後一個關鍵字,大多數編譯器都會認爲是unsigned int。
無符號整型
size_t
7 static_cast
static成員函數中不能使用this指針
- 即使沒有實例化類的對象,static數據成員和成員函數仍然可以使用
- static成員的名字在類的作用域中,因此可以避免與其他類的成員或者全局對象名字衝突
- 可以實施封裝,static成員可以是私有成員,而全局對象不可以
8 打印 std::cout、std::endl
- 橫向打印
int a[10]={1,2,3}; //初始化前三個元素,其餘元素爲0
for( int i=0;i<10;i++ )
cout << a[i] <<" " ;
cout <<endl ; //輸出結果:1 2 3 0 0 0 0 0 0 0
9 數學函數
1、atan(x) #表示求的是x的反正切,其返回值爲[-pi/2,+pi/2]之間的一個數。
2、atan2(y,x) #求的是y/x的反正切,其返回值爲[-pi,+pi]之間的一個數。
3、exp(double)
4、pow(double x, double y) #表示x的y次方
5、sqrt(double x) #表示x開平方
6、log(double x) #表示以e爲底,x的對數
7、log10(double x) #表示以10爲底,x的對數
8、asin(double x) #反正弦,結果在[-pi / 2, pi / 2]
9、acos(double x) #反餘弦,結果在[0, pi]
10、sinh(double x), cosh(double x), tanh(double x) #雙曲
10 namespace的用法
namespace的用法
http://www.cnblogs.com/CBDoctor/archive/2011/12/05/2276563.htmlC++中namesapce必須在
.h
文件、.cpp
文件同時定義,以同樣的方法定義,如下例子
//test.h文件
#ifndef TEST_H
#define TEST_H
namespace exm{
void test1();
};
#endif
//-----------------------------------
// test.cpp文件
#include <iostream>
#include "test.h"
namespace exm{
void test1(){
std::cout << "test" << std::endl;
}
};
#include <iostream>
#include <string>
using namespace std;
//using namespace編譯指示,使在C++標準類庫中定義的名字在本程序中可以使用
//否則,iostream,string等c++標準類就不可見了,編譯就會出錯。
//兩個在不同命名空間中定義的名字相同的變量
namespace myown1{
string user_name = "myown1";
}
namespace myown2{
string user_name = "myown2";
}
int main()
{
cout<< "/n"
<< "Hello, "
<< myown1::user_name //用命名空間限制符myown1訪問變量user_name
<< "... and goodbye!/n";
cout<< "/n"
<< "Hello, "
<< myown2::user_name //用命名空間限制符myown2訪問變量user_name
<< "... and goodbye!/n";
return 0;
}
當然,我們也可以使用程序開頭的預編譯指示來使用命名空間中的名字。使用預編譯指示的好處在於在程序中不必顯式地使用命名空間限制符來訪問變量。以上主程序可修改爲:
int main()
{
using namespace myown1;
cout<< "/n"
<< "Hello, "
<< user_name
<< "... and goodbye!/n";
// using namespace myown2;
cout<< "/n"
<< "Hello, "
<< myown2::user_name //用命名空間限制符myown2訪問變量user_name
<< "... and goodbye!/n";
return 0;
}
但第二個變量必需用命名空間限制符來訪問,因爲此時myown1空間中的變量已經可見,如果不加限制,編譯器就會無法識別是那一個命名空間中的變量。這一點一定要注意。 以上只是初學者不清楚的一個概念,在以後的文章中還將繼續討論其它的一些概念。
下面寫一段完整的程序來表明這個函數的用法;
#include<iostream>
using namespace std;
namespace Cui{
void Love()
{
cout<<"He love a wonderful girl, and her name is SHILI"<<endl;
}
}
using namespace Cui;
int main()
{
int a=10;
cout<<a<<endl;
Love();
Cui::Love(); //調用方式2
return 0;
}
11 模板 template
模板:包括函數模板、類模板
模板使程序員能夠快速建立具有類型安全的類庫集合和函數集合,它的實現,方便了大規模的軟件開發。
對於具有各種參數類型,相同個數,相同順序的同一函數(重載函數),如果用宏定義來寫:
#define max(a,b) ( (a) > (b) ? (a) : (b) )
則它不能檢查其數據類型,損害了類型的安全性,如果用模板,則爲:
template<class T>
T max(T a, Tb){
return a > b ? a : b;
}
泛型編程
- 獨立於任何特定類型的方式編寫代碼
- 模板用於表達邏輯結構相同,但是具體數據元素類型不同的數據對象的通用行爲
模板是泛型編程的基礎
- 通過模板能夠快速建立具有類型安全的類庫集合和函數集合,使用模板操作不同的數據類型,從而避免需要爲每一種數據類型產生一個單獨類或者函數
類模板的作用
- 將程序要處理的對象的類型參數化
- 使程序可以處理不同類型的對象
template
template < class 形參名, class 形參名, ... > 返回類型 函數名(參數列表)
{
函數體
}
- 求絕對值的模板示例
#include <iostream>
using namespace std;
template<typename T>T abs(T x){
return x < 0? -x : x;
} # typename爲類型
int main(){
int n = -5;
double d = -5.5;
cout << abs(n) << endl;
cout << abs(d) << endl;
}
12 opencv中的智能指針模板類Ptr
- opencv中的智能指針模板類Ptr
http://www.tuicool.com/articles/3QNvuu
13 枚舉 enum
14 條件運算符
- 條件運算符
?:
- C++ 條件運算符(三目運算符)
http://www.weixueyuan.net/view/5815.html
15 sizeof( int )
sizeof(int) = 每個數據類型長度
16 類的繼承 class Child: public Parent{}
C++繼承:公有,私有,保護
http://www.cnblogs.com/qlwy/archive/2011/08/25/2153584.html
17 VS編譯之後不關閉cmd窗口(system(“pause”))
#include <opencv2\opencv.hpp>
#include <hash_map>
using namespace cv;
using namespace std;
int main(){
std::cout << "5" << std::endl;
system("pause");
return 0;
}
18 哈希表
- map
- hash_map
- unordered_map
- unordered_set
C++中map容器的說明和使用技巧
http://www.cnblogs.com/anywei/archive/2011/10/27/2226830.html散列表查找(哈希表)的基本操作 (完整代碼)
http://blog.csdn.net/fengyanglian/article/details/49664483C++ STL中哈希表 hash_map介紹
http://blog.csdn.net/ddkxddkx/article/details/6555754Hash表
http://www.cnblogs.com/dolphin0520/archive/2012/09/28/2700000.html數據結構複習之散列表查找(哈希表)
http://www.cnblogs.com/changyaohua/p/4657205.htmlSTL中std::map用法詳解
http://blog.csdn.net/tangketan/article/details/7691472定位式查找—哈希表
http://blog.csdn.net/u014494703/article/details/51285829C++ map的基本操作和使用
http://www.cnblogs.com/hailexuexi/archive/2012/04/10/2440209.html算法導論-散列表(Hash Table)-大量數據快速查找算法
http://www.cnblogs.com/zhoutaotao/p/4067749.html#sanliehanshu
19 面向對象
19.1 類 & 對象
類
類是創建對象的模板和藍圖
類是一組類似對象的共同抽象定義對象
對象是類的實例化結果
對象是實實在在存在的,代表現實世界的某一事物對象的三大關鍵特性
行爲:對象能幹什麼
狀態:對象的屬性,行爲的結果
標識:對象的唯一身份類與對象的區別
類是靜態定義
對象是動態實例
程序代碼操作的是對象而非類
建模得到的是類而非對象類的定義格式
class 類名稱{
public:
//公有函數
protected:
//保護成員
private:
//私有函數
//私有數據成員
int val; //數據成員
};
19.1.1 類成員函數
19.1.2 類訪問修飾符
19.1.3 構造函數 & 析構函數
- 類的對象的初始化只能由類的成員函數來進行
- 建立對象的同時,自動調用構造函數
- 類對象的定義涉及到一個類名和一個對象名
- 由於類的唯一性和對象的多樣性,用類名而不是對象名來作爲構造函數名是比較合適的
- 默認構造函數(如果沒有定義構造函數,則用默認構造函數,默認的構造函數初始化的值爲隨機的)
- 構造函數負責對象初始化工作,將數據成員初始化
- 創建對象時,其類的構造函數確保:在用戶操作對象之前,系統保證初始化的進行
- 建立對象,須有一個有意義的初始值
- C++ 建立和初始化對象的過程專門由該類的構造函數來完成
- 構造函數給對象分配空間和初始化
- 如果一個類設有專門定義構造函數,那麼C++就僅僅創建對象而不做任何初始化
- 構造方法滿足以下語法規則:
- 構造方法名與類名相同
- 沒有返回類型
- 方法實現主要爲字段賦初值
- 放在外部定義的構造函數,其函數名前要加上“類名::”
- 構造函數可以有多個
- 構造函數可以重載
- 析構函數(~)
- C++析構函數(Destructor)
http://c.biancheng.net/cpp/biancheng/view/196.html- 一個類可能在構造函數裏分配資源,這些資源需要在對象不復存在以前被釋放
- 析構函數也是特殊類型的成員,它沒有返回類型,沒有參數,不能隨意調用,也沒用重載。只是在類對象生命期結束的時候,由系統自動調用
- 析構函數名,就是在構造函數名前面加上一個邏輯非運算符
~
,表示“逆構造函數”- 如果類沒有自定義析構函數,則編譯器提供一個默認的析構函數
19.1.4 拷貝構造函數
參考
http://www.runoob.com/cplusplus/cpp-copy-constructor.html拷貝構造函數(copy constructor)是一種特殊的構造函數,具有單個形參,此形參是對該類型的引用。當定義一個新對象並用一個同類型的對象對它進行初始化時,將顯示使用拷貝構造函數。
- 當將該類型的對象傳遞給函數或從函數返回該類型的對象時,將隱式的調用拷貝構造函數
- 如果一個類沒有定義拷貝構造函數,編譯器會默認提供拷貝構造函數
class Student{
public:
Student(const char *pName = "NA", int ssId = 0);
~Student();
Student(const Student &s); //拷貝構造函數
};
void fn(Student fs){
//...
}
int main(){
Student ms;
Student s2 = ms; //用一個對象構造另外一個對象
fn(ms); 拷貝一個臨時對象
}
編譯器提供的默認拷貝構造函數的行爲
- 執行逐個成員初始化(memberwise initialize),將新對象初始化爲原對象的副本
- 逐個成員,是指編譯器將現有的對象的每個非static成員,依次複製到正在創建的對象
淺拷貝
深拷貝
何時需要定義拷貝構造函數
- 類數據成員有指針
- 類數據成員管理資源(如打開一個文件)
如果一個類需要析構函數來釋放資源,則它也需要一個拷貝構造函數
- 如果想禁止一個類的拷貝構造,需要將拷貝構造函數聲明爲private
19.1.5 友元函數(friend void)、友元類(friend class)
友元函數
http://www.runoob.com/cplusplus/cpp-friend-functions.html在某些情況下,允許特定的非成員函數訪問一個類的私有成員,同時仍然組織一般的訪問
友元機制允許一個類將其對非公有成員的訪問權授予指定的函數或類
友元的聲明以關鍵字friend開始
只能出現在類定義的內部
可以出現在類中的任何地方,不是授予友元關係的那個類成員,所以不受其聲明出現部分的訪問控制影響友元關係是授予的
爲了讓類B成爲類A的友元,類A必須顯示聲明類B是他的友元
友元關係是不對稱的
如果類A是類B的友元,類B是類C的友元,不能推出類B是類A的友元
友元會破壞封裝
示例
class X{
public:
void initialize();
friend void g(X, *.int); //Global friend
friend void Y::f(x *); // class member friend
friend class Z; //Entire class is a friend
friend void h();
private:
int i;
};
19.1.6 內聯函數 inline
參考
http://www.runoob.com/cplusplus/cpp-inline-functions.htmlC++關鍵字 inline
http://www.cnblogs.com/carsonzhu/p/4649437.html
19.1.7 類的靜態成員
19.2 繼承
http://www.runoob.com/cplusplus/cpp-inheritance.html
19.3 重載運算符和重載函數
重載函數:即函數的參數個數不同或者類型不同
- 運算符重載
- 類是用戶自定義的數據類型,使用運算符重載可以實現如下邏輯
- 對象3 = 對象2 + 對象1,如描述複數的類,描述字符串的類
- 提高程序的可讀性
- 對象3 = 對象2 + 對象1,如描述複數的類,描述字符串的類
- 如果一個類沒有提供賦值運算符函數,則默認提供一個
- 如果一個類提供了拷貝構造函數,那麼也要提供一個重載的賦值運算函數
- 重載運算符要保持原運算符的意義
- 只能對已有的運算符重載,不能增加新的運算符
- 重載的運算符不會改變原先的優先級和結合性
- 類是用戶自定義的數據類型,使用運算符重載可以實現如下邏輯
Person & Person::operate=(const Person & other){
//檢查自賦值
if(this == & other){
return *this;
}
//釋放原有的內存資源
delete[] m_data;
int length = strlen(other.m_data);
m_data = new char[length+1];
strcpy(m_data.other.m_data);
//返回本對象的引用
return *this;
}
- 運算符的重載形式
- 成員函數
- 友元函數
19.4 多態
多態性是指“多種行爲”
- 同樣的方法調用而執行不同操作、運行不同代碼
多態通過分離做什麼和怎麼做,從另一個角度將接口和實現進行分離
“封裝”通過合併特徵和行爲來創建新的數據類型
“實現隱藏”通過將細節“私有化”把接口和實現進行分離多態則消除了類型之間的耦合關係
- LSP(liskov替換原則):子類型必須能夠替換掉它們的基類型
- 多態的概念基於對象引用的動態綁定特性
多態的實現過程
- 子類重寫父類的方法
- 代碼中向父類型變量發出消息(靜態綁定)
- 運行時,根據變量實際引用的對象類型覺得調用哪個方法(動態綁定)
靜態綁定在編譯期進行
- 動態綁定在運行期進行
動態綁定是多態現象的根源
虛函數與抽象類
class Animal{
virtual ~Animal();
virtual void makeSound();
};
- 純虛函數與接口類
// 接口類不能實例化,不能生成對象實例
class Animal{
virtual ~Animal() = 0;
virtual void makeSound() = 0;
};
- 必須爲多態基類聲明virtual析構函數
- 針對接口編程,而不是針對實現編程
19.5 數據抽象
19.6 數據封裝
參考
http://www.runoob.com/cplusplus/cpp-data-encapsulation.html類背後隱藏的思想是數據抽象和封裝
信息隱藏,信息隱藏對象的實現細節,不讓外部直接訪問到
- 將數據成員和成員函數一起包裝到一個單元中,單元以類的形式實現
將數據成員和成員函數包裝進類中,加上具體實現的隱藏共同被稱作封裝,其結果是一個同時帶有特徵和行爲的數據類型
信息隱藏是oop最重要的功能之一,也是使用訪問修飾符(public,protected,private)的原因。
信息隱藏的原因包括:
- 對模塊的任何實現細節所作的更改不會影響使用該模塊的代碼
- 防止用戶意外修改數據
- 使模塊易於使用和維護
除非必須公開底層實現細節,否則應該將所有字段指定爲private加以封裝
19.7 接口(抽象類)
20 整型轉換爲字符串
- 高效率代碼1
char* int2str(unsigned int values)
{
int len = 0;
const char digits[11] = "0123456789";
unsigned int tvalue = values;
while (tvalue >= 100)
{
tvalue /= 100;
len += 2;
}
if (tvalue > 10)
len += 2;
else if (tvalue > 0)
len++;
char* crtn = new char[len + 1];
crtn += len;
*crtn = '\0';
do
{
*--crtn = digits[values % 10];
} while (values /= 10);
return crtn;
}
http://www.jb51.net/article/109828.htm
- 高效率代碼2
string intstr(double x){
int k = int(std::round(x));
string dst4;
if (k > 0 || k == 0){
do{
int b = k % 10;
k = k / 10;
char ch = '0' + b;
dst4 = ch + dst4;
} while (k > 0);
}
else{
k = -k;
do{
int b = k % 10;
k = k / 10;
char ch = '0' + b;
dst4 = ch + dst4;
} while (k > 0);
dst4 = "-" + dst4;
}
return dst4;
}
21 運算符
&
按位與
如果兩個相應的二進制位都爲1,則該位的結果值爲1,否則爲0
|
按位或
兩個相應的二進制位中只要有一個爲1,該位的結果值爲1
^
按位異或
若參加運算的兩個二進制位值相同則爲0,否則爲1
~
取反
~是一元運算符,用來對一個二進制數按位取反,即將0變1,將1變0
<<
左移
用來將一個數的各二進制位全部左移N位,右補0
>>
右移
將一個數的各二進制位右移N位,移到右端的低位被捨棄,對於無符號數,高位補0
22 整數轉換爲二進制
二進制位從右端第2位開始,都爲1時分別表示:
一個整數由這些2的冪次方相加獲得。如
整數轉換爲二進制的代碼
#include <iostream>
#include<bitset>
using namespace std;
int main()
{
int a=42486;
bitset<32> bs(a);
cout<<bs<<endl;
system("pause");
return 0;
}
23 標準庫類型string
#include <string>
//字符串的初始化
string s1; //默認構造函數,s1爲空字符串
string s2(s1); //將s2初始化爲s1的一個副本
string s3("value"); //將s3初始化爲字符串的副本
string s4(n, 'c'); //將字符串初始化爲字符c的n個副本
//字符串的操作
s.empty() //如果字符串爲空,則返回true,否則返回false
s.size() //返回字符串中字符的個數
s[n] //返回字符串中的第n個字符,下表從0開始
s1+s2 //將s1和s2連接成一個新的字符串,返回新生成的字符串
s1=s2 //將s1的內容替換爲s2的內容
v1==v2 //比較v1和v2的內容,相等則返回true,否則返回false
!=, <, <=, >, >= //保持這些操作符慣有的含義
- string類型支持可變長度的字符串
24 動態內存分配
- 運算符new、delete
- 在堆上生成對象,需要自動調用構造函數
- 在堆上生成的對象,在釋放時需要自動調用析構函數
- new / delete, malloc / free 需要配對使用
- new [] / delete[] 生成和釋放對象數組
- new / delete 是運算符, malloc / free 是函數調用
#include <isotream>
using namespace std;
class Test{
public:
Test(){ cout << "Test" << endl;}
~Test(){ cout << "~Test" << endl; }
private:
int m_val;
};
int main(){
Test a;
cout << "end of }" << endl;
Test* pVal = new Test();
delete pVal;
pVal = NULL;
}
25 const關鍵字
const指定一個不該被改動的對象
const int BUFFER_SIZE = 512;
等價於#difine BUFFER_SIZE 512
const限定指針類型
const出現在星號左邊,表示被指物是常量
const出現在星號右邊,表示指針自身是常量const數據成員必須使用成員初始化列表進行初始化
const成員函數
類接口清晰,確定哪些函數可以修改數據成員
使用const提供函數的健壯性
以pass-by-reference-to-const替換pass-by-value
控制使用指針和引用傳遞的實參被意外修改
26 valgrind內存檢測工具
27 生成隨機數或打亂排序
#include <iostream>
#include <time.h>
std::vector<int> getRandom(int total)
{
srand((int)time(NULL));
std::vector<int> input = *new std::vector<int>();
for (int i = 0; i < total; i++) {
input.push_back(i);
}
std::vector<int> output = *new std::vector<int>();
int end = total;
for (int i = 0; i < total; i++) {
std::vector<int>::iterator iter = input.begin();
int num = std::rand() % end;
iter = iter + num;
output.push_back(*iter);
input.erase(iter);
end--;
}
return output;
}
//參考:http://www.52study.org/bencandy-49-807-1.html
28 讀寫txt文件
#include <fstream>
#include <cassert>
#include <iostream>
#include <string>
//讀取txt文件,同時將字符串轉換爲整數
void readTxt(std::string file)
{
std::ifstream infile;
infile.open(file); //將文件流對象與文件連接起來
assert(infile.is_open()); //若失敗,則輸出錯誤消息,並終止程序運行
std::string s,sx, sy;
while (getline(infile, s))
{
std::cout << s << std::endl;
int k = s.find(",");
sx = s.substr(0, k);
std::cout << "sx = " << sx << std::endl;
sy = s.substr(k + 1, s.length());
std::cout << "sy = " << sy << std::endl;
int x, y;
std::istringstream stream1;
stream1.str(sx);
stream1 >> x;
std::istringstream stream2;
stream2.str(sy);
stream2 >> y;
std::cout << "x = " << int(x) << ", y = " << int(y) << std::endl;
}
infile.close(); //關閉文件輸入流
}
延伸閱讀
- 機器學習、深度學習、計算機視覺、自然語言處理及應用案例——乾貨分享(持續更新……)
http://blog.csdn.net/lql0716/article/details/70479493