c++ 指針總結 函數參數指針調用和堆棧內存的分配原理


c++中的char指針

這個char指針很有意思,char指針通常有兩種初始化形式.一個是使用char數組初始化,一個是使用char變量初始化.

c++當中使用雙引號括起來的字符串起始已經被編譯器初始化為一個const char[]類型的字符串常量.也就是說"hedd"在賦值給其他變量或常量時實際上是將一個已經在內存中分配了地址的const char數組的頭指針賦值給它.如果你使用's'這樣的數字量是不能直接賦值給char指針的,因為's'是一個字符而不是擁有內存的字符變量或常量.這種情況必須使用char變量或者const char在內存中申請內存並初始化為一個字符,然后使用這個變量或常量賦值給cha指針.

使用cout或printf輸出char指針指向的數據

在使用cout或printf輸出char指針時,他們的策略是如果是char指針,則會從指針指向的第一個內存區域開始讀數據,一直向后讀取數據直至獲得了'\0'結尾字符.

所以聽過cout輸出char指針指向的地址是不現實的,必須將char指針搶轉為其他指針,一般我會使用轉化為void指針.這樣轉化之后機會輸出char指針指向的內存塊地址了.

cout和printf只有對字符指針有這樣的獨特判斷,對於其他類型的指針將直接輸出指針所在的地址,而不會去讀該地址的內容,更不會一直讀取下一個地址的內容直至遇到'\0'結尾字符.

從上圖我們就可以發現,cout對char指針使用*取值還是正常的,他只會去所指向的地址內存有的數據.而不會自動讀取下一個地址的內容

從上圖我們可以發現,當使用一個char變量地址給char指針,然后使用cout輸出時,cout會自動讀取char變量后面地址的內容,直至發現一個內容轉化char等於'\0'字符的地址.使用這種方式就存在着越界讀取的情況.

現在我們回頭想象就明白為什么使用cout讀取char i[6]={'h','e','l','l','\0'}和"hello" 以及const char*p="hello"的結果是一樣的了.同時我們也發現,編譯器是允許我們使用"hello"對const char j[6]數組直接賦值的.

這時我們就可以考慮一個事情了,我們是否可以運用這個特性對其他字符進行這樣的賦值而不需要使用數組的單個賦值呢?

從上圖我們發現我們是可以將int型地址轉為char 然后通過他賦值char數組的,但是對於其他數組形式我們這里就沒有測試了.

堆和棧內存

我們都知道程序都是有自己的堆和棧內存的,我們使用的變量,常量一般都是放在棧當中,常量和全局變量一般放在全局棧中,而函數的局部變量都放置在函數的局部棧當中.當我們不適用堆內存而只是用棧內存處理函數調用間的數據時,要防止破壞函數的調用棧,如果破壞掉程序將報異常,有時候的異常還是很難定位的.

 

void func(char * msg_)

 當func被調用時,他的參數是一個指針,這個指針指向的是這個函數之外的地址,雖然這個指針是局部作用域中的,因此很有必要在使用時將這個指針指向的內容復制到一個局部變量中.在多線程時很可能會因為外部指針的實效而出現指向無用指針的情況.如果不使用這種方式的另一種方式就是使用堆,因為堆的內存不會被自動釋放掉.->因此在多線程等環境中,參數為指針的,雖然講數據的指針傳過來,但是並不代表着這個指針一致有效,應該在傳入時將指針所指向的數據備份在局部變量中.

void func2(char & msg_)

  這個傳進來的是一個char變量,嚴格上將是傳遞一個指針,只是msg_變量是實參的引用.他指向的了char類型的變量.因為參數里的類型是char而不是char* ,雖然進來的是同樣的地址但是參數規定了他是一個char變量而不是一個char數組.所以還是需要使用char* 來傳遞字符串.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM