《轉》C語言指標5分鐘教程

2022-03-10 05:23:33 字數 3944 閱讀 9809

什麼是指標?什麼是記憶體位址?什麼叫做指標的取值?指標是乙個儲存計算機記憶體位址的變數。在這份教程裡「引用」表示計算機記憶體位址。從指標指向的記憶體讀取資料稱作指標的取值。指標可以指向某些具體型別的變數位址,例如int、long和double。指標也可以是void型別、null指標和未初始化指標。本文會對上述所有指標型別進行**。

根據出現的位置不同,操作符*既可以用來宣告乙個指標變數,也可以用作指標的取值。當用在宣告乙個變數時,*表示這裡宣告了乙個指標。其它情況用到*表示指標的取值。

&是位址操作符,用來引用乙個記憶體位址。通過在變數名字前使用&操作符,我們可以得到該變數的記憶體位址。

//

宣告乙個int指標

int *ptr;

//宣告乙個int值

int val = 1;//

為指標分配乙個int值的引用

ptr = &val;

//對指標進行取值,列印儲存在指標位址中的內容

int deref = *ptr;

printf(

"%d\n

", deref);

第2行,我們通過*操作符宣告了乙個int指標。接著我們宣告了乙個int變數並賦值為1。然後我們用int變數的位址初始化我們的int指標。接下來對int指標取值,用變數的記憶體位址初始化int指標。最終,我們列印輸出變數值,內容為1。

第6行的&val是乙個引用。在val變數宣告並初始化記憶體之後,通過在變數名之前使用位址操作符&我們可以直接引用變數的記憶體位址。

第8行,我們再一次使用*操作符來對該指標取值,可直接獲得指標指向的記憶體位址中的資料。由於指標宣告的型別是int,所以取到的值是指標指向的記憶體位址儲存的int值。

這裡可以把指標、引用和值的關係模擬為信封、郵箱位址和房子。乙個指標就好像是乙個信封,我們可以在上面填寫郵寄位址。乙個引用(位址)就像是乙個郵件位址,它是實際的位址。取值就像是位址對應的房子。我們可以把信封上的位址擦掉,寫上另外乙個我們想要的位址,但這個行為對房子沒有任何影響。

乙個指標可以被宣告為void型別,比如void *x。乙個指標可以被賦值為null。乙個指標變數宣告之後但沒有被賦值,叫做未初始化指標。

int *uninit; //

int指標未初始化

int *nullptr = null; //

初始化為null

void *vptr; //

void指標未初始化

int val = 1

;int *iptr;

int *castptr;

//void型別可以儲存任意型別的指標或引用

iptr = &val;

vptr =iptr;

printf(

"iptr=%p, vptr=%p\n

", iptr, vptr);

//通過顯示轉換,我們可以把乙個void指標轉成

//int指標並進行取值

castptr = (int *)vptr;

printf(

"*castptr=%d\n

", *castptr);

//列印null和未初始化指標

printf("

uninit=%p, nullptr=%p\n

", uninit, nullptr);

//不知道你會得到怎樣的返回值,會是隨機的垃圾位址嗎?

//printf("*nullptr=%d\n", nullptr);

//這裡會產生乙個段錯誤

//printf("*nullptr=%d\n", nullptr);

執行上面的**,你會得到類似下面對應不同記憶體位址的輸出。

iptr=0x7fff94b89c6c, vptr=0x7fff94b89c6c

*castptr=1

uninit=0x7fff94b89d50, nullptr=(nil)

第1行我們宣告了乙個未初始化int指標。所有的指標在賦值為null、乙個引用(位址)或者另乙個指標之前都是未被初始化的。第2行我們宣告了乙個null指標。第3行宣告了乙個void指標。第4行到第6行宣告了乙個int值和幾個int指標。

第9行到11行,我們為int指標賦值為乙個引用並把int指標賦值為void指標。void指標可以儲存各種其它指標型別。大多數時候它們被用來儲存資料結構。可以注意到,第11行我們列印了int和void指標的位址。它們現在指向了同樣的記憶體位址。所有的指標都儲存了記憶體位址。它們的型別只在取值時起作用。

第15到16行,我們把void指標轉換為int指標castptr。請注意這裡需要顯示轉換。雖然c語言並不要求顯示地轉換,但這樣會增加**的可讀性。接著我們對castptr指標取值,值為1。

第19行非常有意思,在這裡列印未初始化指標和null指標。值得注意的是,未初始化指標是有記憶體位址的,而且是乙個垃圾位址。不知道這個記憶體位址指向的值是什麼。這就是為什麼不要對未初始化指標取值的原因。最好的情況是你取到的是垃圾位址接下來你需要對程式進行除錯,最壞的情況則會導致程式崩潰。

null指標被初始化為o。null是乙個特殊的位址,用null賦值的指標指向的位址為0而不是隨機的位址。只有當你準備使用這個位址時有效。不要對null位址取值,否則會產生段錯誤。

c語言的陣列表示一段連續的記憶體空間,用來儲存多個特定型別的物件。與之相反,指標用來儲存單個記憶體位址。陣列和指標不是同一種結構因此不可以互相轉換。而陣列變數指向了陣列的第乙個元素的記憶體位址。

乙個陣列變數是乙個常量。即使指標變數指向同樣的位址或者乙個不同的陣列,也不能把指標賦值給陣列變數。也不可以將乙個陣列變數賦值給另乙個陣列。然而,可以把乙個陣列變數賦值給指標,這一點似乎讓人感到費解。把陣列變數賦值給指標時,實際上是把指向陣列第乙個元素的位址賦給指標。

int myarray[4] = ;

int *ptr =myarray;

printf(

"*ptr=%d\n

", *ptr);

//陣列變數是常量,不能做下面的賦值

//myarray = ptr

//myarray = myarray2

//myarray = &myarray2[0]

第1行初始化了乙個int陣列,第2行用陣列變數初始化了乙個int指標。由於陣列變數實際上是第乙個元素的位址,因此我們可以把這個位址賦值給指標。這個賦值與*ptr = &myarray[0]效果相同,顯示地把陣列的第乙個元素位址賦值到了ptr引用。這裡需要注意的是,這裡指標需要和陣列的元素型別保持一致,除非指標型別為void。

就像陣列一樣,指向結構體的指標儲存了結構體第乙個元素的記憶體位址。與陣列指標一樣,結構體的指標必須宣告和結構體型別保持一致,或者宣告為void型別。

?

struct

person ;

struct

person first;

struct person *ptr;

first.age = 21

;char *fullname = "

full name";

first.name =fullname;

ptr = &first;

printf(

"age=%d, name=%s\n

", first.age, ptr->name);

第1至6行宣告了乙個person結構體,乙個變數指向了乙個person結構體和指向person結構體的指標。第8行為age成員賦了乙個int值。第9至10行我們宣告了乙個char指標並賦值給乙個char陣列並賦值給結構體name成員。第11行我們把乙個person結構體引用賦值給結構體變數。

第13行我們列印了結構體例項的age和name。這裡需要注意兩個不同的符號,』.』 和 『->』 。結構體例項可以通過使用 『.』 符號訪問age變數。對於結構體例項的指標,我們可以通過 『->』 符號訪問name變數。也可以同樣通過(*ptr).name來訪問name變數。

希望這份簡短的概述能夠有助於了解不同的指標型別。在後續的博文中我們會**其它型別的指標和高階用法,比如函式指標。

C語言指標 二 3分鐘學會多級指標

首先,我們先以乙個簡單的例子回顧一級指標的知識指標基本介紹 定義 int a 3 計算機給我們開闢了乙個記憶體空間,裡面放入3這個整數,這個記憶體空間的位址是 a 定義指標int p a 計算機給我們開闢了乙個記憶體空間,裡面放入 a,這個記憶體空間的位址是 p 我們可以通過 p來訪問a的值,p的意...

5分鐘搞懂kexec工作原理 轉

什麼是kexec?可從當前正在執行的核心直接跳轉到新核心 為什麼需要kexec?跳過boot階段,減少重啟時間 kexec整體思路如下 1 新的kernel映象和initrd映象連續儲存在記憶體中,initrd的位置記錄在boot params中 2 切換到新核心就是跳轉到新的kernel映象所在記...

Git五分鐘教程

使用git前,需要先建立乙個倉庫 repository 您可以使用乙個已經存在的目錄作為git倉庫或建立乙個空目錄。git initgit init newrepo從現在開始,我們將假設您在git倉庫根目錄下,除非另有說明。我們有乙個倉庫,但什麼也沒有,可以使用add命令新增檔案。git add f...