C++ primer (第五版) 雜記

C++ string

#include <string>
using std::string;

string包含在頭文件iostream.h中:

#include <iostream>
using std::string;

int main()
{
    string s1 = "hello";
    string s2 = "world";
    
    std::cout<<s1+s2<<std::endl;
    
    return 0;
}

string的初始化:ios

string s1;             //默認初始化
string s2(s1);
string s2 = s1;
string s3("value");
string s3 = "value";
string s4(n, 'c');    //用n個'c'來初始化字符串

初始化分爲兩種:1.複製初始化(copy initialization) 2.直接初始化(direct initialization)c++

string 操做

os << s            //如cout<<s
is >> s            //如cin>>s
getline(is, s)     //如getline(cin, s)
s.empty()
s.size()           //返回類型是string::size_type,具體是unsigned,足夠大
s[n]
s1+s2              //字符串鏈接
s1,s2比較          //如s1==s2,s1!=s2,s1<s2

int main()
{
    string s;
    cin >> s;
    cout<< s <<endl;
    /*忽略前面的whitespace(如空格、換行、tabs),直到再次遇到whitespace爲止
        如:鍵入[  hello  world   ],輸出[hello]
    */
    
    string line;
    getline(cin, line);
    cout << line <<endl;
    /*不忽略whitespace,獲得一整行,可是不包括換行符。
        如:鍵入[  hello  world   ],輸出[  hello  world   ]
    */
    return 0;
}

int main()
{
    string word;
    while(cin>>word)
    {
        cout<<word<<endl;
    }
    /*打印文件中所有的單詞,直到end-of-file結束(EOF)。在C語言中while(scanf("%s", word)!=EOF)
        測試經常使用重定向符:./a.out < data.txt
    */
    
    string line;
    while(getline(cin, line))
    {
        cout<<line<<endl;
    }
        /*打印文件中所有的行,直到end-of-file結束(EOF)。在C語言中while(scanf("%s", word)!=EOF)
        測試經常使用重定向符:./a.out < data.txt
    */
    return 0;
}

在C++11中,能夠用auto關鍵字來推斷size()的返回值:編程

auto len = line.size();    //len is type string::size_type

字符串鏈接

string s1 = "hello", s2 = "world";
string s3 = s1 + ", " + s2;    //ok
string s4 = s1 + ", ";         //ok:adding a string and a literal
string s5 = "hello"+", ";      //error:no string operand

處理字符串中的每個字符

C++11中最好的方式是range for表述。數組

string str("some string");
for(auto c : str)        //實際上是char,用char也能夠
    cout<<c<<endl;

#include<iostream>
using namespace std;

int main()
{
    //將s轉換成大寫字符串
    string s = "hello, world";
    for(auto &c : s)      //引用
        c = toupper(c);
    cout<<s<<endl;        //output: HELLO,WORLD
    return 0;
}

C++ vector

#include<vector>
using std::vector;


C++異常處理

throw表達式

#include<iostream>
#include<stdexcept>

using namespace std;

int main()
{
    int a,b;
    cin>>a>>b;
    if(a!=b)
        throw runtime_error("not same");
    else
        .....
}

拋出異常將終止當前的函數,並把控制權轉移給能處理該異常的代碼。app

類型runtime_error是標準庫異常類型的一種,定義在stdexcept頭文件中。函數

函數

函數的參數傳遞在C++中只有兩種:值傳遞和引用傳遞。傳遞指針其實也是值傳遞(拷貝進函數內的是指針的副本)。引用傳遞是對象自己,使用引用能夠避免拷貝。特別是一些複雜的類型。測試

bool isShorter(const string &s1, const string &s2)
{
    return s1.size()<s2.size();
}

另外,使用引用形參還能夠返回額外信息。這是常見的編程技巧,由於一個函數只能返回一個值,然而有時函數須要同時返回多個值,引用形參爲咱們一次返回多個結果提供了有效的途徑。spa

數組做爲形參時:

使用標準庫規範指針

void print(const int *beg, const int *end)
{
    while(beg!=end)
        cout<< *beg++ <<endl;
}
int j[2]={0,1};
print(begin(j), end(j));

顯式傳遞一個表示數組大小的形參調試

這個方法很經常使用。

void print(const int[], size_t size);

數組引用形參

這塊用的很少,可是也要理解。C++容許將變量定義成數組的引用。

/*
**這裏[10]個數必須去肯定的,不然出錯
**注意:只有引用才能夠用這種for語句,不然出錯。如在void print(const int arr[], size_t n)中使用for(auto elem : arr)將會報錯,由於不知道數組具體的大小。
*/
void print(int (&arr)[10])
{
    for(auto elem : arr)
        cout<<elem<<endl;
}

無返回值函數能夠有沒有返回值的return語句。

不要返回局部對象的引用或指針

const string &manip()
{
    string ret;
    if(!ret.empty())
        return ret;
    else
        return "Empty";
}

上面的兩條return語句都將返回未定義的值,也就是說,試圖使用manip函數的返回值將引起未定義的行爲。對於第一條return語句來講,顯然返回的是局部對象的引用。在第二條return語句中,字符串字面值轉換成一個局部臨時string對象,對於manip來講,該對象和ret同樣都是局部的。

引用返回左值

函數的返回類型決定函數調用是不是左值。調用一個返回引用的函數獲得左值,其餘返回類型獲得右值。能夠像使用其餘左值那樣來使用返回引用的函數的調用,特別是,咱們能爲返回類型是很是量引用的函數的結果賦值:

char &get_val(string &str, string::size_type ix)
{
    return str[ix];
}
int main()
{
    string s("a value");
    cout<< s << endl;
    get_val(s, 0) = 'A';
    cout<< s << endl;
    
    return 0;
}

把函數調用放在賦值語句的左側可能看起來有點奇怪,但其實這沒什麼特別的。

列表初始化返回值

vector<string> process()
{
    //expected和actual是string對象
    if(expected.empty())
        return {};
    else if(expected==actual)
        return {"functionX", "okay"};
    else
        return {"functionX", expected, actual};
}

調試幫助

assert是一種預處理宏。所謂預處理宏實際上是一個預處理變量,它的行爲有點相似於內聯函數。assert宏使用一個表達式做爲它的條件:assert(expr);

首先對expr求值,若是表達式爲假,assert輸出信息並終止程序的執行。若是表達式爲真,assert什麼也不作。

assert宏定義在cassert頭文件中。

順序容器

vector         可變大小數組
deque          雙端隊列
list           雙向鏈表
forward_list   單向鏈表
array          固定大小數組
string         與vector類似的容器,但專門用於保存字符。隨機訪問快。

forward_list和array是新C++11標準增長的類型。通常來講,每一個容器都定義在一個頭文件中,文件名與類型名相同。即,deque定義在頭文件deque中,list定義在頭文件list中,依次類推。容器均定義爲模板類。例如對vector,咱們必須提供額外信息來生成特定的容器類型。如:

list<Sales_data>
deque<double>

標準庫array具備固定大小

與內置數組同樣,標準庫array的大小也有類型的一部分。當定義一個array時,除了指定元素的類型,還要指定容器大小。如:

array<int, 42>    //類型爲:保存42個int的數組
array<string, 10>    //類型爲:保存10個string的數組

爲了使用array類型,咱們必須同時指定元素類型和大小:

array<int, 10>::size_type i;    //ok
array<int>::size_type j;        //error

C++ swap函數

c++內置了swap函數,能夠交換相同類型的對象。如:

#include<iostream>
#include<vector>
using namespace std;

int main()
{
    int m=5,n=6;
    swap(m,n);    //交換兩個整數
    cout<<m<<n<<endl;
    
    vector<int> v1, v2;
    v1.push_back(1);
    v1.push_back(2); 
    v2.push_back(3);
    v2.push_back(4);
    swap(v1, v2);    //交換兩個vector
    
    return 0;
}


因爲string是一個字符容器,咱們也能夠用push_back在string末尾添加字符(這個之前真不知道):

void pluralize(size_t cnt, string &word)
{
    if(cnt>1)
        word.push_back('s');
}

string類型支持順序容器的賦值運算符以及assign、insert和erase操做。

s.insert(s.size(), 5, '!');    //在s末尾插入5個感嘆號
s.erase(s.size()-5, 5);        //從s刪除最後5個字符

const char *cp = "Stately, plump Buck";
s.assign(cp, 7);        //s=="Stately"
s.insert(s.size(), cp+7);    //s=="Stately, plump Buck"
string s1 = s.substr(0,7);    //s1=="Stately"
s.append(".");
s.replace(5,3,"5th");
相關文章
相關標籤/搜索