一、基礎
1. 循環讀入數據
讀取數量不定的輸入數據
void test01() {
int value = 0;
while (cin >> value)
{
// 當遇到文件結束符或遇到一個無效輸入(比如讀到的值不是一個整數),istream對象狀態變爲無效,條件爲假
cout << value << endl;
}
}
2. 重定向
使用文件重定向連接標註你輸入和標準輸出
command < filename1 > filename2
Project4.exe < infile.txt > outfile.txt
- 用double 而不是float
- 無符號數的減法結果必須要確保爲正,尤其小心死循環
- \123 八進制字符 \x1234 十六進制字符
- 列表初始化: int value{0}; 優點:用列表初始化如果初始值存在丟失信息的風險,編譯器會報錯
3. extern:聲明
extern作用: 聲明一個變量而非定義,用於分文件編譯。
變量的定義只能出現在一個文件中,聲明可以出現在多個文件中
extern int j; //聲明i而非定義
int j; // 聲明並定義j
extern int j = 10; //定義
4. constexpr:常量
常量表達式:值不改變並且在編譯的時候就可以得到結果
constexpr作用:將變量聲明爲該類型以便有編譯器來驗證變量是否爲常量表達式。聲明爲constexpr的變量一定是個常量,而且必須用常量表達式初始化,否則會報錯
const int a =10; //Yes ,是常量表達式
const int a = getsize();//No,不是常量表達式
constexpr int a = 10; //a爲常量
constexpr int a = getsize();//只有當getsize是個constexpr函數(在編譯時就可以得到結果)時,纔不報錯
//如果constexpr聲明中如果定義了指針,限定符只對指針有效
const int *p = nullptr;
constexpr int *q = nullptr; //
5. typedef :類型別名
typedef double wages; //wages是double的同義詞
wages hourly, weekly;
typedef wages base, *p; // base是double的同義詞,p是double*的同義詞
using SI = Sales_item; // SI是Sales_item的同義詞----新方法:別名聲明
SI item;
6. auto : 類型說明符
auto : 編譯器通過初始值分析表達式所屬的類型
auto item = val1 + val2; // 自動根據val1和val2推斷item類型
auto i=0, *p = &i; // 正確,i和*p是同一個類型
auto sz=0, pi = 3.14; //錯誤,auto在一條語句中聲明多個變量時,要求類型一致
7. decltype : 類型說明符
decltype : 編譯器分析表達式並得到其類型,但不實際計算表達式的值
decltype(f()) sum = x; //sum的類型由f返回類型決定,但不調用函數
decltype(s.size()) index = 0;
8. 指針的引用
int i = 42;
//int *&r = &i; 報錯,不能定義指向引用的指針
int *p;
int *&r = p;
p = &i;
cout << *r; //令i=0
9. 多文件常量共享
const聲明和定義中都加入extern
// 文件1
extern const int bufsize = 10;
// 文件2
extern const int bufsize;
10. 常量引用
int i = 42;
const int &r1 = i; //Yes,但是不可以通過r1修改i的值
const int &r2 = 42; //Yes 常量引用可綁定非常量對象、字面值和表達式
11. 常量指針和指針常量
//指針常量,值是常量
const double p = 3.14;
double *p1 = &p; //No
const double *p2 = &p; //Yes,但不能通過p2改p
//常量指針,地址是常量
int a = 0;
int const *p3 = &a;
12. for (declaration: expression) statement
for(declaration : expression) statement
for(元素:序列) 操作 //遍歷每個元素,並對序列中的每個值執行操作
string c{"hello"};
for(auto &i:c){cout << i;}
13. 迭代器類型
vector<int>::iterator it1; // it1可讀寫vector元素
vector<int>::consti_iterator it2;// it2只能讀vector元素
auto it3 = v.cbegin(); //it3類型爲vector<int>::consti_iterator,只讀操作最好用常量類型
for(auto it = text.cbegin();it != text.cend() && !it->empty();++it}{
cout << *it << endl;
}
14. 複雜數組聲明
int a[10];
int * p1[10]; // 存放10個指針的數組
int (*p2)[10]; // p是指針,指向存放10個int的數組
int(&r)[10] = a; // r是引用,引用含有10個int的數組
int *(&arr)[10] = p1; //arr是引用,引用一個數組,該數組是存放10個指針的數組。
15. 數組索引類型
數組下標類型size_t,無符號類型,足夠大,可以表示內存中任意對象的大小
int scores[10] = {};
for (auto i: scores){
cout << typeid(i).name()<< " " <<i << endl;
}
16. 標準庫函數 begin, end
需要包含頭文件 #include
int arr[] = {0,1,2,3,4,5,6};
int *beg = begin(arr);
int *last = end(arr); // 指向尾元素的下一個位置
cout << *beg;
cout << *(last-1);
17. 指針下標的表示
int a[] = {1,2,3,4,5,6};
int *p=a+1;
cout << p[0];
18. 標準庫函數string
儘量還是使用string對象,而不是標準庫函數,因爲常常會出現越界的情況
char a[] = "hello";
char b[] = "areyouok";
strlen(a); // 返回字符串的長度
strcmp(a,b); // 比較兩個字符換是否相等a>b返回正
strcat(a, b); // 拼接字符串,返回a
strcpy(a, b); // 將b拷貝給a,返回a
// 混用數組字符串和string對象
string a("areyouok");
const char *str = a.c_str();
char b[] = { 1,2,3,4,5 };
vector<char> vec(begin(b), end(b));
19. 多維數組
int a[3][4] = {
{1,2,3,4},
{2,3,4,5},
{3,4,5,6}
};
int (&b)[4] = a[1]; // b 爲四元數組的引用
int(*c)[4] = &a[1]; // c 爲指向四元數組的指針
int(*d)[4] = a; // d 爲指向四元數組的指針
// 用for循環處理多維數組,必須用到引用類型,否則無法通過編譯
for (auto &row :a){
for (auto &col : row){
cout << col << " ";
}
cout << endl;
}
for (auto &row:a){
for(auto col:row)
cout << col << " ";
cout << endl;
}
// 指針和多維數組
for (auto p=a;p!=a+3;p++){ // p是指向四個元素的數組,
for (auto q = begin(*p);q!=end(*p);q++){ // q是指向
cout << *q;
}
cout << endl;
}
20. 運算符
-
遞增遞減運算符
優先使用++a,而不是a++型
*p++; // *(p++) 將p值+1後,返回p指向的初始值
cout << *it++ << endl;
-
成員訪問運算符
string s = "hello", *p = &s; auto n = s.size(); n = (*p).size(); n = p->size();
-
條件運算符
注意: 當其他表達式子裏有條件運算符出現時,通常需要加上括號
int grade = 75; string finalgrade = (grade > 90) ? "great": ((grade > 60)?"good" : "bad");
-
sizeof運算符
int a; sizeof(int); sizeof a;
21. 異常處理
throw runtime_error("Data must be equal");
try{
//
}catch(runtime_error err){
cout << err.what();
}
二、函數
1. 局部靜態對象
有些時候,有必要令局部變量的聲明週期貫穿函數調用之後的時間,可以將局部變量定義成static類
size_t count_calls() {
static size_t count=0;
return ++count;
}
int main(int argc, char ** argv) {
for (size_t i = 0; i < 10; i++) {
cout << count_calls() << endl;
}
}
2. 指針形參傳遞
void reset(int *p) { // 當調用函數時,形參p指針拷貝了原來的指針的地址,是兩個不同的指針
*p = 10; // 修改形參p指向的值,會修改原來指針的值
p = nullptr; // 修改形參p的指向,不會對原來的指針造成影響
}
int main(int argc, char ** argv) {
int i = 42;
reset(&i);
cout << "i=" << i << endl;
system("pause");
return 0;
}
3. 引用形參傳遞
值傳遞和引用傳遞都可以作爲函數的形參。
當某種類型不支持拷貝操作時,比如IO,函數只能通過引用形參訪問該類型對象。
當函數無須修改引用形參的值時,最好用常量引用。
bool isShorter(const string &s1, const string &s2){
return s1.size()+s2.size();
}
函數如何返回多個信息?
方法一:定義一個新的數據類型,讓它包含多個成員
方法二:給函數傳入額外的引用實參,令其保存需要的信息