【C++筆記】字符串、向量和數組

string(C++Primer 5th)

string & vector

  string表示可變長的字符序列,vector存放的是某種給定類型對象的可變長序列。

using聲明

  頭文件不應包含using聲明,否則頭文件的內容會拷貝到所有引用它的文件中去。

string初始化賦值

  使用等號=初始化的是拷貝初始化,不使用等號的稱爲直接初始化。
size()函數的返回值是類型size_type,無符號整數型。如果n是負值的int,則s.size()

string s(10,'c');               // s的內容是cccccccccc

cin>>word;                      // 遇到空格停止
getline(cin,line);              // 讀入一整行,直到換行符

auto len = line.size();         // len的類型是string::size_type

string s1 = s + "," + "world";  // 加法需保證+兩次的運算對象至少有一個是string 
string s2 = "hello" + "," + s1; // 錯誤:兩個運算對象都不是string
使用C++版本的C標準庫頭文件

  一般來說,C++程序應該使用名爲cname的頭文件而不使用name.h的形式。

基於範圍的for語句
// 統計string對象中標點符號的個數
string s("Hello World!!!");     
decltype(s.size())  punct_cnt=0; // 用於統計個數,無符號整型確保下標不小於0 
for(auto c:s)
    if(ispunct(c))  punct_cnt++; 
// 使用範圍for語句改變字符串中的字符
string s("Hello World!!!");
for(auto &c:s)
    c = toupper(c);             // 將string對象轉換成大寫
cout << s << endl;




vector

vector概念

  標準庫類型vector表示對象的集合,其中所有對象的類型都相同,通常也稱容器。

  vector是模板而非類型,由vector生成的類型必須包含vector中元素的類型,如vector<int>、vector<vector<int>>

  由於引用不是對象,所以不存在包含引用的vector。

列表初始化 OR 元素數量
vector<int> v1(10);         // v1有10個元素,每個的值都是0
vector<int> v2{10};         // v2有1個元素,該元素的值是10

vector<int> v3(10,1);       // v3有10個元素,每個的值都是1
vector<int> v4{10,1};       // v4有2個元素,值分別是10和1

vector<string> v5{"hi"};    // v5有一個元素"hi"
vector<string> v6("hi");    // 錯誤,不能用字符串字面值構建vector對象
vector<string> v7{10};      // v7有10個默認初始化的元素
vector<string> v8{10,"hi"}; // v8有10個值爲"hi"的元素
向vector對象中添加元素

  添加元素的方法是先創建一個空vector,然後在運行時利用vector的成員函數push_back向其中添加元素。PS:預先指定vector對象的容量沒有什麼必要,反而可能導致性能變差,不建議。

  如果循環體內部含有向vector對象添加元素的語句,則不能使用範圍for循環!範圍for語句體內不應改變其所遍歷序列的大小。

vector<int> v;              // 空vector對象
for(int i = 0; i != 100; i++)
    v.push_back(i);         // 往vector中添加0到99,不能用下標方式添加元素!

/*《C++Primer 5th》P94.練習3.16*/

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

void main()
{
    vector<int> v1, v2(10), v3(10, 42), v4{ 10 }, v5{ 10,42 };
    vector<string> v6{ 10 }, v7{ 10,"hi" };

    cout << "v1:"     << endl;  for (auto c : v1)       cout << c << "\t";  
    cout << "\n\nv2:" << endl;  for (auto c : v2)       cout << c << "\t";  
    cout << "\n\nv3:" << endl;  for (auto c : v3)       cout << c << "\t";  
    cout << "\n\nv4:" << endl;  for (auto c : v4)       cout << c << "\t";  
    cout << "\n\nv5:" << endl;  for (auto c : v5)       cout << c << "\t";  
    cout << "\n\nv6:" << endl;  for (auto c : v6)       cout << c << "\t";  
    cout << "\n\nv7:" << endl;  for (auto c : v7)       cout << c << "\t";

    getchar();
    return ;
}


迭代器

相比下標運算符

  所有標準庫容器如vector都可以使用迭代器,但是隻有少數幾種才同時支持下標運算符。嚴格來說,string對象不屬於容器類型,但它支持迭代器。

begin、end

  begin成員負責返回指向第一個元素的迭代器,end成員負責返回尾元素的下一位置(該位置並無元素)的迭代器。end返回的迭代器通常稱爲尾後迭代器或尾迭代器。

  如果容器爲空,則begin和end返回的是同一個迭代器即尾後迭代器。

  所有標準庫容器的迭代器都定義了==和!=,但其中大多數並沒有定義<運算符!!!

for(auto it = s.begin(); it != s.end(); ++it)       
    *it = toupper(*it); 

vector<int>::iterator it;           // it能讀寫vector<int>的元素
string::iterator it2;               // it2能讀寫string對象中的字符

vector<int>::const_iterator it3;    // it3只能讀元素,不能寫元素
string::const_iterator it4;         // it4只能讀字符,不能寫字符
const_iterator

  begin和end返回的具體類型由對象是否是常量來決定,如果對象是常量,begin和end返回const_iterator;如果對象不是常量,返回iterator。

cbegin、cend

  C++11新標準引入了cbegin和cend,用法與begin、end相同,不同的是不論vector對象是否常量,返回值都是const_iterator。

解引用與成員訪問

  it->mem和(*it).mem表達的意思相同。

(*it).empty()                       // 解引用it,然後調用empty成員
*it.empty()                         // 錯誤,試圖訪問it的empty成員(並不存在)

for(auto it = text.cbegin(); it != text.cend() && !it->empty(); ++it)
    cout<< *it <<endl;
difference_type

  迭代器的距離是指一個迭代器移動多少位置能追上另一個迭代器,類型位difference_type的帶符號整型數,可正可負。

二分搜索

  迭代器的經典算法時二分搜索。




數組

數組初始化

  定義數組時必須指定數組類型,不允許使用auto關鍵字由初始值的列表推斷類型。和vector一樣,數組元素應爲對象,因此不存在引用的數組。

// 錯誤示範

const char a[6] = "Daniel";         // 錯誤,沒有空間存放空字符

int a[] = {0,1,2};  
int a2 = a;                         // 錯誤,不允許使用一個數組初始化另一個數組
a2 = a;                             // 錯誤,不能把一個數組直接賦值給另一個數組
數組聲明
int *ptrs[10];                      // ptrs是含有10個整型指針的數組
int &refs[10] = /*?/;               // 錯誤,不存在引用的數組
int (*parray)[10] = &arr;           // parray指向一個含有10個整數的數組
int (&arrRef)[10] = arr;            // arrRef引用一個含有10個整數的數組
int *(&array)[10] = ptrs;           // arry是數組的引用,該數組含有10個指針
指針也是迭代器
int arr = {0,1,2,3,4,5,6,7,8,9};
int *e = &arr[10];                  // 指向arr尾元素的下一位置的指針
for(int *b = arr; b != e; ++b)      // arr表示首元素的地址
    cout << *b << endl;

  說明:arr有10個元素,尾元素所在位置的索引是9,下一位置的不存在的元素用於提供地址初始化e。與尾後迭代器雷系,尾後指針不指向具體的元素,不能進行解引用或是遞增操作。

標準庫函數begin和end

  C++11標準引入了begin和end兩個函數,與容器中的成員函數功能相似。但數組不是類類型,所以begin和end不是數組的成員函數,正確的使用形式是將數組作爲它們的參數。

int ia[] = {0,1,2,3,4,5,6,7,8,9};
int *beg = begin(ia);               // 指向ia首元素的指針
int *last = end(ia);                // 指向arr尾元素的下一位置的指針
指針運算
constexpr = size_t sz =5;
int arr[sz] = {1,2,3,4,5};
int *ip = arr;
int *ip1 = ip + 4;                  // ip1指向arr的尾元素arr[4]

auto n = end(arr)-begin(arr);       // n爲5,類型爲ptrdiff_t帶符號類型

  如果兩個指針分別指向不相關的對象,則不能比較它們。

  如果p是空指針,允許給p加上或減去一個值爲0的整型常量表達式。兩個空指針也允許彼此相減,結果爲0。


C風格字符串

cstring

  定義在cstring頭文件中,cstring是C語言頭文件string.h的C++版本。

  對大多數應用來說,使用標準庫string要比使用C風格字符串更安全、更高效。

string s("hello world");            // string初始化
char *str = s;                      // 錯誤,不能用string對象初始化char*
const char *str = s.c_str();        
// 正確,返回C風格的字符串,不改變字符數組內容,改變s的值會使返回的數組失效
使用數組初始化vector對象
int int_arr[] = {0,1,2,3,4,5};
vector<int> ivec(begin(int_arr),end(int_arr));
遍歷多維數組

  要使用範圍for語句處理多維數組,除了最內層的循環外,其他所有循環的控制變量都應該是引用類型。

size_t cnt =0;
for(auto &row : ia)                 // for(auto row : ia )錯誤,自動轉換成ia首元素的指針
    for(auto &col : row)            // for(auto col : row)也正確
    {
        col = cnt;
        ++cnt;
    }

for(auto p = begin(ia); p != end(ia); ++p)
    for(auto q = begin(*p); q != end(*p); ++q)
        cout << *q << ' ';


發佈了99 篇原創文章 · 獲贊 210 · 訪問量 40萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章