當初自學C++時的筆記記錄

編輯:劉風琛css

最初編寫日期:2020年4月11日下午 最新更新日期:2020年9月20日上午ios

標註:c++

  • 從筆記開始截止到程序第四章「程序流程結構」,使用Joplin編寫,其他部分爲Typora編寫。
  • 筆記對應課程連接爲:(https://www.bilibili.com/video/BV1et411b73Z) 做者:黑馬程序員-
  • 當前進度爲P107:類和對象

目錄

1. 變量

給一段內存起名,方便使用。程序員

2. 常量

用於記錄程序中不可更改的數據。算法

  • 定義常量的兩種方式
    1. #define宏常量 #define 常量名 常量值
      • 一般在文件上方定義,表示一個常量。
    2. const修飾的變量 const 數據類型 常量名=常量值
      • 一般在變量定義前加const,修飾該變量爲常量,不可更改。`

3. 數據類型

sizeof()能夠返回當前數據類型所佔內存大小。編程

  • 強制轉換
    語法:(數據類型)被轉變量
    舉例:windows

    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++中能夠用如下方式表示整型,區別在於所佔內存空間不一樣app

數據類型 佔用空間 取值範圍
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;
    }
    • 注意:
      1. 字符串內容要用單引號括起來。
      2. 變量名後必須加中括號表示數組。
  • 當前標準方式:string 變量名 = "abcde"
    示例:

    #include <string>
    int main(){
    	string str = "Hello World!";
    	cout<<str<<endl;
    	return 0;
    }
    • 注意:
      1. 使用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(條件){知足條件執行的代碼塊}

    • 注意:
      1. 注意不要加入多餘的分號。
    • 示例:
    int main(){
    	int score;
    	cout<<"Please input your score:";
    	cin>>score;
    	if (score>=600){
    		cout<<"Good!";
    	}
    	return 0;
    }

    用法二:if(條件){知足條件執行的代碼塊}else{不知足時執行的代碼塊}

    • 注意:
      1. else爲可選分支,刪除後和用法一相同。
      2. 注意不要加入多餘的分號。
    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時執行的代碼塊}
    -。

    1. elseelse if 爲可選分支.
    2. 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;
    }
    • 注意:
      1. 須要使用break跳出分支。
      2. 缺點是沒法使用區間視線分支。

4.3 循環結構

循環執行代碼塊。

4.3.1 while語句

條件知足時不斷循環執行指定代碼塊,不然跳出循環。

  • 用法:while(條件){條件爲真時循環執行的代碼塊}

  • 注意:

    1. 可使用break跳出循環。
  • 示例:

    int main(){
    	int a=0;
    	while(a<10){
    		a++;
    		cout<<a;
    	}
    	return 0;
    }

4.3.2 do...while語句

  • 用法:do{代碼塊}while(條件);

  • 注意:

    1. 基本注意事項和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. 數組

數組就是一個集合,裏邊存放了一組相同類型的數據。

  • 特色
    1. 數組中每一個元素都是相同的數據類型。
    2. 數組是由連續的內存位置組成的。

5.1 一維數組

  • 一維數組的定義方式:

    1. 數據類型 數組名[數組長度];
    2. 數據類型 數組名 [數組長度]={值1,值2,...,值n};
    3. 數據類型 數組名[]={值1,值2,...,值n};
  • 訪問格式:array [0]

  • 注意事項:

    1. 訪問時下標從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;
    }
  • 補充:

    • 數組名的用途:
      1. 能夠統計數組或數組中元素所佔內存空間。(使用sizeof(數組名/數組名[])函數)
      2. 能夠獲取數組在內存中的首地址。(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. 數據類型 數組名 [行數][列數]={{數值1,數值2...},{數值n,數值n+1...}};
    2. 數據類型 數組名 [行數][列數];
    3. 數據類型 數組名 [行數][列數]={數據1,數據2,數據3,數據4};
    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;
      }
  • 二維數組名的用途

    1. 能夠統計數組、數組中一行或數組中元素所佔內存空間。(使用sizeof(數組名/數組名[]/數組名[][])
    2. 能夠獲取數組在內存中的首地址。(cout<<array;
  • 注意:

    1. 爲了程序的可讀性,咱們通常使用前兩種定義方式。
    2. 第三種定義方式會自動分出行列。
    3. 第四種必須指定列數,行數會依據數據數量進行自動分配。

6. 函數

函數就是一個程序塊,能夠方便的進行調用,能很好的減小代碼量,一個較大的程序每每分紅好多模塊,每一個模塊實現特定功能。

6.1函數的定義

  • 函數的定義示例:

    返回值類型 函數名(形參)
    {
        程序代碼塊;
        retuen 返回值表達式;
    }
  • 注意:

    1. 必須返回一個正確的返回值類型。
    2. 若不須要返回值能夠聲明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 函數的分文件編寫

爲了防止單文件形勢下代碼量過大。

  • 要素:

    1. 一個自定義的頭文件(.h)
    2. 源文件(.cpp)
    3. 函數的聲明寫在頭文件中
    4. 函數的定義寫在源文件中
  • 示例:

    • 文件結構:

    • 代碼示例:

      • 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
      • 做用:指針所指的內存地址不可更改,值也不可更改。

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 私有權限 類內能夠訪問,類外不能夠訪問,子不可訪問父的私有內容
  • classstruct的區別:

    • 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字節,由於對象必需要有一個首地址。
  • 做用:

    • 構造函數:主要用在建立對象時給對象的成員屬性賦值,由編譯器自動調用。
    • 析構函數:主要用於對象銷燬前的自動調用,負責清理工做。
  • 語法:

    • 構造函數:類名(){}

      1. 構造函數,沒有返回值,也不用寫void。
      2. 函數名稱和類名相同。
      3. 構造函數能夠有參數,所以能夠發生重載。
      4. 程序在調用對象的時候自動調用構造函數,而且只會調用一次,無需手動調用。
    • 析構函數:~類名(){}

      1. 析構函數,沒有返回值,也不用寫void。
      2. 函數名稱和類名相同,在名稱前加上~
      3. 析構函數不能夠有參數,所以沒法發生重載。
      4. 程序在對象銷燬前自動調用析構函數,而且只會調用一次,無需手動調用。
    1. 手動釋放在堆區申請的空間要用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++編譯器至少給一個類添加三個函數:

  1. 默認構造函數(無參,函數體爲空)
  2. 默認析構函數(無參,函數體爲空)
  3. 默認拷貝構造函數,對其屬性值進行拷貝。

構造函數調用規則:

  • 若是用戶自定義有構造函數,編譯器再也不提供默認無參構造函數,可是會提供默認拷貝構造。
  • 若是用戶定義拷貝構造函數,編譯器再也不提供其餘構造函數。
  • 總結:寫了有參必須寫無參,寫了拷貝就得有參無參都寫上。

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則沒法訪問,這也是二者的惟一區別。

13. 文件操做

使用文件操做須要包含頭文件<fstream>

文件類型分爲兩種:

  1. 以ASCII碼形式儲存的文本數據。
  2. 二進制文件形式儲存的,用戶通常讀不懂。

操做文件三大類:

  1. ofstream 寫文件
  2. ifstream 讀文件
  3. 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容器的基操

  • stringchar *的區別
    • 本質上二者區別不大,前者是後者的封裝,能夠管理字符串。
  • 構造函數
    • 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爲靜態變量。
  • 靜態變量儲存在內存的全局區中。
相關文章
相關標籤/搜索