C++被稱爲「完美的程序設計語言」,在chromium內核中應用很是普遍,以前沒有系統學習過C++相關的知識,經過看書來學習相關的知識,如今將《C++ Primer》基本知識提取出來,供你們學習。ios
1.輸入輸出
2.變量與基本類型編程2.1 引用與指針數組
2.1.1 獲取對象地址
2.1.2 指針值
2.1.3 利用指針訪問對象
2.1.4 空指針
2.1.5 void* 指針數據結構2.2 const符號函數
2.2.1 constexpr性能
2.3 處理類型學習
2.3.1 類型別名
2.3.2 auto類型說明
2.3.3 decltype類型指示符spa2.4 結構體設計
3.字符串、向量、數組指針
3.1 string標準庫
3.1.1 初始化string對象
3.1.2 string執行操做
3.1.3 string中字符處理操做3.2 vector標準庫
3.2.1 向vector添加元素
3.2.2 其餘vector操做3.3 迭代器
3.3.1 迭代器運算
3.4 數組
3.4.1 指針和數組
標準輸入輸出是一個語言的重要功能。
cin是C++中的標準輸入流對象,主要用於從標準輸入讀取數據,這裏的標準輸入,是指鍵盤。
cout是輸入流對象,即ostream類的對象。
在理解cin功能時,不得不提標準輸入緩衝區。當咱們從鍵盤輸入字符串的時候須要敲一下回車鍵纔可以將這個字符串送入到緩衝區中,那麼敲入的這個回車鍵(\r)會被轉換爲一個換行符\n,這個換行符\n也會被存儲在cin的緩衝區中而且被當成一個字符來計算!好比咱們在鍵盤上敲下了123456這個字符串,而後敲一下回車鍵(\r)將這個字符串送入了緩衝區中,那麼此時緩衝區中的字節個數是7 ,而不是6。
下面看下簡單的例子:
#include <iostream> using namespace std; int main() { cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!! double val; cin >> val; cout << "The val is " << val << endl; return 0; }
輸出以下:
jeffmony@jeffmony-OptiPlex-7050:~/workspace/cppProjects/test$ ./a.out !!!Hello World!!! 12.3 The val is 12.3
C++中有兩種複合類型:引用與指針。
#include <iostream> using namespace std; int main() { int ival = 1024; int &refVal = ival; cout << "refVal is " << refVal <<endl; return 0; }
輸出的結果以下:
jeffmony@jeffmony-OptiPlex-7050:~/workspace/cppProjects/test$ ./a.out refVal is 1024
注意:通常在初始化變量時,初始值會被拷貝到新建的對象中。然而定義引用時,程序把引用和它的初始值綁定在一塊兒,而不是講初始值拷貝給引用。一旦初始化完成,引用將和它的初始值對象一直綁定在一塊兒。由於沒法令引用從新綁定到另一個對象,所以引用必須初始化。
指針是指向另一種類型的複合類型。與引用相似,指針也實現了對其餘對象的間接訪問。與引用不一樣點:
1.指針自己就是一個對象,容許對指針賦值與拷貝,並且在指針的生命週期內能夠指向幾個不一樣的對象;
2.指針無須在定義時賦初始值,塊做用域內定義的指針若是沒有初始化,將擁有一個不肯定的值。
2.1.1 獲取對象地址
指針存放某個對象的地址,要想獲取該地址,須要使用取地址符(& )
2.1.2 指針值
指針的值會取以下的四種狀況:
1.指向一個對象
2.指向緊鄰對象所佔空間的下一個位置
3.空指針,指針沒有指向任何對象
4.無效指針
2.1.3 利用指針訪問對象
2.1.4 空指針
空指針不指向任何對象,在使用一個指針以前要判斷一下當前指針是否爲nullptr
2.1.5 void* 指針
void* 是一種特殊的指針類型,能夠用於存聽任意對象的地址。一個void*指針存放着一個地址,這一點和其餘的指針相似。可是咱們不知道改地址中究竟是個什麼類型的對象,因此操做的時候要十分當心,基本上也不能進行有效操做。
1.const用來定義常量,一旦定義了,就不能改變。
2.const默認狀況下僅在文件內有效,若是想在多個文件之間共享const對象,必須在變量的定義以前添加extern關鍵字。
#include <iostream> using namespace std; int main() { int i = 42; const int &r1 = i; cout << "result is " << r1 << endl; i++; cout << "result is " << r1 << endl; return 0; }
r1綁定了對象i,可是不容許經過r1修改對象i的值,可是對象i值改變的時候會反映到r1上,這點要記住哦。
2.2.1 constexpr
constexpr是常量表達式,是指值不會改變而且在編譯過程就能獲得計算結果的表達式。
constexpr int mf = 30; constexpr int limit = mf + 1;
2.3.1 類型別名
傳統的使用typdef,例如:
typedef double wages;
新標準使用using來「別名聲明」定義別名:
using SI = Sales_item;
2.3.2 auto類型說明
編程時經常須要把表達式的值賦給變量,這就要求在聲明變量的時候清楚地知道表達式的類型,可是有的時候作不到這一點。
C++11引入了auto類型說明符,用它就能讓編譯器替咱們去分析表達式所屬的類型。
auto item = val1 +val2; // item初始化爲val1 val2相加的結果
2.3.3 decltype類型指示符
有時但願用表達式的類型推斷出要定義的變量的類型,可是不想用該表達式的值初始化變量。
Sales_data.h struct Sales_data { std::string bookNo; unsigned unints_sold = 0; double revenue = 0.0; };
#include <iostream> #include "Sales_data.h" using namespace std; int main() { Sales_data data1,data2; double price = 0.0; cin >> data1.bookNo >> data1.unints_sold >> price; data1.revenue = price * data1.unints_sold; cin >> data2.bookNo >> data2.unints_sold >> price; data2.revenue = price * data2.unints_sold; cout << data1.bookNo << ", " << data2.bookNo <<endl; return 0; }
輸出的結果以下:
jeffmony@jeffmony-OptiPlex-7050:~/workspace/cppProjects/test$ ./a.out 0-201-78345-X 3 20.00 0-201-78435-P 2 15.00 0-201-78345-X, 0-201-78435-P
標準庫string表示可變長的字符序列,使用string必須包括string頭文件:
#include <string>
using std::string;
3.1.1 初始化string對象
string s1;
string s2 = s1;
string s3 = "hello";
string s4(s3); //等同於s4 = s3;
string s5("hello"); //等同於s5 = "hello";
string s6(10, 'c'); //把s6初始化爲10個字符c組成的串
3.1.2 string執行操做
操做語句 | 含義 |
---|---|
os << s | 將s寫到輸出流中,返回os |
is >> s | 從is中讀取字符串賦給s,字符串以空白分隔,返回is |
getline(is, s) | 從is中讀取一行賦給s,返回is |
s.empty() | s爲空返回true,不然返回false |
s.size() | 返回s中字符的個數 |
s[n] | 返回s中第n個字符的引用,位置n從0計算 |
s1 + s2 | 返回s1和s2鏈接後的結果 |
s1 = s2 | 用s2的副本代替s1中原來的字符 |
s1 == s2 | 若是s1包含的字符和s2徹底同樣,則相等;相等判斷對大小寫敏感 |
s1 != s2 | 不等性判斷 |
< , <= , > , >= | 利用字符在字典序中的順序進行比較,對大小寫敏感 |
標準輸入cin若是輸入一個string對象,string對象會自動忽略開頭的空白(空格符、換行符、製表符),並從第一個真正的字符開始讀起,直到碰見下一處空白爲止。
#include <iostream> using namespace std; int main() { string s; cin >> s; cout << s << endl; return 0; }
輸出結果以下:
jeffmony@jeffmony-OptiPlex-7050:~/workspace/cppProjects/test$ ./a.out hello, world; hello,
能夠很明顯的看到cin的主要區別。
使用getline讀取一整行,咱們但願在最終獲得的字符串中保留輸入時的空白符,這時應該用getline函數替代原來的>>運算符,getline直到遇到一行換行符爲止。getline一遇到換行符就結束讀取操做並返回結果。
注意:觸發getline函數返回的那個換行符實際上被丟棄掉了,獲得的string對象並不包括該換行符。
#include <iostream> using namespace std; int main() { string line; while(getline(cin, line)) { cout << line << endl; } return 0; }
輸出結果以下:
jeffmony@jeffmony-OptiPlex-7050:~/workspace/cppProjects/test$ ./a.out hello, world; hello, world; ^C
字符串中+操做不能將兩個字面值相加,否則會產生錯誤。下面的例子就是由於s3中有兩個字符串的字面值相加了,因此致使編譯錯誤。
#include <iostream> using namespace std; int main() { string s1 = "hello"; string s2 = "world"; string s3 = "hello" + "," + "world"; return 0; }
jeffmony@jeffmony-OptiPlex-7050:~/workspace/cppProjects/test$ g++ helloworld.cpp helloworld.cpp: In function ‘int main()’: helloworld.cpp:7:22: error: invalid operands of types ‘const char [6]’ and ‘const char [2]’ to binary ‘operator+’ string s3 = "hello" + "," + "world"; ~~~~~~~~^~~~~
3.1.3 string中字符處理操做
cctype頭文件中有一些操做字符的庫函數,和C語言中ctype.h頭文件的內容是同樣的,cctype頭文件從明明規範上更加符合C++語言的要求。
字符串遍歷操做:
#include <iostream> using namespace std; int main() { string s1 = "hello"; for(auto c : s1) { cout << c << endl; } return 0; }
輸出結果以下:
jeffmony@jeffmony-OptiPlex-7050:~/workspace/cppProjects/test$ ./a.out h e l l o
C++中string能夠默認當成數組,可使用下標,可是下標範圍必須在0和s.size() 之間,在範圍以外會產生未知的影響。
標準庫vector表示對象的集合,其中全部的類型都相同,集合中每一個對象都有一個與之對應的索引,索引用於訪問對象,vector被成爲容器。使用vector須要加上頭文件。
#include <vector>
using std::vector;
vector能容納絕大多數類型的對象做爲其元素,引用不是對象,因此不存在包含引用的vector。
表達式 | 含義 |
---|---|
vector<T> v1 | v1是一個空vector,它潛在的元素是T類型的,執行默認初始化操做 |
vector<T> v2(v1) | v2中包含有v1全部元素的副本 |
vector<T> v2 = v1 | 等價於v2(v1),v2中包含有v1全部元素的副本 |
vector<T> v3(n ,val) | v3包含了n個重複的元素,每一個元素都是val |
vector<T> v4(n) | v4包含了n個重複地執行了值初始化操做的對象 |
vector<T> v5{a,b,c,...} | v5包含了初始值個數的元素,每一個元素被賦予相應的初始值 |
vector<T> v5={a,b,c,...} | 等價於v5{a,b,c,...} |
3.2.1 向vector添加元素
使用push_back函數向vector中添加元素,看看下面的例子:
#include <iostream> #include <vector> using namespace std; int main() { vector<int> vec; for(int i=0;i<100;i++) { vec.push_back(i); } cout << vec.size() << endl; return 0; }
輸出結果以下:
jeffmony@jeffmony-OptiPlex-7050:~/workspace/cppProjects/test$ ./a.out 100
通常狀況下,咱們能夠在初始化vector的時候不初始化vector的大小,由於vector會動態擴張,可是vector的動態擴張比較耗時,若是在知道vector大小的狀況下,建議仍是直接在初始化的時候定義vector大小較好,這樣減小以後的擴張操做。Java中的ArrayList和HashMap也是一樣的思路。
3.2.2 其餘vector操做
表達式 | 含義 |
---|---|
v.empty() | 若是v不含有任何緣故;返回真;不然返回假 |
v.push_back(t) | 向v的尾端添加一個值爲t的元素 |
v[n] | 返回v中第n個位置上的元素的引用 |
v1 = v2 | 替換 |
v1={a,b,c,...} | |
v1 == v2 | v1與v2相等當且僅當它們的元素數量相同且對應位置的元素值都相同 |
v1 != v2 | |
< , <=, >, >= | 字典序進行比較 |
咱們已知使用下標運算符來訪問string對象或者vector對象,還有另外的機制也能夠實現,就是迭代器,除了vector以外,還有幾種標準容器,全部標準容器庫均可以使用迭代器,可是隻有少數幾種支持下標運算符。
string對象不屬於容器類型,可是string支持迭代器,vector支持下標,這點要注意了。
#include <iostream> #include <vector> using namespace std; int main() { vector<int> vec; for(int i=0;i<10;i++) { vec.push_back(i); } for(auto it = vec.begin(); it != vec.end(); it++) { cout << *it << endl; } return 0; }
輸出結果以下:
0 1 2 3 4 5 6 7 8 9
C++語言中習慣使用 != 符號,而不是 < 符號,這和咱們理解的Java或者其餘的語言有點不一樣,記住就好了,由於部分標準容器庫的迭代器都定義了 == 和!=,沒有定義 < 符號,因此建議使用定義好的符號。
迭代器類型:
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類型,C++11新標準還引入兩個新函數,分別是cbegin 和cend,分別表示const_iterator 和const_end
但凡是使用迭代器的循環,都不要向迭代器所屬的容器中添加元素,這會形成迭代器失效,這樣注意一點。
3.3.1 迭代器運算
表達式 | 含義 |
---|---|
iter + n | 相對原來的位置,移動了若干個位置,這兒要注意,因此操做的iter必定要在正常的範圍以內,不然發生問題。 |
iter - n | |
iter += n | |
iter -= n | |
iter1 - iter2 | |
>, >=, <, <= |
數組相似與vector的數據結構。與vector不一樣的是:數組大小肯定不變,不能隨意向數組中增長元素。由於數組大大小固定,因此實時訪問性能較好。
初始化數組:
int arr[10];
string str[10];
int *par[10]; //定義含有10個整型指針的數組
定義字符數組的時候,必定要記住字符數組末尾的地方有一個空字符:'\0'
char a3 = "C++"; \自動添加表示字符串結束的空字符
注意:不容許把一個數組直接賦值給另外一個數組。
3.4.1 指針和數組
C++中指針和數組的關鍵很是密切,使用數組的時候編譯器通常默認將它轉換爲指針。
string nums[] = {"one", "two", "three"};
string *p = &nums[0]; // p指向nums的第一個元素
string *p2 = nums; // *p2 = &nums[0],默認轉化爲指向數組首元素的指針。
- 指針自己也是迭代器,能夠直接迭代。這一點學過C語言的應該都很清楚。
數組中的標準庫函數begin 和end也用到了指針相關的。
int ia[] = {0,1,2,3,4,5,6,7,8,9,10};
int *beg = begin(ia); //指向ia首元素的指針
int *last = end(ia); //指向ia尾元素的下一個元素的指針。
#include <iostream> using namespace std; int main() { int arr[] = {1,2,3,4,5,-7,-9,10}; int *pbeg = begin(arr); int *pend = end(arr); while(pbeg != pend && *pbeg > 0) { pbeg++; } cout << *pbeg << endl; return 0; }
找出數組中第一個爲負數的數:
jeffmony@jeffmony-OptiPlex-7050:~/workspace/cppProjects/test$ ./a.out -7
C語言中導入string.h頭文件,C++中導入cstring
函數 | 含義 |
---|---|
strlen(p) | 返回p的長度,空字符不算在內 |
strcmp(p1, p2) | 比較p1與p2, p1==p2,返回0,p1>p2,返回正數,p1<p2,返回負數 |
strcat(p1, p2) | p2拼接到p1以後,返回p1 |
strcpy(p1, p2) | p2拷貝給p1, 返回p1 |