程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C++學習筆記

C++學習筆記

編輯:關於C++

A.函數是具有用途的自包含的代碼塊。函數名既是函數的標識,用來在程序中調用函數。如果函數名不在名稱空間中定義,它就是全局的,否則就要用名稱空間的名稱來限定他。

B.函數的主要優點之一是根據需要可以在程序的不同位置執行任意次。如果不能將代碼塊封裝到函數中,則程序將最終成為龐然大物,因為那樣通常需要再程序的不同位置復制相同的代碼。使用函數還可以將程序分為易於管理的代碼塊,以方便開發和測試,復雜的大型程序如果包含幾個小代碼塊,就比編寫為一個大代碼塊更容易理解和測試。

C.函數頭

int num(double a,int b);

本行由三部分組成:

a.返回值的類型(本例中int)

b.函數名(本例中num)

c.圓括號中的函數形參(本例中是a和b,分別為double和int類型)

注意:函數頭末尾和函數體右大括號後面都不需要分號。如果函數沒有返回值,則由void來指定返回類型。(void myNum(int a));

 

簡單介紹完函數,下面其實是好幾個例子組成的:

下面這是main主函數和一些要調用函數的聲明:

#include "stdafx.h"

using std::cin;
using std::cout;
using std::endl;
//1.值傳遞(pass by value )
int _value(int a,int b);
//2.地址傳遞(pass by pointer)
int _pointer(int* a);
//3.引用傳遞(pass by reference)
int _reference(int &a,int &b);
//4.函數返回指針
int*  _rpointer(int a,int b);
//5.函數中的靜態變量
int _countNum(int a,int b);
//6.遞歸函數調用
int _chengNum(int n);
int _tmain(int argc, _TCHAR* argv[])
{
    int a{ 5 };
    int b{ 5 };
    int _vNum{};
    int* _pNum{&a};
    int _rNum{};

    int* _pRNum{};
    int _cNum{};
    //1.值傳遞
    printf("調用傳值前:a=%d,b=%d,vNum=%d\n", a, b, _vNum);
    _vNum = _value(a, b);
    printf("傳值後:a=%d,b=%d,vNum=%d\n", a, b, _vNum);
    //2.地址傳遞
    printf("調用傳地址前:a=%d,*_pNum=%d\n", a, *_pNum);
    *_pNum = _pointer(&a);
    printf("傳地址後:a=%d,*_pNum=%d\n", a, *_pNum);
    //3.引用傳遞
    printf("調用傳引用前:a=%d,b=%d,_rNum=%d\n", a, b, _rNum);
    _rNum = _reference(a, b);
    printf("傳引用後:a=%d,b=%d,_rNum=%d\n", a, b, _rNum);

    //4.函數返回指針
    _pRNum = _rpointer(a,b);
    cout << "_pRnum = " << *_pRNum << endl;

    delete _pRNum;                       //釋放掉內存
    _pRNum = nullptr;

    //5.函數中的靜態變量
    _vNum = _countNum(a, b);
    _vNum = _countNum(a, b);
    _vNum = _countNum(a, b);
    _vNum = _countNum(a, b);

    //6.遞歸
    int c{ 5 };
    _cNum = _chengNum(c);
    cout << c << "的階乘是:" << _cNum << endl;

    system("pause");
    return 0;
}

實現被調用的函數

1.給函數傳遞實參:

int _value(int a, int b)
{
    a += 5;        //改變形參a的值
    b += 5;        //改變形參b的值
    return a + b;
}

2.地址傳遞

當使用指針作為實參時,按值傳遞機制仍然像以前一樣工作。但指針是另一個變量的地址,如果創建該地址的副本,則副本仍然指向相同的變量。以指針作為形參可以使函數處理調用者實參。

int _pointer(int* a)
{
    //return &a;
    *a += 5;       //改變指針指向的地址
    return *a;
}

3.引用傳遞

給函數傳遞實參的第二種方法:形參其實是引用被傳遞實參的別名,該機制不再復制所提供的實參。允許函數直接訪問調用函數中的實參。

當使用類類型對象時,對函數使用引用形參具有特殊的意義。對象可能會很大,很復雜,此時復制過程中,可能會耗費很多時間。在這樣的情況下,使用引用形參可以大大加快代碼的執行速度。

可以給函數的形參使用const修飾符,以告訴編譯器我們不想以任何方式修改這個形參。

int _reference(int &a, int &b)
{
    a += 5;        //改變形參a的值
    b += 5;        //改變形參b的值
    return a + b;
}

4.函數返回指針

返回地址的規則:永遠不要從函數中返回局部自動變量的地址。

這樣做很危險的,因為:函數_rpointer(a,b)中的變量num是在該函數開始執行時創建的,並在該函數退出時被銷毀,因此指針ptr指向的內存不在包含原來的變量值。先前分配給num的內存現在可能用於其他目的。

改正:我們的意圖是返回指向某些有用數據的指針,以便最終能夠返回多想數據。一種方法是動態分配內存。使用操作符new,可以在空閒存儲器中創建一個新變量,該變量一直存在,知道最終被delete銷毀,或者知道程序結束。

注意:動態分配內存時,每次調用該函數時都要多分配一些內存。當然不需要內存時,主調程序需要將其刪除,但實踐中

人們很容易忘記這麼做,結果就是空閒存儲器的內存被逐漸消耗,知道某個時刻內存用盡且程序失敗。這類問題稱為內存洩漏。

int* _rpointer(int a, int b)
{
    //int num = a + b;
    //num += 10;

    //改正後
    int* num{ new int{} };
    *num = a + b;
    *num += 10;
    return num;
}

5.函數中的靜態變量

有些時候用自動變量不能完成的。例如不能計算調用函數的次數,因為無法再多次調用中累積數值。有多重方法可以解決該問題。例如,可以使用引用形參來更新調用程序中的計數器,但如果程序中的許多不同位置都調用該函數,這種方法將無濟於事。還可以使用在函數中遞增的全局變量,但這樣做是有風險的,因為程序中任何位置都可以訪問全局變量,他們非常容易被以外修改。在具有多個訪問全局變量的執行線程的應用程序中,全局變量同樣是危險的,因此必須特別注意管理從不同線程中訪問全局變量的方式。當多個線程都可以訪問某個全局變量時,必須處理的基本問題:一個線程使用全局變量時,另一個線程可以修改該變量的值。在這樣的情況下,最好的解決方案是完全避免使用全局變量。

函數內靜態變量的初始化僅僅發生在第一次調用該函數的時候。事實上,初次調用函數時該變量包含的任何值都可以在下次調用時使用。

關於Static關鍵字

a.靜態變量,分配在靜態存儲區,在數據段中。函數退出之後,變量值不變。

b.作用域,全局的靜態變量、靜態函數只能在本文件中使用。(不同於一般全局變量)

局部的靜態變量同函數的局部變量

注:局部靜態變量占用內存時間較長,並且可讀性差,因此,除非必要,盡量避免使用局部靜態變量。

作用:

a、非靜態全局變量的作用域是整個源程序 ,當一個源程序由多個源文件組成時,非靜態的全局變量在各個源文件中都是有效的。

b、靜態全局變量則限制了其作用域, 即只在定義該變量的源文件 內有效,在同一源程序的其它源文件(即聲明了該變量的CPP文件, 或包含該變量聲明頭文件的CPP文件)中不能使用它。

在C++中,內存分成5個區,他們分別是堆、棧、自由存儲區、全局 / 靜態存儲區和常量存儲區。

int _countNum(int a, int b)
{
    a += 5;
    b += 5;
    static int countNum{};
    countNum++;
    cout << "調用次數:"<

6.遞歸函數 遞歸函數調用:當函數包含自身的調用時,稱之為遞歸函數。遞歸的函數調用也可以是間接的,即函數fun1 調用函數fun2,後者再調用fun1。 遞歸可以看做實現無窮循環的一種方法,如果我們不小心,就會發生這種情況。無窮循環將鎖住計算機,需要按Ctrl+Alt+Del組合鍵才能終止程序,這永遠是件非常令人討厭的事情。避免無窮循環的前提是函數包含某種使遞歸調用過程停止的方法。 在物理和數學方面,有許多問題可以被視為包含遞歸。整數的階乘就是個簡單的例子。對於給定的整數N來說,其階乘就是乘積1*2*3*。。。*N

注意:除非遇到的問題特別適用於使用遞歸函數,或者沒有明顯的替代方法,否則使用其他方法一般(如循環)會更好。使用循環比使用遞歸的函數調用的效率更高。在深度適中的遞歸調用中,系統開銷也可以大大超過使用循環時的開銷。當然這樣說的意思不是我們永遠不應該使用遞歸。當問題適於用遞歸函數調用來解決時,遞歸就是非常強大的技術可以大大簡化代碼。

int _chengNum(int n)
{
    static int countNum{n};                           //聲明一個靜態變量;
    countNum *= (n - 1);
    cout << countNum << endl;
    if (n > 2)
        return _chengNum(n - 1);
    else
    {
        return countNum;
    }
}
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved