C++ primer 學習筆記1-7

學校只教過C和JAVA,C++是自己看的,始終還是喜歡C的風格。
對C++的很多特性始終都是一知半解,也許可以學習一些細節。

第一章 快速入門
cin(see-in)標準輸入
cout(see-out)標準輸出
cerr(see-err)標準錯誤
clog
後面3個在實現上的具體區別:
cout,cerr和clog的輸出都可以重定向,比如文件,通過1> 和2>的不同來區別。
cout和clog的輸出是有緩衝區的,緩衝區滿或者遇到endl,cerr直接輸出。
比如在代碼裏cout和cerr、clog,然後執行文件>1.txt,那麼cout的內容到達1.txt,cerr、clog的內容到屏幕。
如果使用2>,即錯誤輸出,那麼結果相反。
#include <iostream>
using namespace std;
int main()
{
cout<<"cout"<<endl;
cerr<<"cerr"<<endl;
clog<<"clog"<<endl;
return 0;
}

運行g++ test.cpp
./a.out   那麼全部輸出屏幕
./a.out > 1.txt 那麼屏幕輸出cerr和clog,文本是cout
./a.out 2>1.txt   哪麼屏幕輸出cout,文本是cerr和clog


cin也是有返回值的
可以使用
int value;
while(cin>>value)……;
來輸入數值,如果無效或者是EOF,則返回假。

(就這幾行字,重打了好幾次,QQ導致死機2次,遨遊神祕退出一次)

第二章 變量和基本類型
初始化分:複製初始化和直接初始化。
int ival=1000;
int ival(1000);

string all_nines(10,'9');//all_nines="9999999999"

流比printf好一點,就是string輸出不用加討厭的.c_str()了。無論是cin還是cout。

const int connum=0;定義一個常量,必須初始化,以前習慣了使用宏定義的,const只是在方法的傳遞參數時纔會使用的,不過始終感覺不到在定義常數時,const比宏定義好哪裏

定義在文件中的變量,非const變量默認爲extern,如果加上const,那麼這個常量就不能在這個文件以外的地方使用的了。除非extern const int connum = 0;

枚舉是四個字節長度,每個成員都是int類型,可以初始化負數。

無論是c還是c++,struct都是默認實現=號賦值的。

第三章 標準庫類型
cin忽略開頭的空白字符(空格換行製表符)。讀取時遇到空白字符,讀取終止。
要讀取一行用getline,不過忽略最後一個回車。
string line;
while(getline(cin,line))
cout<<line<<endl;
cout<<"ctrl + d"<<endl;
ctrl + d結束輸入。

string的方法size()返回類型是string::size_type,無符號整型。
string的變量可以直接用數組的形式來操作,包括替換。比如string str1="123"; str1[1]=a;//str1="1a3"

P89頁表3-3記錄了對字母判斷和操作的函數。或者看這裏:
http://net.pku.edu.cn/~yhf/linux_c/function/01.html#linuxc1

裝換大小寫
for(size_type i=0;i!=s.size();++i)s[i]=tolower(s[i]);
其實也可以這樣寫:
transform(s.begin(),s.end(),s.begin(),tolower);
據說用stl最大的好處是可以拋棄for循環。

vector<int> ivec(10,-1)//10個成員,每個都是-1。不加第二個參數,默認給0
vector<string> svec(10,"hi")//10個成員,每個初始化賦值hi

迭代器iterator其實就是指針,但是注意,迭代器的++或者是--,不能對傳入參數裏面的迭代器操作,否則就會出錯。

同時還提供了一個const_iterator,作用只可取值不能賦值。
這裏需要區別 const iterator,這個可以賦值但是不能++或者-- 。

vector<int>::const_iterator it = vector1.begin();
*it=5;//錯誤,不能賦值

const vector<int>::iterator it = vector1.begin();
*it =5;//正確
it++;//錯誤,不能++

迭代器可以使用+n,或者-n操作。比如:
vector<int>::iterator mid = vi.begin() + vi.size()/2;


標準庫bitset類型
這個我還一直沒有用過。

和vector的區別在於尖括號裏的長度而不是類型。
單位是位。bitset<32>bitvec(0xffff) 就是65536 。0到15位是1,16到31位是0 。
也可以用字符串來初始化:
string str("11100111"); bitset<32>bitves(str,5,3) //從第5位取3個值,那麼就是0x111 。
cout<<bitves.to_ulong()<<endl; //輸出7
cout<<bitves<<endl;//輸出00000000000000000000000000000111

P90是bitset的方法。

第四章 數組和指針
無論是數組還是變量,在函數外定義的都是自動初始化0 ,在函數內定義的都是隨機值。
如果成員是類,無論哪裏定義,自動調用默認構造函數。

char a1[]={'c','+','+'};//打印a1,打印出了後面的亂碼,一直到有0出現。

const int *a1;//*a1不可修改。a1可修改。
int *const a1;//如果指向的不是常量,那麼*a1可修改。a1不可以修改。
const int *const a1;//*a1和a1都不可以修改。

這裏有個很多人都會犯的錯誤。
typedef string *pstr;
const pstr cstr;
那麼cstr是什麼類型?
const string* cstr;//錯誤!
string *const cstr;//正確。

注意呀。

動態數組的初始化只能使用默認值0,比如:
int *pai = new int[10]();//所有值爲0,小括號裏不能給值,否則編譯不過。

創建0個元素的數組不合法。但是創建0個元素的動態數組合法。
int a[0];//error
int *a = new int[0];//ok

第五章 表達式
&&優先級高於||

++i與i++區別:
前面的代碼風格里已經說過了,後置的++會多複製一份對象出來,增加開銷。不過對基礎類型沒有什麼區別,因爲編譯器會做優化,但是對複雜類型就要有額外開銷了。

如果程序耗盡的內存,new可能失敗,系統拋出bad_alloc的異常,而不是返回NULL!
不過其實耗盡內存依然可以new成功,直到地址空間全部用完。

delete爲0的指針是合法的操作,不會報錯。

強制裝換:
static_cast,dynamic_cast,const_cast,reinterpret_cast
實在實在是不喜歡用,直接用C的強制轉換多方便,而且也看不出什麼好處來
C的強制轉換相當於reinterpret_cast。

第六章 語句
int i=0;
a[i]=b[i++];
結果是a[0]=b[0];i++;


拋出異常,是從內往外找處理語句。

都不處理則交給terminate標準庫函數,一般處理是退出程序。

P189 表6-1 定義各種異常。
<exception>包括最常見的異常類。
<stdexcept>定義了幾種常見異常,比如rumtime_error 使用的時候直接扔,如throw runtime_error("XXX");
<new>new失敗的時候拋出bad_alloc異常,而不是返回NULL。
<type_info>定義了bad_cast

try{
……
throw runtime_error("XXX");
}
catch(runtime_error err)
{
cout<<err.what()<<endl;
}
輸出XXX。
如果沒有catch這個異常,顯示異常類爲什麼,然後自動打印what內容,最後退出程序。
如果覺得每個異常都要寫,就寫一個也行,但是XXX就沒有了。比如:
catch(exception err)
{
cout<<err.what()<<endl;
}
無論扔出什麼異常,打印的結果都是St9exception
不知道有什麼辦法可以知道拋出的是什麼異常呢?
或者:
catch(...)
{
}
什麼都不處理。

原來while還可以使用多個條件,如while(i<5 , j<6){}

編譯處理器裏面生成的宏,在代碼裏可以使用。以前我一直以爲是vc的東西,原因是標準c的東西。
__FILE__ 文件名
__LINE__ 該行的行號
__TIME__ 編譯時間
__DATE__ 編譯日期

第七章 函數

內聯函數類似宏定義,在編譯的時候自動替換成函數的內容,避免了寫成函數的額外執行開銷。

內聯函數的定義需要寫在頭文件裏。
還是喜歡宏定義。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章