指針變量的初始化,C語言指針變量初始化詳解

原文鏈接,優(yōu)秀

本節(jié)來解決如何給一個指針變量初始化。即怎樣使一個指針變量指向另一個變量椎麦。

前面章節(jié)中的某些程序?qū)嶋H上已經(jīng)使用了,即可以用賦值語句使一個指針變量得到另一個變量的地址材彪,從而使它指向該變量观挎。比如:

inti,*j;

j=&i;

這樣就將變量 i 的地址放到了指針變量 j 中,通過 i 的地址段化,j 就能找到 i 中的數(shù)據(jù)嘁捷,所以 j 就“指向”了變量 i。其中 & 是“取地址運算符”显熏,與 scanf 中的 & 是一樣的概念雄嚣;* 為“指針運算符”,功能是取其內(nèi)部所存變量地址所指向變量中的內(nèi)容喘蟆。因為 j 是定義成指針型變量缓升,所以 j 中只能存放變量的地址,所以變量i前一定要加 &蕴轨。需要注意的是港谊,指針變量中只能存放地址,不要將一個整數(shù)或任何其他非地址類型的數(shù)據(jù)賦給一個指針變量橙弱。

此外歧寺,還有兩點需要注意:

j 不是 i,i 也不是 j棘脐。修改j的值不會影響i的值斜筐,修改 i 的值也不會影響 j 的值。j 是變量 i 的地址蛀缝,而 i 是變量 i 里面的數(shù)據(jù)奴艾。一個是“內(nèi)存單元的地址”,另一個是“內(nèi)存單元的內(nèi)容”内斯。

定義指針變量時的“*j”和程序中用到的“*j”含義不同蕴潦。定義指針變量時的“*j”只是一個聲明,此時的“*”僅表示該變量是一個指針變量俘闯,并沒有其他含義潭苞。而且此時該指針變量并未指向任何一個變量,至于具體指向哪個變量要在程序中指定真朗,即給指針變量初始化此疹。而當(dāng)指定 j 指向變量 i 之后,*j 就完全等同于 i 了,可以相互替換蝗碎。

下面給大家寫一個程序:

# include<stdio.h>

intmain(void)

{

inti=3,*j;//*j表示定義了一個指針變量j

j=&i;

printf("*j = %d\n",*j);//此時*j完全等同于i

printf("j = %d\n",j);//j里面存儲的是變量i的地址

return0;

}

輸出結(jié)果是:

*j = 3

j = 1245052

下面再將上面這個程序修改一下:

# include<stdio.h>

intmain(void)

{

inti=3;

int*j=&i;//*j表示定義了一個指針變量j, 并將變量i的地址賦給它

printf("*j = %d\n",*j);//此時*j完全等同于i

printf("j = %d\n",j);//j里面存儲的是變量i的地址

return0;

}

輸出結(jié)果是:

*j = 3

j = 1245052

這個程序與第一個程序有什么不同湖笨?同樣是將變量 i 的地址賦給指針變量 j,第一個程序是“j=&i蹦骑;”慈省,而第二個程序是“*j=&i;”眠菇。原因是边败,前者是定義指針變量后對它初始化,即先定義后初始化捎废;而后者是定義指針變量時對它進行初始化笑窜,即定義時初始化。通過這個對比我們可以更鮮明地看出定義指針變量時的“*j”和程序中用到的“*j”含義的不同登疗。

那么指針變量和指針變量之間可不可以相互賦值呢排截?我們看看下面這個程序:

# include<stdio.h>

intmain(void)

{

int*i,*j;

intk=3;

i=&k;

j=i;//直接指針變量名之間進行賦值

printf("*j = %d\n",*j);//此時*j完全等同于k

printf("j = %d\n",j);// j里面存儲的是變量k的地址

return0;

}

輸出結(jié)果是:

*j = 3

j = 1245044

可見,可以直接將一個指針變量賦給另一個指針變量辐益,只要將指針變量名賦給另一個指針變量名即可断傲。但是需要注意的是:

這兩個指針變量的基類型一定要相同。

在賦值之前荷腊,賦值運算符“=”右邊的指針變量必須是已經(jīng)初始化過的艳悔。也就是說,切忌將一個沒有初始化的指針變量賦給另一個指針變量女仰。這是非常嚴(yán)重的語法錯誤猜年。

同樣,也可以在定義指針變量時就給它賦初值:

# include<stdio.h>

intmain(void)

{

intk=3;

int*i=&k;

int*j=i;

printf("*j = %d\n",*j);//此時*j完全等同于k

printf("j = %d\n",j);//j里面存儲的是變量k的地址

return0;

}

輸出結(jié)果是:

*j = 3

j = 1245048

注意疾忍,“int*j=i乔外;”千萬不要寫成“int*j=*i;”一罩。因為此時 *i 不是定義指針變量 i杨幼,而是完全等同于變量 k。所以 int 型變量不能賦給 int* 型的變量聂渊。

指針常見錯誤

1) 引用未初始化的指針變量

試圖引用未初始化的指針變量是初學(xué)者最容易犯的錯誤差购。未初始化的指針變量就是“野”指針,它指向的是無效的地址汉嗽。

有些書上說:“如果指針變量不初始化欲逃,那么它可能指向內(nèi)存中的任何一個存儲單元,這樣就會很危險饼暑。如果正好指向存儲著重要數(shù)據(jù)的內(nèi)存單元稳析,而且又不小心向這個內(nèi)存單元中寫入了數(shù)據(jù)洗做,把原來的重要數(shù)據(jù)給覆蓋了,這樣就會導(dǎo)致系統(tǒng)崩潰彰居〕现剑”這種說法是不正確的!如果真是這樣的話就是編譯器的一個嚴(yán)重的 BUG陈惰!

編譯器的設(shè)計人員是不會允許這么大的 BUG 存在的畦徘。那么如果指針變量未初始化,編譯器的設(shè)計人員是如何處理這個問題的呢奴潘?肯定不可能讓它亂指旧烧。以VC++6.0這個編譯器為例影钉,如果指針變量未初始化画髓,那么編譯器會讓它指向一個固定的、不用的地址平委。下面來寫一個程序:

# include<stdio.h>

intmain(void)

{

int*p,*q;

printf("p = %#X\n",p);

printf("q = %#X\n",q);

return0;

}

輸出結(jié)果是:

p = 0XCCCCCCCC

q = 0XCCCCCCCC

可見奈虾,在 VC++6.0 中只要指針變量未初始化,那么編譯器就讓它指向 0XCCCCCCCC 這個內(nèi)存單元廉赔。而且這個內(nèi)存單元是程序所不能訪問的肉微,訪問就會觸發(fā)異常,所以也不怕往里面寫東西蜡塌。

而如果在 VS 2008 這個編譯器中碉纳,程序雖然能編譯通過,但是在運行的時候直接出錯馏艾,它并不會像 VC++6.0 那樣還能輸出所指向的內(nèi)存單元的地址劳曹。

下面來看一個程序:

# include<stdio.h>

intmain(void)

{

inti=3,*j;

*j=i;

return0;

}

程序中,j 是 int* 型的指針變量琅摩。j 中存放的應(yīng)該是內(nèi)存空間的地址铁孵,然后“變量 i 賦給 *j”表示將變量i中的值放到該地址所指向的內(nèi)存空間中。但是現(xiàn)在 j 中并沒有存放一個地址房资,程序中并沒有給它初始化蜕劝,那么它指向的就是 0XCCCCCCCC 這個內(nèi)存單元。這個內(nèi)存單元是不允許訪問的轰异,即不允許往里面寫數(shù)據(jù)岖沛。而把 i 賦給 *j 就是試圖往這個內(nèi)存空間中寫數(shù)據(jù),程序執(zhí)行時就會出錯搭独。但這種錯誤在編譯的時候并不會報錯婴削,只有在執(zhí)行的時候才會出錯,即傳說中的“段錯誤”戳稽。所以馆蠕,一定要確保指針變量在引用之前已經(jīng)被初始化為指向有效的地址期升。

在實際編程中,這種錯誤常見的另一個地方是用 scanf 給指針變量所指向的內(nèi)存單元賦值互躬。我們看看下面這個程序:

# include<stdio.h>

intmain(void)

{

int*i;

scanf("%d",i);

return0;

}

該程序試圖給指針變量 i 所指向的內(nèi)存單元賦值播赁。但現(xiàn)在指針變量 i 并沒有初始化,所以程序執(zhí)行時出錯吼渡。所以同樣容为,在使用 scanf 時必須要先給指針變量 i 初始化。比如像下面這樣寫:

# include<stdio.h>

intmain(void)

{

int*i,j;

i=&j;//先給指針變量i初始化

scanf("%d",i);//i本身就是地址, 所以不用加&

printf("%d\n",*i);

return0;

}

輸出結(jié)果是:

10

10

能不能使用 scanf 給指針變量初始化寺酪?指針變量里面存放的是地址坎背,而內(nèi)存中有數(shù)不清的單元,每個單元都有一個地址寄雀,你知道每個單元的地址嗎得滤?你知道哪些地址是空閑可用的,而哪些地址正存儲著重要數(shù)據(jù)不能用嗎盒犹?不知道的話怎么用scanf給它初始化呢懂更?萬一隨便寫一個地址正好是存儲著非常重要的數(shù)據(jù)的內(nèi)存單元地址,那系統(tǒng)就真的崩潰了急膀!

隨著大家編程能力的不斷提高沮协,慢慢地就會發(fā)現(xiàn),其實編程最重要卓嫂、最核心的就是如何處理內(nèi)存的問題慷暂,如何與內(nèi)存打交道。

2) 往一個存放NULL地址的指針變量里面寫入數(shù)據(jù)

這也是編程中最容易犯的錯誤晨雳,不僅是初學(xué)編程的行瑞,即使是有一些經(jīng)驗的程序員也會不小心犯這個錯誤。我們把前面的程序改一下:

# include<stdio.h>

intmain(void)

{

inti=3;

int*j=NULL;

*j=i;

return0;

}

之前是沒有給指針變量j初始化悍募,現(xiàn)在初始化了蘑辑,但是將它初始化為指向 NULL。NULL 也是一個指針變量坠宴。NULL 指向的是內(nèi)存中地址為 0 的內(nèi)存空間洋魂。以 32 位操作系統(tǒng)為例,內(nèi)存單元地址的范圍為 0x00000000~0xffff ffff喜鼓。其中 0x00000000 就是 NULL 所指向的內(nèi)存單元的地址副砍。但是在操作系統(tǒng)中,該內(nèi)存單元是不可用的庄岖。凡是試圖往該內(nèi)存單元中寫入數(shù)據(jù)的操作都會被視為非法操作豁翎,從而導(dǎo)致程序錯誤。同樣隅忿,這種錯誤在編譯的時候也不會報錯心剥,只有在執(zhí)行的時候才會出錯邦尊。這種錯誤也屬于“段錯誤”。

然而雖然這么寫是錯誤的优烧,但是將一個指針變量初始化為指向 NULL蝉揍,這在實際編程中是經(jīng)常使用的。就跟前面講普通變量在定義時給它初始化為 0 一樣畦娄,指針變量如果在定義時不知道指向哪里就將其初始化為指向 NULL又沾。只是此時要注意的是,在該指針變量指向有效地址之前不要往該地址中寫入數(shù)據(jù)熙卡。也就是說杖刷,該指針變量還要二次賦值。

既然不能往里面寫數(shù)據(jù)驳癌,而且還容易犯錯滑燃,為什么還要這樣給它初始化呢?直接同前面定義普通變量時一樣喂柒,在定義時也不初始化不瓶,等到后面知道該給它賦什么值時再給它賦值不行嗎禾嫉?可以灾杰!但還是建議大家將它初始化為 NULL,就同前面將普通變量在定義時初始化為 0 一樣熙参。這是很好的一種編程習(xí)慣艳吠。

最后關(guān)于 NULL 再補充一點,NULL 是定義在 stdio.h 頭文件中的符號常量孽椰,它表示的值是 0昭娩。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市黍匾,隨后出現(xiàn)的幾起案子栏渺,更是在濱河造成了極大的恐慌,老刑警劉巖锐涯,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件磕诊,死亡現(xiàn)場離奇詭異,居然都是意外死亡纹腌,警方通過查閱死者的電腦和手機霎终,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來升薯,“玉大人莱褒,你說我怎么就攤上這事∠雅” “怎么了广凸?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵阅茶,是天一觀的道長。 經(jīng)常有香客問我谅海,道長目派,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任胁赢,我火速辦了婚禮企蹭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘智末。我一直安慰自己谅摄,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布系馆。 她就那樣靜靜地躺著送漠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪由蘑。 梳的紋絲不亂的頭發(fā)上闽寡,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天,我揣著相機與錄音尼酿,去河邊找鬼爷狈。 笑死,一個胖子當(dāng)著我的面吹牛裳擎,可吹牛的內(nèi)容都是我干的涎永。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼鹿响,長吁一口氣:“原來是場噩夢啊……” “哼羡微!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起惶我,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤妈倔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后绸贡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體盯蝴,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年恃轩,在試婚紗的時候發(fā)現(xiàn)自己被綠了结洼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡叉跛,死狀恐怖松忍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情筷厘,我是刑警寧澤鸣峭,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布宏所,位于F島的核電站,受9級特大地震影響摊溶,放射性物質(zhì)發(fā)生泄漏爬骤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一莫换、第九天 我趴在偏房一處隱蔽的房頂上張望霞玄。 院中可真熱鬧,春花似錦拉岁、人聲如沸坷剧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽惫企。三九已至,卻和暖如春陵叽,著一層夾襖步出監(jiān)牢的瞬間狞尔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工巩掺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留偏序,地道東北人。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓锌半,卻偏偏與公主長得像禽车,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子刊殉,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,500評論 2 359

推薦閱讀更多精彩內(nèi)容