編輯:劉風琛
最初撰寫日期:2020年4月11日下午 最新更新日期:2020年9月20日上午
標注:
- 從筆記開始截止到程式第四章“程式流程結構”,使用Joplin撰寫,其余部分為Typora撰寫,
- 筆記對應課程鏈接為:(https://www.bilibili.com/video/BV1et411b73Z) 作者:黑馬程式員-
- 當前進度為
P107:類和物件
目錄
- 1. 變數
- 2. 常量
- 3. 資料型別
- 3.1 整型
- 3.2 浮點型(小數)
- 3.3 字符型
- 3.4 字串
- 3.5 布爾型別
- 3. 運算子
- 4. 程式流程結構
- 4.1 順序結構
- 4.2 選擇結構
- 4.3 回圈結構
- 4.3.1 while陳述句
- 4.3.2 do...while陳述句
- 4.3.3 for回圈陳述句
- 4.4 跳轉陳述句
- 4.4.1 break陳述句
- 4.4.2 continue陳述句
- 4.4.3 goto陳述句
- 5. 陣列
- 5.1 一維陣列
- 5.2 二維陣列
- 6. 函式
- 6.1函式的定義
- 6.2 函式的呼叫
- 6.3 函式的宣告
- 6.4 函式的分檔案撰寫
- 6.5 函式的默認值
- 6.6 函式的占位引數
- 6.7 函式的多載
- 6.7.1 概述
- 6.7.2 函式多載的細節問題
- 7. 指標
- 7.1 指標的定義
- 7.2 指標的使用
- 7.3 空指標
- 7.4 野指標
- 7.5 const修飾指標
- 7.6 指標和陣列
- 7.7 指標和函式
- # 指標、函式、陣列的搭配示例
- 8. 結構體
- 8.1 定義和使用
- 8.2 結構體陣列
- 8.3 結構體指標
- 8.4 結構體嵌套
- 8.5 將結構體作為函式引數傳遞
- 9. 聯系人管理系統實體
- 10 程式的記憶體模型
- 10.1 記憶體磁區模型
- 10.2 磁區意義
- 10.3 程式運行前
- 10.4 程式運行后
- 11. C++中的參考
- 11.1 參考的基本使用
- 11.2 參考作函式引數
- 11.2 參考作函式的回傳值
- 11.3 常量參考
- 12. 類和物件
- 12.1 封裝
- 12.1.1 封裝的意義
- 12.1.2 訪問權限控制
- 12.1.3 成員屬性私有化
- 12.2 物件的初始化和清理
- 12.2.1 建構式和解構式
- 12.2.2 建構式的分類以及呼叫
- 12.2.3 拷貝建構式的呼叫時機
- 12.2.4 建構式的呼叫規則
- 12.2.5 深拷貝與淺拷貝
- 12.2.6 初始化串列
- 12.2.7 類物件作為類成員
- 12.2.8 靜態成員
- 12.3 C++物件模型和this指標
- 12.3.1 成員變數和成員函式分開儲存
- 12.3.2 this指標概念
- 12.3.3 空指標呼叫成員函式
- 12.3.4 const修飾成員函式
- 12.4 友元
- 12.5 運算子的多載
- 12.5.1 加號運算子的多載
- 12.6 繼承
- 12.1 封裝
- 13. 檔案操作
- 13.1文本檔案
- 13.1.1寫檔案的基本操作
- 13.1.2讀檔案的基本操作
- 13.1文本檔案
- 14. C++中的STL
- 14.1 STL的基本概念
- 14.2 vector容器的基本使用
- 14.3 string容器的基操
- # 其他內容
- 亂數生成
- 記憶體
- 靜態變數
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為靜態變數, - 靜態變數儲存在記憶體的全域區中,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/272419.html
標籤:C++
