當初自學C++時的筆記記錄
編輯:劉風琛
最初編寫日期:2020年4月11日下午 最新更新日期:2020年9月20日上午
標註:
- 從筆記開始截止到程式第四章「程式流程結構」,使用Joplin編寫,其餘部分為Typora編寫。
- 筆記對應課程鏈接為:(//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為靜態變數。 - 靜態變數儲存在記憶體的全局區中。


