深度長文教你徹底掌握C C指標 一 基石

2021-07-22 16:26:11 字數 3140 閱讀 3192

深度長文教你徹底掌握c++/c指標(二):指標和陣列與字串

c++或者c裡面最容易讓人糊塗應該是指標了,不管是初學者甚至是有經驗的童鞋有時候在用指標的時候也會出現一些很隱蔽的錯誤.

指標本身就是乙個很繞的概念,而指標又能夠和很多的結構比如陣列(二維陣列),字串,記憶體分配和管理等等一些聯絡起來變成更加繞的概念.所以基礎不好的同學常常會犯一些很無厘頭的錯誤,但是高手也會犯錯誤,而且更加隱蔽.

接下來所有的文章內容並不能夠保證你能夠完完全全避免開發中的錯誤,但是文章的目標是幫助很多童鞋對於指標概念做乙個系統性的歸納.減少犯錯誤的機率.或者是幫助剛剛入門的boy更加快速深入的理解指標,把基礎打得紮實一點.

恩,很多人都說指標很難,那為什麼還要學指標呢?對於這樣的問題,拒絕回答.

我們已經很熟悉一些基本的儲存單位了,比如乙個bit(位)用儲存0或者1.也可以把幾個bit合起來表示更大的數字,比如乙個byte(位元組)就包含了8個bit.這些都是很基礎很簡單的東西.然後我們可以把計算機的記憶體想象成乙個位元組陣列,記憶體中的每乙個位址表示乙個位元組.

每個位元組中都能夠儲存一定位數的內容,因此,每個位元組都能夠通過一些位址來標識.有時候,乙個位元組不夠,怎麼辦呢?那麼就同時用很多個位元組來表示,比如乙個int在我的系統裡面就用了4個位元組。

下面的圖是上面那幅每兩個位元組合併在一起之後樣子.這個因為是兩個位元組合併,所以它成為比乙個位元組更大的記憶體單位(廢話),能夠儲存的資訊就更多(廢話).但是雖然乙個字是兩個位元組合併的,但是它仍然只包含乙個位址,也就是說,合併之後只需要乙個位址來找到合併之後的記憶體.

因此,我們可以得到:

1.記憶體中的每個位置都由乙個獨一無二的位址表示.

2.記憶體中的每個位置都包含乙個值.

通俗一點,我們可以通過乙個位址,來找到記憶體中的某個具體位置,然後訪問到(得到)該位置的值(允許的話).這就是記憶體和位址簡單的思想.

指標這個名字確實折磨過很多人,這個名字是個好名字,同時也是乙個非常不好的名字. 說它好,是因為指標這個東西很形象的體現了它的功能:指標指標,指到某個地方某個位置.非常形象. 它不是個好名字是因為她的名字有時候掩蓋了它的真實含義.一般來說,指標是乙個其值為位址的變數。(就是乙個儲存位址的變數)

所以,要養成一種條件反射,看到指標首先不是想到他能夠指向**,而是想到這個變數存放的是乙個位址,是這個位址指向****.(比如,char型別的變數中存放的是char型別的資料.int變數中存放的是int型別的資料.指標中存放的是乙個位址!!!)

反覆的把上面的概念消化之後,我們就來看兩個基本的運算子:&(取址運算子)*(間接訪問運算子/解引用指標)

首先是&運算子:當它後面跟乙個變數名的時候,給出這個變數名的位址.

#include 

using

namespace

std;

int main()

例子很簡單,就不解釋了.

有乙個非常重要的是,因為null不指向任何地方,所以,也就肯定不能夠解引用了.這點一定要注意.因為連位址都沒有,怎麼得到不存在的位址中的值呢?所以要是想你的程式健壯,最好是在解引用之前加乙個判斷是否為null指標的步驟,要是你有足夠的信心以後都不會有問題,那麼不加也罷.

下面這個例子是當我試圖對乙個null指標解引用之後的程式運**況.(就是上面那個例子加了一句話而已)

#include 

using

namespace

std;

int main()

int main()

講到現在,發現前面很多的錯誤都是由於解引用沒有初始化的指標引起來的.所以,這裡提個建議,就是盡量定義了物件之後再定義指向這個物件的指標,對於不清楚的指向**的指標,一律初始化為nullptr(c++11)或者null(0).之後再判斷是否指向物件再進行相應的操作.

接下來講void*.

void*是一種特殊型別的指標,能夠用來存放任何型別物件的位址.通俗來說,就是我不知道這個指標指向的是什麼型別的物件.

要是還是理解不了那就上例子:

#include 

int fun(int num)

int main()

void *暫時了解到這裡就行了,後面記憶體分配的時候還會專門和他打交道.

指標的指標就是指向指標的指標.再多講就繞暈了.直接看定義和例子吧.

通過這個例子,我們發現其建立方式也是和普通指標的建立方式是差不多的,除了建立時候的兩個星號**.那建立指標必定需要指標型別,指標型別怎麼選擇呢?通俗一點說,就是跟著前面的走:我們發現建立整形時候使用的是int,比如這裡的int a=10;.那我們建立指向a的指標的時候,肯定必須也要是int了,比如這裡的int *p_a=&a;.最後建立指標的指標的時候,也就用int了.比如這裡的int **pp_a=&p_a;.並不困難

另外乙個就是解引用的時候,帶上兩個星號,就回到的最開始的那個變數.這麼說有點模糊.詳細來說,**pp_a因為*的從右向左的結合性,這個表示式可以寫成*(*pp_a),那麼我們知道pp_a存放的是p_a的位址,*pp_a就是表示p_a這個位址中存放的內容即a的位址(不能暈!!!).那麼*(*pp_a)就相當於*p_a或者a.

至此,基本的概念部分就結束啦.

一文教你玩轉git

首先進入乙個目錄之後,使用這個命令是先初始化乙個git倉庫 git init 它會預設建立乙個名為master的分支 下面這個用於檢視是否有修改的檔案,如果有就會報紅 git status 下面這個用於檢視檔案修改的細節 git diff test.txt 下面這個是提交到暫存區 git add t...

一文教你看懂原型!!!

談到原型,我們都知道最重要的兩個屬性就是 proto 和prototype,那麼他們到底有什麼關係又到底是什麼呢,這一篇看完相信你就會有一些理解了。js中萬物皆物件,每個資料都會有乙個 proto 的屬性,這個屬性叫隱式原型。乙個物件 obj 的 隱式原型 proto 指向構造該物件 obj 的 建...

一文教你 Mysql資料備份

按照備份時對資料庫的影響範圍分為 cold backup 冷備 指在資料庫停止的情況下進行備份 offlinebackup 官方手冊稱為離線備份 warm backup 溫備 備份同樣在資料庫執行時進行,但是會對當前資料庫的操作有所影響,例如 加乙個全域性讀鎖以保證備份資料的一致性。按照備份後的檔案...