編輯:劉風琛
最初編寫日期:2020年4月11日下午 最新更新日期:2020年9月20日上午
標註:
- 從筆記開始截止到程式第四章“程式流程結構”,使用Joplin編寫,其餘部分為Typora編寫。
- 筆記對應課程連結為:(https://www.bilibili.com/video/BV1et411b73Z) 作者:黑馬程式設計師-
- 當前進度為
P107
:類和物件
1. 變數
給一段記憶體起名,方便使用。
2. 常量
用於記錄程式中不可更改的資料。
- 定義常量的兩種方式
- #define巨集常量
#define 常量名 常量值
- 通常在檔案上方定義,表示一個常量。
- const修飾的變數
const 資料型別 常量名=常量值
- 通常在變數定義前加const,修飾該變數為常量,不可更改。`
- #define巨集常量
3. 資料型別
sizeof()
可以返回當前資料型別所佔記憶體大小。
-
強制轉換
語法:(資料型別)被轉變數
舉例:int main(){ char ch = 'a'; cout<<(int)ch<<endl; return 0; }
輸出結果:
97
(字元a的ASCII碼) -
轉義字元
轉義字元用反斜槓\
表示,可以用來表示ASCII碼的特殊值。
轉義字元 | 含義 | ASCII碼值 |
---|---|---|
\a | 警報 | 007 |
\b | 退格(BS),將當前位置移到前一列 | 008 |
\f | 換頁(FF),將當前位置移到下頁開頭 | 012 |
\n | 換行(LF),將當前位置移到下一行開頭 | 010 |
\r | 回車(CR),將當前位置移到本行開頭 | 013 |
3.1 整型
C++中可以用以下方式表示整型,區別在於所佔記憶體空間不同
資料型別 | 佔用空間 | 取值範圍 |
---|---|---|
short(短整型) | 2位元組 | -215~215-1 |
int(整型) | 4位元組 | -231~231-1 |
long(長整型) | windows為4位元組;Linux 32位4位元組,64位8位元組 | -231~231-1 |
long long(長長整型) | 8位元組 | -263~263-1 |
3.2 浮點型(小數)
浮點型分為以下兩種:
資料型別 | 佔用空間 | 取值範圍 |
---|---|---|
float(單精度) | 4位元組 | 7位有效數字 |
double(雙精度) | 8位元組 | 15~16位有效數字 |
- 科學計數法
舉例:
整數:3e1表示3*10^1,也就是30
小數:3e-1表示3*10^-1,也就是0.3
3.3 字元型
表示單個字元的資料型別,只佔一個位元組。
- 語法:
char ch = 'a'
- 注意:
- 字元需要用單引號括起。
- 且單引號中只能有一個字元。
- 計算機真正存放的不是字元,是ASCII碼。
3.4 字串
表示一串字元,可以有兩種表示方式。
-
C語言中常用方式(陣列):
char 變數名[] = "abcde"
示例:int main(){ char str[] = "Hello world!"; cout<<str<<endl; return 0; }
- 注意:
- 字串內容要用單引號括起來。
- 變數名後必須加中括號表示陣列。
- 注意:
-
當前標準方式:
string 變數名 = "abcde"
示例:#include <string> int main(){ string str = "Hello World!"; cout<<str<<endl; return 0; }
- 注意:
- 使用
string
需要引入標頭檔案:#include <string>
- 使用
- 注意:
3.5 布林型別
代表"true(1)"或者"false(0)",表示邏輯。
- 所佔記憶體:1位元組。
- 本質上1代表真,0代表假。
- 使用cin輸入時,非0表示真,0表示假,0~1之間的小數視為0。
3. 運算子
包括四則運算,取餘等方法。
-
四則運算注意事項
- 除法符號為"
/
"注意不要和反斜槓"\
"混淆。 - 除法運算時,兩個整數(這裡指型別)相除,結果依然是整數,小數部分消除(不是四捨五入)。
- 0為除數時程式崩潰
- 除法符號為"
-
取模運算
- 符號為"
%
" - 取模運算作用是獲取兩數相除所得餘數。
- 取模運算本質上也是除法的一種,除數不可為0。
- 小數不可以進行取模運算
- 符號為"
-
遞增和遞減
- 兩者的功能類似,都是讓變數加、減1
- 前置遞增/遞減為先加1,後運算;後置遞增/遞減為先運算,後加1.
-
賦值運算子
- 包括
=
、+=
、-=
、*=
、/=
、%=
。
示例:int main(){ int a=1; a=3; //此時a=3; a+=2; //此時a=5 a-=3; //此時a=2 a*=2; //此時a=4 a/=2; //此時a=2 a%=1; //此時a=0 cout<<a<<endl; return 0; }
- 包括
-
比較運算子
-
包括
==
、>=
、<=
、!=
、>
、<
。 -
邏輯運算子
- 包括非
!
、與&&
、或||
。
- 包括非
-
三目運算子
- 用法:
表示式1 ? 表示式2 : 表示式3
- 含義:如果表示式1成立,則返回表示式2的執行結果,否則返回表示式3的執行結果。
示例:
int main(){ int a=1,b=10,c=0; //用法一 c = (a > b ? a : b); //括號能提高三目運算的優先順序防止執行出錯 //將a和b中值較大的賦值給c //用法二 (a > b ? a : b) = 999; //把999賦給a和b中較大的變數 return 0; }
- 用法:
4. 程式流程結構
4.1 順序結構
就是從頭到尾順序執行,沒啥可記的。
4.2 選擇結構
判斷選擇,可以實現跳過或者分支。
-
if語句
用法一:if(條件){滿足條件執行的程式碼塊}- 注意:
- 注意不要加入多餘的分號。
- 示例:
int main(){ int score; cout<<"Please input your score:"; cin>>score; if (score>=600){ cout<<"Good!"; } return 0; }
用法二:if(條件){滿足條件執行的程式碼塊}else{不滿足時執行的程式碼塊}
- 注意:
else
為可選分支,刪除後和用法一相同。- 注意不要加入多餘的分號。
int main(){ int score; cout<<"Please input your score:"; cin>>score; if (score>=600){ cout<<"Good!"; }else{ cout<<"Bad!"; } return 0; }
用法三:if(條件1){滿足條件執行的程式碼塊}else if(條件2){不滿足條件1但滿足條件2時執行的程式碼塊}
-。else
和else if
為可選分支.else if
可並列多次使用
int main(){ int score; cout<<"Please input your score:"; cin>>score; if (score>=600){ cout<<"Good!"; } else if(score>=400){ cout<<"Bad!"; } else{ cout<<"So Bad!"; } return 0; }
用法四:if語句的巢狀,我認為沒啥高階的,所以不記了。
- 注意:
-
switch語句
- 用法:在示例中演示
- 意義:可以輕鬆實現多分支
示例:
int main(){ int level; cin>>level; switch(level){ case 1: cout<<"Good"; break; case 2: cout<<"Normal"; break; case 3; cout<<"Bad"; break; default : cout<<"非法輸入!請輸入1~3之間的整數。"; break; } return 0; }
- 注意:
- 需要使用break跳出分支。
- 缺點是無法使用區間視線分支。
4.3 迴圈結構
迴圈執行程式碼塊。
4.3.1 while語句
條件滿足時不斷迴圈執行指定程式碼塊,否則跳出迴圈。
-
用法:
while(條件){條件為真時迴圈執行的程式碼塊}
-
注意:
- 可以使用
break
跳出迴圈。
- 可以使用
-
示例:
int main(){ int a=0; while(a<10){ a++; cout<<a; } return 0; }
4.3.2 do...while語句
-
用法:
do{程式碼塊}while(條件);
-
注意:
- 基本注意事項和
while
相同。
- 基本注意事項和
-
示例:
int main(){ int a=0; do{ a++; cout<<a<<endl; } while(a<10); return 0; }
4.3.3 for迴圈語句
-
用法:
for(起始表示式;條件表示式;末尾表示式){迴圈程式碼塊}
-
注意:可以使用
break
跳出迴圈。 -
示例:
int main(){ for(int i=1;i<10;i++){ cout<<i<<endl; } return 0; }
4.4 跳轉語句
用於跳出或者移動當前結構中的執行位置。
4.4.1 break語句
- 可以出現在switch語句中,用於跳出分支。
- 可以出現在迴圈語句中,用於跳出迴圈。
- 在位於巢狀迴圈結構時,用於跳出當前所在層的迴圈。
4.4.2 continue語句
-
作用:在迴圈語句中跳過餘下尚未執行的語句,直接進入下一次迴圈。
-
示例:
int main(){ for (int i=1;i<=10;i++) { cout<<i<<endl; continue; cout<<"這段不被輸出\n"; } return 0; }
4.4.3 goto語句
-
作用:可以跳轉到任意標記的位置。
-
示例:
int main(){ for(int i=1;i<=10;i++){ cout<<"這是第一句話\n"; cout<<"這是第二句話\n"; goto flag; cout<<"這句話我們不要了\n"; flag: cout<<"這是第三句話\n"; } return 0; }
5. 陣列
陣列就是一個集合,裡邊存放了一組相同型別的資料。
- 特點
- 陣列中每個元素都是相同的資料型別。
- 陣列是由連續的記憶體位置組成的。
5.1 一維陣列
-
一維陣列的定義方式:
資料型別 陣列名[陣列長度];
資料型別 陣列名 [陣列長度]={值1,值2,...,值n};
資料型別 陣列名[]={值1,值2,...,值n};
-
訪問格式:
array [0]
-
注意事項:
- 訪問時下標從0開始。
-
示例:
int main(){ int arr[5]={1,2,3,4};//只初始化了前四個,第五個值預設初始化為0 for(int i=0;i<=4;i++) { cout<<arr[i]<<endl; } arr[4]=5; //這是對陣列中未初始化的第5個值賦值 cout<<arr[0]; return 0; }
-
補充:
- 陣列名的用途:
- 可以統計陣列或陣列中元素所佔記憶體空間。(使用
sizeof(陣列名/陣列名[])
函式) - 可以獲取陣列在記憶體中的首地址。(
cout<<array;
)
- 可以統計陣列或陣列中元素所佔記憶體空間。(使用
- 陣列名為常量,不可直接賦值。
- 陣列名的用途:
-
一維陣列的倒置示例:
int main(){ int arr [5]={1,2,3,4,5};//建立一個陣列 int temp,a,b; a=0;b=sizeof(arr)/sizeof (arr[0])-1;//b為通過計算得出的陣列中元素數量減1 while(a<b){ temp=arr[a]; arr[a]=arr[b]; arr[b]=temp; a++;b--; } b=sizeof(arr)/sizeof (arr[0]);//為了節省記憶體,將b重置為陣列元素個數 for(int i = 1;i<=b;i++){ //迴圈b次,依次輸出陣列中每個元素的值 cout<<arr[i-1]<<endl; } return 0; }
-
一維陣列的順序排列示例(氣泡排序):
int main(){ int arr[5]={1,5,2,3,4}; for (int i = 0;i < 5;i++){ for(int j = 0;j<(5-i-1);j++){ if (arr[j]>arr[j+1]){ int temp; temp=arr[j]; arr[j]=arr[j+1]; arr[j+1]=temp; } } } for (int q = 1; q<=5;q++){ cout<<arr[q-1]<<endl; } return 0; }
5.2 二維陣列
-
定義方式:
資料型別 陣列名 [行數][列數]={{數值1,數值2...},{數值n,數值n+1...}};
資料型別 陣列名 [行數][列數];
資料型別 陣列名 [行數][列數]={資料1,資料2,資料3,資料4};
資料型別 陣列名 [][列數]={資料1,資料2,資料3,資料4};
-
示例:
int main(){ //這是建立二維陣列最直觀的形式 int arr[2][3]={ {1,2,3}, {4,5,6} }; //使用for迴圈巢狀遍歷輸出二位陣列中每個元素 for (int i=0;i<2;i++){ for (int j=0;j<3;j++){ cout<<arr[i][j]<<" "; } cout<<endl; } return 0; }
-
二維陣列名的用途
- 可以統計陣列、陣列中一行或陣列中元素所佔記憶體空間。(使用
sizeof(陣列名/陣列名[]/陣列名[][])
) - 可以獲取陣列在記憶體中的首地址。(
cout<<array;
)
- 可以統計陣列、陣列中一行或陣列中元素所佔記憶體空間。(使用
-
注意:
- 為了程式的可讀性,我們一般使用前兩種定義方式。
- 第三種定義方式會自動分出行列。
- 第四種必須指定列數,行數會依據資料數量進行自動分配。
6. 函式
函式就是一個程式塊,可以方便的進行呼叫,能很好的減少程式碼量,一個較大的程式往往分成好多模組,每個模組實現特定功能。
6.1函式的定義
-
函式的定義示例:
返回值型別 函式名(形參) { 程式程式碼塊; retuen 返回值表示式; }
-
注意:
- 必須返回一個正確的返回值型別。
- 若不需要返回值可以宣告void函式。
6.2 函式的呼叫
- 語法:
函式名(引數)
- 形式引數也叫
形參
,是一個形式,呼叫的是使用函式時傳遞的實參
。 - 形參的值在函式中發生變化不會影響到實參。
6.3 函式的宣告
-
語法
返回值型別 函式名(形參)
-
注意:
- 在main函式前宣告函式防止程式執行時無法正常呼叫函式。
- 可以有多次宣告,但是隻能有一次定義
-
示例:
int max(int num1,int num2); //函式max的宣告 int main(){ cout<<max(100,101)<<endl; return 0; } int max(int num1,int num2){ //函式的定義 return num1 > num2 ? num1:num2; } //函式定義在main函式後需要在main函式前宣告。
6.4 函式的分檔案編寫
為了防止單檔案形勢下程式碼量過大。
-
要素:
- 一個自定義的標頭檔案(.h)
- 原始檔(.cpp)
- 函式的宣告寫在標頭檔案中
- 函式的定義寫在原始檔中
-
示例:
-
檔案結構:
-
程式碼示例:
-
main.cpp
#include <iostream> #include "max.h" using namespace std; int main(){ cout<<max(100,101)<<endl; return 0; }
-
max.h
#include <iostream> using namespace std; int max(int num1,int num2);
-
max.cpp
#include "max.h" int max(int num1,int num2){ return num1 > num2 ? num1:num2; }
輸出結果:100
-
-
6.5 函式的預設值
-
語法:
返回值型別 函式名(引數名=預設值);
-
注意:
- 如果某個位置開始有預設引數,那麼從該位置往後都應該有預設引數。
- 宣告和實現只能有一個設定預設引數,不允許重定義預設引數。
-
示例:
void print(int a=10,int b=20,int c=30){ //給所有選項都設定了預設引數 cout<<a+b+c<<endl; } int main() { print(1,2,3);//呼叫函式是傳遞引數 //輸出6 print();//呼叫函式時不傳遞引數,使用預設引數 //輸出60 return 0; }
6.6 函式的佔位引數
-
語法:
返回值型別 函式名 (資料型別);
-
示例:
void print(int = 10){ //只有資料型別,沒有變數名就是佔位引數 cout<<"Hello World!"; } int main(){ print(); //因為佔位引數具有預設值,所以此處無需傳遞,否則必須傳遞一個相應型別的引數 }
6.7 函式的過載
6.7.1 概述
-
意義:函式名可以相同,提高函式複用性。
-
條件:
- 同一作用域下。
- 函式名稱相同。
- 函式
引數名
或引數個數
或引數順序
不同。
-
注意:函式的返回值不可用作函式過載的條件。
-
示例:
void print(){ cout<<"print()函式被呼叫\n"; } void print(int a){ cout<<"print(int a)函式被呼叫\n"; } int main() { print();//print()函式被呼叫 print(1);//print(int a)函式被呼叫 //其他例如引數名,引數個數,引數順序不同 同理 return 0; }
6.7.2 函式過載的細節問題
-
常量引用
-
示例:
void print(int& a){ cout<<"print()函式被呼叫\n";//如果傳入數字1,則為int& a = 1 不合法 } void print(const int& a){ //相當於const int& a = 1 合法 cout<<"print(int a)函式被呼叫\n"; } int main() { int a=1; print(a); print(1); return 0; }
-
-
引入預設值導致的二義性
-
示例:
void print(int a){ cout<<"print()函式被呼叫\n"; } void print(int a,int b=1){ cout<<"print(int a,int b=1)函式被呼叫\n"; } int main() { print(1);//這個會報錯,因為產生了二義性 print(1,1);//會呼叫print(int a,int b=1)函式 return 0; }
-
7. 指標
可以通過指標間接訪問記憶體地址。
- 注意:
- 記憶體編號從0開始記錄,一般使用十六進位制數字儲存
- 可以利用指標變數儲存地址
- 不管什麼指標,在32位系統下佔用4位元組,64位佔用8位元組。
7.1 指標的定義
- 語法:
資料型別 * 指標變數名
7.2 指標的使用
-
讓指標記錄一個地址:
-
語法:
指標變數名 = &變數名
-
注意:
&
為取址符,可以獲取當前記憶體地址。
-
-
指標指向函式:
- 語法:
返回值 (*指標名)(引數列表);
- 語法:
-
指標的使用:
-
通過
解引用
影響指標指向記憶體區域所儲存的值。 -
示例:
int main(){ int a = 10; int * p; //定義一個指標p p=&a; //將變數a的地址賦給指標p //int * p = &a; //這個方式可以將定義和賦值寫在一起 *p=1000; //使用解引用影響指標p指向的記憶體區域,也就是變數a cout<<a<<endl; cout<<*p<<endl; //通過輸出展示指標所產生的影響 return 0; }
-
7.3 空指標
- 用途:給指標變數初始化。
- 特點:空指標指向的記憶體區域無權訪問。
- 定義一個空指標:
int * p = NULL
7.4 野指標
- 定義:指向一塊未申請的記憶體區域。
- 特點:
- 指向的記憶體區域通常無法讀取或修改。
- 一旦嘗試讀取或修改,則會報錯。
7.5 const修飾指標
-
三種方式:
- const修飾指標:常量指標
- 用法:
const int * p = NULL
- 作用:指標所指向的記憶體地址中的值為常量,不可更改;但是指標所指的地址可以更改。
- 用法:
- const修飾常量:指標常量
- 用法:
int * const p = NULL
- 作用:指標本身為常量,指向的記憶體地址不可更改,但是其值可以更改。
- 用法:
- const同時修飾指標和常量
- 用法:
const int * const p=NULL
- 作用:指標所指的記憶體地址不可更改,值也不可更改。
- 用法:
- const修飾指標:常量指標
7.6 指標和陣列
用指標運算元組。
-
示例:
int main(){ int arr[5]={1,2,3,4,5}; int * p=arr; //將指標指向陣列在記憶體中的首地址 for (int i=0;i<5;i++){ cout<<*p<<endl; //輸出指標p指向的值 p++; //每次迴圈將指標p向後偏移4位元組,實現指標在陣列中的遍歷 } return 0; }
7.7 指標和函式
利用指標作為函式的引數可以修改實參的值。
-
示例:
void swap(int *p1,int *p2){ //宣告一個函式用來交換兩個變數的值,形參為兩個指標 //這部分直接影響了指標所指向的記憶體空間,也就是main函式中a,b兩個變數的值 int temp=*p1; *p1=*p2; *p2=temp; } int main(){ int a=1,b=2; cout<<"a="<<a<<" b="<<b<<endl; swap(&a,&b); //引用函式,實參為兩個變數的地址 cout<<"a="<<a<<" b="<<b<<endl; return 0; }
# 指標、函式、陣列的搭配示例
利用冒泡迴圈對陣列排序。
int bubbleSort(int * arr,int len){ //使用函式封裝冒泡迴圈的演算法
for (int i = 0;i<len;i++){
for(int j=0;j<len-i-1;j++){
if(arr[j]>arr[j+1]){
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
}
int main(){
int arr []={1,5,3,2,7,8,3,5,2};
int len=sizeof(arr)/sizeof (arr[0]); //獲取陣列的元素數量
bubbleSort(arr,len); //呼叫函式,第一個實參為arr陣列的記憶體地址
for(int i = 0;i<len;i++){
cout<<arr[i]<<endl;
}
}
8. 結構體
允許使用者建立自定義資料型別
,儲存不同的資料型別。
8.1 定義和使用
-
語法:
struck 結構體名 { 結構體成員列表 };
-
建立變數方式:
- struck 結構體名 變數名 = {成員1;成員2;...}
- struck 結構體名 變數名
- 定義結構體時順便建立變數
-
使用變數的屬性
- 格式:
變數名.屬性
- 格式:
-
示例:
struct student //定義結構體(全域性),struct關鍵字不可省略 { string name; int age; int score; }s3; //此處s3為使用方法三建立的結構體變數 int main(){ //方法一 struct student s1={"Maicss",19 , 650 } ; //struct關鍵字可以省略 cout<<"name:"<<s1.name<<"\tage:"<<s1.age<<"\tscore:"<<s1.score<<endl; //方法二 struct student s2; //struct關鍵字可以省略 s2.name="qian"; s2.age=18; s2.score=600; cout<<"name:"<<s2.name<<"\tage:"<<s2.age<<"\tscore:"<<s2.score<<endl; //方法三 //建立結構體變數在定義結構體之後 s3.name="son"; s3.age=1; s3.score=700; cout<<"name:"<<s3.name<<"\tage:"<<s3.age<<"\tscore:"<<s3.score<<endl; return 0; }
8.2 結構體陣列
-
作用:將自定義的結構體放入陣列中方便維護。
-
語法:struck 結構體名 陣列名[成員數] = { { } , { } , { } }
-
示例:
struct student { //定義一個結構體 string name; int age; int score; }; int main() { //建立一個結構體陣列 struct student stuarr[3]{ {"Maicss",19,100}, {"Max",20,99}, {"Pig",10,30} }; //給結構體陣列中第三個成員的score修改為98 stuarr[2].score =98; //遍歷輸出結構體陣列所有成員屬性 for (int i=0 ;i<3;i++){ cout<<"name:"<<stuarr[i].name<<"\tage:"<<stuarr[i].age<<"\tscore:"<<stuarr[i].score<<endl; } return 0; }
8.3 結構體指標
-
作用:通過指標訪問結構體中的成員。
-
利用操作符
->
可以通過結構體指標訪問結構體屬性。 -
示例:
struct student { //定義一個結構體 string name; int age; int score; }; int main() { //建立一個結構體陣列 student s{"Maicss",19,100}; //建立一個結構體指標 student * p = &s; //通過指標讀取結構體變數屬性 cout<<"name:"<<p->name<<"\tage:"<<p->age<<"\tscore:"<<p->score<<endl; return 0; }
8.4 結構體巢狀
-
作用:讓一個結構體成為另一個結構體的成員。
-
示例:
struct student { //定義一個結構體 string name; int age; int score; }; struct teacher { //定義另一個結構體 string name; int id; int age; student std; }; int main() { //建立一個結構體變數 student std1 {"max",18,100}; //建立另一個結構體變數 teacher thr1 {"maicss",197835,23,std1}; //建立一個結構體指標 teacher * p = &thr1; //修改老師maicss的學生max的年齡為19 thr1.std.age=19; //通過指標讀取結構體變數屬性 cout<<"name:"<<p->name <<"\tID:"<<p->id <<"\tage:"<<p->age <<"\tstudent:"<<p->stds.name //讀取巢狀在teacher結構體中的student的屬性 <<"\tstudentAge:"<<p->stds.age //檢視更改後的學生年齡 <<endl; return 0; }
8.5 將結構體作為函式引數傳遞
-
值傳遞
- 直接在函式引數中傳遞結構體變數。
- 特點:在函式內對引數值(結構體屬性)的修改不會影響實參。
-
指標傳遞
- 在函式引數中傳遞結構體指標。
- 特點:對值(結構體屬性)的修改會影響到實參。
-
const 保護
- 用const修飾指標,防止在函式中無意影響到函式實參。
-
示例:
struct student { //定義一個結構體 string name; int age; int score; }; void print1(student a){ //結構體在函式引數中通過值傳遞 cout<<"name:"<<a.name<<" age:"<<a.age<<" score:"<<a.score<<endl; } void print2(student * p){ //結構體在函式引數中通過指標傳遞 p->age=100; //通過指標修改結構體屬性的值可以影響到實參 cout<<"name:"<<p->name<<" age:"<<p->age<<" score:"<<p->score<<endl; } int main() { //建立一個結構體變數 student std1 {"max",18,100}; //建立一個結構體指標 student * p =&std1; //呼叫函式進行輸出 print1(std1); //值傳遞 print2(&std1);//指標傳遞 cout<<"name:"<<std1.name<<" age:"<<std1.age<<" score:"<<std1.score<<endl; //驗證print2函式的修改 return 0; }
9. 聯絡人管理系統例項
10 程式的記憶體模型
10.1 記憶體分割槽模型
- 程式碼區:存放函式體的二進位制程式碼,由作業系統進行管理。
- 全域性區:存放全域性變數和靜態變數以及常量。
- 棧區:由編譯器自動分配和釋放,存放函式的引數值,區域性變數等。
- 堆區:由程式設計師分配和釋放,若程式設計師不釋放,程式結束時由系統回收。
10.2 分割槽意義
- 不同區域存放的資料賦予不同的生命週期,更強大的靈活的程式設計。
10.3 程式執行前
程式編譯後,生成exe
可執行程式,未執行該程式前分為兩個區域。
- 程式碼區:
- 存放CPU執行的機器指令。
- 程式碼區是共享的,共享的目的是對於頻繁被執行的程式,只需要在記憶體中有一份程式碼即可。
- 全域性區:
- 全域性變數和靜態變數存放在此。
- 全域性區也包含了常量區,字串常量和其他非區域性常量也存放在此。
- 該區域的資料在程式結束後由作業系統釋放。
10.4 程式執行後
-
棧區
-
由編譯器自動分配和釋放,存放函式的引數值,區域性變數等。
-
注意:不要返回棧區的地址,棧區開闢的資料由編譯器自動釋放。
-
棧區的資料在函式執行完後自動釋放。
-
示例:
int* integer(){ int a=1; return &a; //返回區域性變數a的記憶體地址 } int main() { int * p=integer(); //將指標p指向區域性變數a的地址 cout <<*p<< endl; //第一次解引用p //這裡之所以會輸出a是因為編譯器為程式保留了一次記憶體 cout <<*p<< endl;//第二次解引用p //編譯器不再為程式保留,所以不再是原來的數值 return 0; }
-
-
堆區
-
由程式設計師分配和釋放,若程式設計師不釋放,程式結束時由系統回收。
-
使用
new
在堆區開闢記憶體。- 語法:
new 資料型別
- new建立的資料會返回該資料型別對應的指標。
- 語法:
-
使用
delect
釋放記憶體。- 語法:
delect 指標
- 釋放後不能繼續訪問。
- 語法:
-
-
為了防止出現
野指標
,在堆區記憶體空間被釋放時要將指向該記憶體的指標指向NULL
。- 示例:
int main() { int * p = new int(10); //使用new開闢一塊記憶體儲存整數10並將地址給指標p int * p2 = new int[10]; //建立一個陣列 cout<<*p<<endl;//解引用指標p結果為10 //賦值部分省略 delete p;//釋放記憶體 delete[] p2;//釋放陣列 }
- 示例:
11. C++中的引用
引用的本質是指標常量。
11.1 引用的基本使用
-
作用:給變數起別名。
-
語法:
&別名=原名
-
注意事項:
- 引用必須要初始化。
- 引用一旦初始化就不可以更改。
11.2 引用作函式引數
-
作用:就像指標一樣,可以影響到實參。
-
示例:
//建立一個交換函式 void swap(int &a,int &b){ //使用引用傳遞引數 int temp; temp=a; a=b; b=temp; } int main() { int a,b; a=0;b=1; swap(a,b); cout<<a<<"\n"<<b<<endl; }
11.2 引用作函式的返回值
-
作用:可以讓函式的呼叫作為左值。
-
示例:
//建立一個函式 int& num(){ static int a=10; //建立靜態變數,儲存在全域性區中 return a; } int main() { int& ref=num(); // 給num函式中的a搞一個引用 num()=1000; cout<<ref<<endl; //驗證將函式呼叫作為左值是否有效 return 0; }
-
11.3 常量引用
-
作用:可以用來修飾形參,防止實參被影響。
-
示例:
void change(const int& a){ //使用const修飾形參 //此處不可修改a的值 cout<<a; } int main() { int a=1; change(a); return 0; }
12. 類和物件
C++物件導向的三大特性:封裝、繼承、多型。
萬物皆物件、物件上有其屬性和行為。
12.1 封裝
12.1.1 封裝的意義
-
封裝是c++物件導向三大特徵之一
-
封裝的意義:
- 將屬性和行為作為一個整體來表現實物。
- 將屬性和行為加以許可權控制。
-
示例:
#include <iostream> using namespace std; #define Pi 3.1415926 //定義一個巨集常量Pi class circle{ //建立一個circle類 public: //定義公有部分 int r; //定義一個半徑屬性r double circle_C(){ //定義一個成員函式,計算周長 return 2*r*Pi; } void set_r(double set_r){ r=set_r; } }; int main() { circle yuan; //通過circle類例項化一個物件 yuan.r=10; //給物件的公有屬性r賦值 cout << yuan.circle_C() << endl; //通過成員函式輸出周長 yuan.set_r(5); cout << yuan.circle_C() << endl; //通過成員函式輸出周長驗證修改 return 0; }
12.1.2 訪問許可權控制
-
總共有三個許可權
名稱 意義 特點 public 公共許可權 類內和類外都可以訪問 protected 保護許可權 類內可以訪問,類外不可以訪問,子可以訪問父的保護內容 private 私有許可權 類內可以訪問,類外不可以訪問,子不可訪問父的私有內容 -
class
和struct
的區別:class
預設是私有許可權,struct
預設是公有許可權。
12.1.3 成員屬性私有化
-
優點:
- 對成員屬性私有化可以自己控制讀寫許可權。
- 對於讀寫許可權,可以檢測資料的有效性。
-
示例:
#include <iostream> using namespace std; class human{ public: void setName(string set_name){ //定義一個用來設定姓名的成員函式 name=set_name; } string getName(){ //定義一個獲取姓名的成員函式 return name; } void setAge(int set_age){ //定義一個用來設定年齡的成員函式 if (set_age<0 || set_age>150){ //使用if語句判斷所給值是否合法 cout<<"非法資料!"; }else{ age=set_age; } } int getAge(){ //定義一個用來獲取年齡的成員函式 return age; } void setLover(string set_lover){ //定義一個用來設定愛人的成員函式 lover=set_lover; } private: //私有屬性的定義 string name; int age; string lover; }; int main() { human maicss; //例項化一個物件 //使用成員函式設定相關屬性 maicss.setName("Maicss"); maicss.setAge(18); maicss.setLover("qian"); //使用成員函式獲取相關私有函式的值在 cout<<"name:"<<maicss.getName()<<" age:"<<maicss.getAge()<<endl; return 0; }
12.2 物件的初始化和清理
12.2.1 建構函式和解構函式
-
物件的
初始化
和清理
是兩個重要的問題。- 一個物件或者變數沒有初始化狀態,其使用後果是未知的。
- 使用完一個物件或者變數,沒有及時的清理,也會造成一定的安全問題。
-
注意:
- 建構函式和解構函式可以解決上述問題,由編譯器自動呼叫,完成物件的初始化和清理工作。物件的初始化和清理是必須要做的事情。因此不必要提供構造和解構函式,編輯器會提供,但是編譯器提供的建構函式和解構函式是
空實現
。 - 一個空物件所佔用的記憶體為1位元組,因為物件必須要有一個首地址。
- 建構函式和解構函式可以解決上述問題,由編譯器自動呼叫,完成物件的初始化和清理工作。物件的初始化和清理是必須要做的事情。因此不必要提供構造和解構函式,編輯器會提供,但是編譯器提供的建構函式和解構函式是
-
作用:
- 建構函式:主要用在建立物件時給物件的成員屬性賦值,由編譯器自動呼叫。
- 解構函式:主要用於物件銷燬前的自動呼叫,負責清理工作。
-
語法:
-
建構函式:
類名(){}
- 建構函式,沒有返回值,也不用寫void。
- 函式名稱和類名相同。
- 建構函式可以有引數,因此可以發生過載。
- 程式在呼叫物件的時候自動呼叫建構函式,並且只會呼叫一次,無需手動呼叫。
-
解構函式:
~類名(){}
- 解構函式,沒有返回值,也不用寫void。
- 函式名稱和類名相同,在名稱前加上
~
。 - 解構函式不可以有引數,因此無法發生過載。
- 程式在物件銷燬前自動呼叫解構函式,並且只會呼叫一次,無需手動呼叫。
- 手動釋放在堆區申請的空間要用
delete
語句。
-
-
示例:
class human{ public: //為了保證建構函式和解構函式能被全域性呼叫,所以需要設定為public許可權 human(){ //建立一個建構函式 cout<<"human的建構函式被呼叫\n"; } ~human(){ //建立一個解構函式 cout<<"human的解構函式被呼叫\n"; } }; void hum(){ //函式中例項化一個物件,函式執行結束後物件被銷燬 human m; } int main() { human maicss;//建立物件同時執行建構函式 hum(); //呼叫hum函式來建立物件,同時執行建構函式 //hum函式執行結束時物件m被銷燬,同時執行解構函式 return 0;//mian函式返回0,程式結束前會執行解構函式 }
12.2.2 建構函式的分類以及呼叫
-
兩種分類方式:
- 按引數分為:有參構造和無參構造
- 按型別分為:普通構造和拷貝構造
- 拷貝建構函式是用來將一個物件的所有屬性拷貝到新物件中。
-
三種呼叫方式:
- 括號法
- 顯示法
- 隱式轉換法
-
注意事項:
- 使用預設建構函式時,不要用
()
,否則會被認為是函式定義。 - 不要利用拷貝建構函式初始化匿名物件,編譯器會認為是引數物件的宣告。
- 使用預設建構函式時,不要用
-
示例(有點長):
class human{ public: human(){ cout<<"human的無參(預設)建構函式被呼叫\n"; } human(int a){ age=a; cout<<"human的有參建構函式被呼叫\n"; } human(const human &p){ //const的意義是不允許在建構函式中修改傳入物件的屬性,只讀。 age=p.age; cout<<"human的拷貝建構函式被呼叫\n"; } ~human(){ cout<<"human的解構函式被呼叫\n"; } int age; }; void hum1(){ //括號法呼叫 human m1; //無參構造 human m2(10); //有參構造 human m3(m1); //拷貝構造 } void hum2(){ //顯示法 human m1; //無參構造 human m2=human(10); //有參構造 human m3=human(m1); //拷貝構造 } void hum3(){ //隱式轉換法 human m1; //無參構造 human m2=10; //有參構造 human m3=m2; //拷貝構造 } int main() { hum1(); hum2(); hum3(); return 0; }
12.2.3 拷貝建構函式的呼叫時機
C++中拷貝建構函式的呼叫時機通常由三種情況:
- 使用一個建立完畢的物件來初始化一個新的物件。
- 以值傳遞的方式給函式的引數傳值
- 以值方式返回區域性物件
12.2.4 建構函式的呼叫規則
預設情況下,C++編譯器至少給一個類新增三個函式:
- 預設建構函式(無參,函式體為空)
- 預設解構函式(無參,函式體為空)
- 預設拷貝建構函式,對其屬性值進行拷貝。
建構函式呼叫規則:
- 如果使用者自定義有建構函式,編譯器不再提供預設無參建構函式,但是會提供預設拷貝構造。
- 如果使用者定義拷貝建構函式,編譯器不再提供其他建構函式。
- 總結:寫了有參必須寫無參,寫了拷貝就得有參無參都寫上。
12.2.5 深拷貝與淺拷貝
-
定義:
- 淺拷貝:簡單的賦值操作。如果是用編譯器提供的拷貝函式會利用淺拷貝。
- 深拷貝:在堆區重新申請一塊記憶體空間,進行拷貝操作。
-
注意:
- 淺拷貝可能導致堆區記憶體重複釋放。
-
示例(淺拷貝):
class person{ public: person(){ cout<<"無參建構函式被呼叫\n"; } person(int age,int height){ m_height=new int (height); //在堆區申請一塊記憶體區域用來存放height m_age=age; cout<<"有參建構函式被呼叫\n"; } ~person(){ if(m_height!=NULL){ delete m_height; //釋放m_height指向的記憶體區域 //解構函式會被執行兩次,因為兩個物件在man()函式結束後被銷燬,但是由於淺拷貝將指標拷貝給第二個物件,因此兩個物件的m_height指標指向了堆區的同一塊記憶體區域,這塊記憶體區域釋放兩次,會報錯。 m_height=NULL; //將指標指向NULL,防止野指標的出現。 } cout<<"解構函式被呼叫\n"; } private: int m_age; int * m_height; //建立一個int指標指向有參構造申請的記憶體區域 }; void man(){ person one(16,160); person two(one);//淺拷貝 } int main() { man(); cout << "Hello World!" << endl; return 0; }
-
示例(深拷貝):
class person{ public: person(){ cout<<"無參建構函式被呼叫\n"; } person(int age,int height){ m_height=new int (height); //在堆區申請一塊記憶體區域用來存放height m_age=age; cout<<"有參建構函式被呼叫\n"; } person(const person &p){ m_age=p.m_age; m_height=new int (*p.m_height);//在堆區重新申請一塊記憶體實現深拷貝 } ~person(){ if(m_height!=NULL){ delete m_height; //釋放m_height指向的記憶體,此時不會出現多次釋放同一記憶體空間的問題 m_height=NULL; //將指標指向NULL,防止野指標的出現。 } cout<<"解構函式被呼叫\n"; } int m_age; int * m_height; //建立一個int指標指向有參構造申請的記憶體區域 }; void man(){ person one(16,160); person two(one);//由於定義了拷貝函式,所以此處會通過定義實現深拷貝 cout<<one.m_age<<" "<<*one.m_height<<endl; cout<<two.m_age<<" "<<*two.m_height<<endl; } int main() { man(); cout << "Hello World!" << endl; return 0; }
12.2.6 初始化列表
-
作用:初始化列表語法可以用來初始化物件屬性。
-
語法:
建構函式():屬性1(值1),屬性2(值2), ...
-
示例:
class person{ public: person(int a,int b):age(a),height(b){} int age; int height; }; void man(){ person one(18,180); cout<<"age:"<<one.age<<" height:"<<one.height<<endl; } int main() { man(); return 0; }
12.2.7 類物件作為類成員
-
定義:一個類宣告的物件成為另一個類的屬性成員。
-
例如:
class A{} class B{ A a; }
-
注意:
- 構造時先構造作為屬性成員的物件(A)再構造物件本身(B)。
- 析構時先析構物件本身(B)再析構各個屬性成員(A)。
12.2.8 靜態成員
靜態成員可以看作屬於類的作用域,被所有物件公用。
靜態成員變數和靜態成員函式都有許可權控制。
-
靜態成員變數
-
作用:所有成員公用一個成員變數。
-
語法:
static 資料型別 變數名
-
注意:
- 靜態成員變數要在類內宣告,類外初始化。
- 在編譯階段會分配記憶體
-
示例:
class human{ public: static int age;//在類內的宣告 }; int human::age=100;//在類外的初始化 int main() { human a; cout<<a.age<<endl; human b; b.age=18;//使用物件b給靜態變數重新賦值 //也可以通過類名操作成員變數 human::age=18; cout<<a.age<<endl;//此時物件a的age值也會隨b變成18 return 0; }
-
-
靜態成員函式
-
作用:所有成員公用一個成員函式。屬於類的作用域。
-
語法:
static 函式返回值型別 函式名();
-
注意:靜態成員函式屬於類的作用域,只能操作靜態成員變數。
-
示例:
class human{ public: static void func(){ age=1; } static int age;//在類內的宣告 }; int human::age=100;//在類外的初始化 int main() { human a; cout<<a.age<<endl; human b; //訪問靜態成員函式,下面兩種方式效果完全相同 b.func();//通過物件訪問 human::func();//通過類的作用域訪問 cout<<a.age<<endl; return 0; }
-
12.3 C++物件模型和this指標
12.3.1 成員變數和成員函式分開儲存
- 非靜態成員變數屬於類的物件
- 靜態成員變數不屬於類的物件。
- 非靜態成員函式不屬於類的物件。
- 靜態成員函式不屬於類的物件。
12.3.2 this指標概念
-
作用:this指標指向被呼叫的成員函式所屬的物件。
-
特點:
- 隱含在每一個非靜態成員函式內的一種特殊指標。
- this指標不需要定義,直接用即可。
-
使用場景:
- 當形參名和成員變數名相同時,可以用this指標區分。
- 在類的非靜態成員函式中返回物件本身,可以用
return *this
。
-
示例:
class human{ public: void c_age(int age){ this->age=age;//用this指標表示成員變數 } human& addage(human &p){ //函式返回值要用引用的方式返回,否則會建立新物件 this->age+=p.age; return *this; } int age; }; void func(){ human maicss; human p1; p1.age=10; maicss.c_age(18); maicss.addage(p1).addage(p1).addage(p1); //鏈式程式設計思想 cout<<"maicss的年齡是:"<<maicss.age<<endl; } int main() { func(); return 0; }
12.3.3 空指標呼叫成員函式
空指標可以呼叫成員,但是為了防止崩潰,要避免訪問成員變數。
class human{
public:
void printname(){
cout<<"name is maicss\n";
}
void printage(){
if (this==NULL){//防止程式崩潰進行的保險措施
return ;
}
cout<<"age is "<<this->age<<endl;
}
int age;
};
void func(){
human * maicss=NULL;
maicss->printname();//使用空指標訪問成員函式
maicss->printage();//使用空指標在成員函式中訪問成員變數
}
int main()
{
func();
return 0;
}
12.3.4 const修飾成員函式
常函式:
- 成員函式後加
const
,我們稱這個函式為常函式。 - 常函式內不可以修改成員屬性。
- 成員屬性加關鍵字
mutable
後,在常函式中依然可以修改。
常物件:
- 宣告物件前加
const
稱該物件為常物件。 - 常物件只能呼叫常函式。
示例:
class human{
public:
human(){}//新建一個無參建構函式,為了建立常物件
void func() const{
//age=18; //由於成員函式末尾加了const,所以函式體內不允許修改成員變數
height=180; //由於成員變數前加了mutable關鍵字,所以該變數可以在函式中修改
}
void func2(){}
int age;
mutable int height;
};
int main()
{
human maicss;
const human maicss2;
//maicss2.func2(); //由於是常物件,所以只能呼叫常函式。也只能修改帶有mutable關鍵字的成員變數
maicss.func();
return 0;
}
12.4 友元
-
作用:讓一個函式或類,訪問另一個類中的私有成員。
-
關鍵字:
friend
-
三種實現方式:
- 全域性函式作友元
- 類作友元
- 成員函式作友元
-
示例:
class room; //宣告類 class goodgay2{ public: goodgay2(); void visit(); room * m_room; //建立一個指標 }; class goodgay{ public: goodgay(); //宣告建構函式 void visit(); //宣告成員函式用於訪問room的私有成員 room * m_room; //建立一個指標 }; class room{ friend void text(); //將全域性函式作為友元 friend class goodgay; //將另一個類作為友元 friend void goodgay2::visit(); public: string sittingroom="客廳"; private: string bedroom="臥室"; }; goodgay::goodgay(){ //類外定義建構函式 m_room=new room; //在建構函式中於堆區建立一個物件 } goodgay2::goodgay2(){ m_room=new room; } void goodgay::visit(){ //類外定義成員函式 cout<<"b在訪問:"<<m_room->bedroom<<endl; cout<<"b在訪問:"<<m_room->sittingroom<<endl;//訪問room的私有成員 }; void goodgay2::visit(){ cout<<"c在訪問:"<<m_room->bedroom<<endl;//訪問room的私有成員 } void text(){ room a; cout<<"a訪問了:"<<a.bedroom<<endl; goodgay b; b.visit(); //通過訪問visit成員函式訪問room的私有成員 goodgay2 c; c.visit(); } int main() { text(); return 0; }
12.5 運算子的過載
12.5.1 加號運算子的過載
-
方式:
- 使用成員函式過載
- 使用全域性函式過載
-
示例:
//使用成員函式過載 class Person{ public: int age; int height; public: Person operator+(Person &p); //使用成員函式對加號的過載 }; Person Person::operator+(Person &p){//定義過載函式 Person temp; temp.age=this->age+p.age; temp.height=this->height+p.height; return temp; } int main(){ Person p1; Person p2; p1.age=10; p2.age=18; p1.height=159; p2.height=180; Person p3=p1+p2; cout<<"P3的年齡為:"<<p3.age<<" P3的身高為:"<<p3.height<<endl; return 0; }
//使用全域性函式過載 class Person{ public: int age; int height; }; Person operator+(Person &p1,Person &p2){ //使用成員函式對加號的過載 Person temp; temp.age=p1.age+p2.age; temp.height=p1.height+p2.height; return temp; } int main(){ Person p1; Person p2; p1.age=10; p2.age=18; p1.height=159; p2.height=180; Person p3=p1+p2; cout<<"P3的年齡為:"<<p3.age<<" P3的身高為:"<<p3.height<<endl; return 0; }
12.6 繼承
繼承使物件導向三大特性之一
定義某些了類時,下一級別的成員擁有上一級別的共性,還有自己的特性。
使用繼承可以儘量減少程式碼
-
用法:
class A : public B;
-
說明:上述A為子類(派生類),B為父類(基類)。
-
示例:
class base{ //建立一個基類 public: int age; string name; }; class human : public base{ //建立一個以base為基類的派生類 public: int score; }; class dog : public base{//另一個以base為基類的派生類 public: human master; }; void test1(){ //對派生類中屬性的訪問示例 human maicss; dog dazhuang; dazhuang.age=4; maicss.age=20; dazhuang.name="DAZ"; maicss.name="Maicss"; dazhuang.master=maicss; maicss.score=100; } int main() { void test1(); return 0; }
-
注意:
- 經過測試,若定義基類時關鍵字改為private,那麼所繼承的所有屬性全為私有屬性;若為public,則正常繼承。
(這是依我自己理解的)
- 被定義為
protected
的成員變數為保護許可權,此時子類可以訪問這種成員變數,但是如果是private
則無法訪問,這也是兩者的唯一區別。
- 經過測試,若定義基類時關鍵字改為private,那麼所繼承的所有屬性全為私有屬性;若為public,則正常繼承。
13. 檔案操作
使用檔案操作需要包含標頭檔案<fstream>
檔案型別分為兩種:
- 以ASCII碼形式儲存的文字資料。
- 二進位制檔案形式儲存的,使用者一般讀不懂。
操作檔案三大類:
ofstream
寫檔案ifstream
讀檔案fstream
讀寫檔案
13.1文字檔案
13.1.1寫檔案的基本操作
寫檔案的基本步驟:
//1.包含標頭檔案
#include <fstream>
//2.建立流物件
ofstream ofs;
//3.開啟檔案
ofs.open("檔案路徑",開啟方式);
//4.寫資料
ofs<<"文字檔案";
//5.關閉檔案
ofs.close();
開啟方式 | 解釋 |
---|---|
ios::in | 為讀檔案而開啟檔案 |
ios::out | 為寫檔案而開啟檔案 |
ios::ate | 初始位置:檔案尾 |
ios::app | 追加方式寫檔案 |
ios::trunc | 如果檔案存在,先刪除再建立 |
ios::binary | 二進位制方式 |
檔案開啟方式配合使用需要|
符號
示例:
#include <iostream>
#include <fstream> //包含檔案流標頭檔案
using namespace std;
int main()
{
std::ofstream ofs; //建立一個ofstream類物件,實現寫檔案
ofs.open("text.txt",ios::out); //開啟檔案
ofs<<"你好世界"; //寫到檔案
return 0;
}
13.1.2讀檔案的基本操作
寫檔案的基本步驟:
//包含標頭檔案
#include <fstream>
//建立流物件
std::ifstream ifs;
//開啟檔案
ifs.open("檔案路徑",開啟方式);
if (!ifs.is_open()){
cout<<"檔案開啟失敗"<<endl;
return ;
}
//讀入檔案
//第一種方式
char text1[1024]={0};
while (ifs>>text1) {
cout<<text1<<endl;
}
//第二種方式
char text2[1024]={0};
while (ifs.getline(text2,sizeof(text2))){
cout<<text2<<endl;
}
//第三種方式
string text3;
while (getline(ifs,text3)) {
cout<<text3<<endl;
}
//第四種方式
char text4;
while ((text4=ifs.get())!=EOF){
cout<<text4;
}
//關閉檔案
close
14. C++中的STL
STL是為了提高軟體程式碼的複用性而產生的一種標準模板庫
14.1 STL的基本概念
- STL(Standard Template Library,標準模板庫)
- STL從廣義上分為:容器(container)、演算法(algorithm)、迭代器(iterator)
- 容器和演算法之間通過迭代器無縫連線。
- STL幾乎所有程式碼都採用了模板類或模板函式。
14.2 vector容器的基本使用
-
容器:
vector
-
演算法:
for_each
-
迭代器:
vector<int>::iterator
-
示例:
#include <iostream> using namespace std; #include <vector>//使用容器必須引入標頭檔案 void print(int i) {//第三種遍歷方法要用到 cout << i << endl; } int main() { vector<int> v; v.push_back(1);//使用尾插新增元素 v.push_back(2); v.push_back(3); v.push_back(4); //遍歷容器的第一種方法 vector<int>::iterator head = v.begin();//begin()會返回指向容器中第一個元素的指標 vector<int>::iterator tail = v.end();//end()會返回指向容器中最後一個元素的下一個位置的指標 while (head != tail) { cout << *head << endl; head++; } //遍歷容器的第二種方法(是第一種方式的簡化) for (vector<int>::iterator h = v.begin(); h != v.end(); h++) { cout << *h << endl; } //遍歷容器的第三種方法(使用標準演算法庫中的for_each) for_each(v.begin(),v.end(),print); getchar(); return 0; }
14.3 string容器的基操
string
和char *
的區別- 本質上兩者區別不大,前者是後者的封裝,可以管理字串。
- 建構函式
string();
無參構造,建立一個空的字串。string(const char* s);
使用字串s進行初始化。string(const string& str);
使用字串str初始化。string(int n,char c);
使用n個字元c初始化。
# 其他內容
隨機數生成
- rand()函式
- 用法:
rand()%10
可以生成0~9的隨機數。 - 置隨機數種子:
srand((unsigned int)time(NULL))
(需要#include <ctime>
)
- 用法:
記憶體
-
獲取記憶體地址
- 陣列的首地址可以直接使用陣列的名字。
- 或者使用取址符“&”。
-
注意:
- 0~255之間的記憶體是無法訪問的。
靜態變數
- 在普通變數前加
static
為靜態變數。 - 靜態變數儲存在記憶體的全域性區中。