指標作函式引數,引用作函式引數以及記憶體釋放

2021-06-11 13:42:28 字數 3055 閱讀 2277

指標作為函式引數

1.  函式引數概念:

形參:被調函式中的引數

實參:主調函式中的引數

形參和實參:

c 中函式中實參和形參是按值傳遞的,呼叫函式後,會將實參的值拷貝給形參(即形參和實參之間是沒有關係的,只是它們的值是相同的)。在被調函式中不可以改變實參的值,同樣形參定義在被調函式中,在整個函式體內都可以使用, 離開該函式則不能使用。

(1) 形參變數只有在被呼叫時才分配記憶體單元,在呼叫結束時, 即刻釋放所分配的記憶體單元。

(2) 在進行函式呼叫時,實參都必須具有確定的值,以便把這些值傳送給形參。

(3) 實參可以是常量、變數、表示式、函式等, 無論實參是何種型別的量。

(4) 實參和形參在數量上,型別上,順序上應嚴格一致, 否則會發生「型別不匹配」的錯誤。

2.  指標作函式引數使用 

實際程式設計中,經常要改動傳入引數

的值。這時,我們需要使用指標作為實參,用指標作為引數

,即傳入的是引數的位址而不是引數本身,形參中拷貝的也是記憶體位址,當對形參去(*)運算時,就可以得到指標實參所指向的值,改變該位址就可以直接改變實參所指向的值。

c中函式的變數是區域性變數,也就是說主用函式與被呼叫函式的實參和形參在記憶體中占用的是不同的儲存空間,但它們記憶體空間中的值是相同的。當指標作為函式引數時,它們的記憶體空間中即儲存著相同的記憶體位址(指向另一塊記憶體空間),所以取(*)運算之後,它們的值是相同的,並且是同一塊位址中的值。

這也就是我們在實際程式設計中會看見某些c函式會用到char ***的原因(一般程式設計,char** 已經夠用了),它只是把想把char** 傳入函式中,賦值之後返回。

main()

myfun(int *p)

在上面簡單的程式中&i則是i的位址,傳入被調函式後,指標p所指向的記憶體位址即i的位址,(*p)則就是i,所以函式執行後i也會變成2。並且這裡i是編譯器自動對其進行了初始化,並分配了記憶體,所以&i是有值的(實參必須有確定的值)。

3. 引用概念

定義引用使用&符號。引用只在c++中可以使用,c中沒有引用的概念。

引用等於是物件的另乙個名字,與原物件一模一樣,並都指向同一塊記憶體位址。

int a = 5;

int & b = a;

這裡定義了引用b,它就是a的乙個別名,那麼a=6和b=6效果是一樣的。

定義引用時應注意:

1).  定義引用是必須給它初始化,並且不能初始化null,int &b;這樣的定義是不正確的。

2).  引用並不是物件的拷貝,也不是指標。

3).  &這裡並不是取位址,它只是代表引用。

4).   引用不是一種資料型別,所以沒有引用的引用,沒有引用的指標。

4. 引用作函式引數

實際程式設計中,要經常要改動傳入引數的值,除了使用指標,還可以使用引用。這時,我們需要使用變數或類對作為實參,用引用作為形參,則形參和實參就是一樣的。改變形參後,實參的值也會改變。

主調函式: 

void main(void)

被調函式:

void fun(string & ref_str)

在fun函式中改變形參的話,實參也會跟著改變。
5. 記憶體概念
在c++中,記憶體分成5個區,他們分別是堆、棧、自由儲存區、全域性/靜態儲存區和常量儲存區.
棧,就是那些由編譯器在需要的時候分配,在不需要的時候自動清除的變數的儲存區。裡面的變數通常是區域性變數、函式引數等。

堆,就是那些由new分配的記憶體塊,他們的釋放編譯器不去管,由我們的應用程式去控制,一般乙個new就要對應乙個delete。如果程式設計師沒有釋放掉,那麼在程式結束後,作業系統會自動**。在源程式裡,堆裡的變數等都是沒有名字的,它們是通過指標被訪問的。在堆區里生成變數的過程稱為動態記憶體分配。

自由儲存區,就是那些由malloc等分配的記憶體塊,他和堆是十分相似的,不過它是用free來結束自己的生命的。

全域性/靜態儲存區,全域性變數和靜態變數被分配到同一塊記憶體中,在以前的c語言中,全域性變數又分為初始化的和未初始化的,在c++裡面沒有這個區分了,他們共同占用同一塊記憶體區。

常量儲存區,這是一塊比較特殊的儲存區,他們裡面存放的是常量,不允許修改(當然,你要通過非正當手段也可以修改,而且方法很多)。

記憶體洩漏,用動態儲存(new,malloc)分配函式動態開闢的空間,在使用完畢後未釋放,結果導致一直佔據該記憶體單元。直到程式結束。即所謂記憶體洩漏。如果程式一直執行,則長時間之後,會記憶體耗盡,發生宕機等現象。

6. 記憶體釋放

在棧中的變數所佔記憶體會自動釋放,就像第二節中的區域性變數i,由編譯器自動進行了初始化,並分配了記憶體空間以存放 i 的值,在main函式結束時,變數i會自動釋放其在棧記憶體中所佔的空間。棧中記憶體由編譯器自己控制,程式設計師可以不用管它,只管定義和使用即可。

但是new出來的記憶體空間儲存在堆記憶體空間中,它們則不會自動釋放。例如,如果是int *a = new int,(*a)是動態分配的記憶體單元,a是指向該記憶體單元的指標,則函式執行完成後,(*a)所佔的記憶體空間則不會自動釋放,如果要釋放該記憶體空間,必須使用

delete a,否則會出現記憶體洩露。 而int a;就不存在這種問題,程式會自動**記憶體的。所以堆中記憶體由程式設計師來控制,在用new初始化記憶體空間後,需要考慮在什麼時候去釋放它。

malloc分配的記憶體則需要由free();來釋放記憶體空間。

另外,需要注意的是 delete(&),引數是乙個位址。假如有個指標p,delete(p)釋放的是p所指向的記憶體,p指標並沒有釋放,p指標這時是個野指標;但p還是指向那個位址,如果那塊記憶體被其他程式使用了,再用*p來修改其內容,這樣對程式來說是非常危險的事,所以我們在delete刪除指標所指向記憶體後,會加上p = null; 使指標指向為空。

int *p = new int;

.....

.....

delete p;

p = null;

再需要注意的乙個地方,delete p;實際上只是將p所指向的記憶體空間標記為可使用,讓其他程式去使用該記憶體空間,並沒有刪除記憶體空間中所儲存的資料,在該記憶體被其他程式使用之前 (*p)還是原來的值

指標用作函式的引數

函式的引數不僅可以是整形,字元型,實型也可以是指標型別。它的作用就是把乙個變數的位址傳送到乙個函式中。include void change int i,int p main int argc,char argv 執行結果 我們發現,a的值仍然是10,而b的值變成11了。為什麼?在以前的博文我們談到...

指標和引用作為函式傳遞引數

引用傳遞 void outputnumber int nnumber 設定引用型別引數 intmain intargc,char argv 指標傳遞 void outputnumber int pnumber 使用指標作為函式引數 intmain intargc,char argv 輸出結果是一樣的...

C 引用作為函式引數

有了變數名,為什麼還需要乙個別名呢?c 之所以增加引用型別,主要是把它作為函式引數,以擴充函式傳遞資料的功能。到目前為止我們介紹過函式引數傳遞的兩種情況。1 將變數名作為實參和形參 這時傳給形參的是變數的值,傳遞是單向的。如果在執行函式期間形參的值發生變化,並不傳回給實參。因為在呼叫函式時,形參和實...