?? 教學--第19章 指針一 基本概念.htm
字號:
<TD width="6%" rowSpan=2>---<SPAN lang=en-us>></SPAN></TD>
<TD width="23%" bgColor=#000000><FONT color=#ffffff>打開火折,但見</FONT>
<P><FONT color=#ffffff>紙條內容:“XXX街3K號</FONT>”</P></TD>
<TD width="6%" rowSpan=2>---<SPAN lang=en-us>></SPAN></TD>
<TD width="15%" bgColor=#000000><FONT
color=#ffffff>你前往這紙條的神秘地址……</FONT></TD>
<TD width="6%" rowSpan=2>---<SPAN lang=en-us>></SPAN></TD>
<TD width="23%" bgColor=#000000><FONT
color=#ffffff>“XXX街3K號”里住著一千年老妖!你……</FONT></TD></TR>
<TR>
<TD width="21%">程序訪問了一個沒有初始化的指針:
<P><SPAN lang=en-us>int* p;</SPAN></P></TD>
<TD width="23%"><SPAN lang=en-us>p </SPAN>的內存是隨機的一個數,比如:<SPAN
lang=en-us> 0x3FF0073D</SPAN></TD>
<TD width="15%">程序隨即訪問內存地址:
<P><SPAN lang=en-us> 0x3FF0073D</SPAN></P></TD>
<TD width="23%"><SPAN lang=en-us>0x3FF0073D</SPAN>
是哪里的內存?說不定正好是<SPAN lang=en-us>Windows</SPAN>老大要用的內存,你竟敢訪問!
<P><SPAN lang=en-us>Windows</SPAN>一生氣,藍屏。</P></TD></TR></TBODY></TABLE>
<P>
<P>
<P>既然沒有賦值的指針這么危險,下面來看看如何給指針賦值。
<P>
<H4><B><SPAN lang=en-us><A name=19.4.2>19.4.2</A> </SPAN>給指針變量賦值</B></H4>
<P><SPAN lang=en-us></SPAN>
<P><SPAN lang=en-us>(1) int k =
100;</SPAN>
<P><SPAN lang=en-us>(2) int*
p;</SPAN>
<P><SPAN lang=en-us>(3) p =
&k;</SPAN> //p取得變量<SPAN lang=en-us>k</SPAN>的地址 (也稱:p指向k)
<P>
<P>第1行定義一個整型變量k。
<P>第2行定義了一個整型指針p。
<P>而第3行,“指針 p 存儲了變量k的地址”。短的說法是“<SPAN lang=en-us>p</SPAN>指向了<SPAN
lang=en-us>k</SPAN>”。
<P>
<P>執行了上面三行代碼后,結果是: p 指向 k。我們來看具體的內存示意圖。
<P>
<P align=center><IMG height=218 src="教學--第19章 指針一 基本概念.files/ls19.h1.gif"
width=273 border=0>
<P align=center><SPAN lang=en-us>p </SPAN>指向 <SPAN lang=en-us>k </SPAN>示意圖
<P>
<P>上圖中,紅色數字代表什么?紅數字11000002 是 變量 k 的內存地址。
<P>
<P>指針初始化的結果,就是讓它存儲下另一個變量的地址。簡稱指向另一個變量。
<P>
<P>下面說說三種常見的,給指針賦值的操作:
<P>
<P><B>一、用<SPAN lang=en-us> & </SPAN>取得普通變量的地址。</B>
<P>
<P>要想讓指針指向某個普通變量,需要通過<SPAN lang=en-us> & </SPAN>來得到該普通變量的地址。
<P>
<P><SPAN lang=en-us>int k;</SPAN>
<P><SPAN lang=en-us>int* p = &k;</SPAN>
<P>
<P>
<P><B>二、指針之間的賦值。</B>
<P>兩個指針之間也可以相互賦值,此時不需要通過<SPAN lang=en-us> & </SPAN>來取址。
<P>
<P><SPAN lang=en-us>int k;</SPAN>
<P>
<P><SPAN lang=en-us>int* p1</SPAN>
<P><SPAN lang=en-us>int* p2;</SPAN>
<P>
<P><SPAN lang=en-us>p1 = &k;</SPAN> //<SPAN lang=en-us>p1
</SPAN>先指向<SPAN lang=en-us> k</SPAN>
<P><SPAN lang=en-us>p2 = p1; //</SPAN>然后 ,p2 也指向<SPAN lang=en-us>
</SPAN>k。
<P>
<P>注意,<SPAN lang=en-us>p2 = p1</SPAN>的結果是:讓p2也指向“p1所指的內容”,而不是讓p2指向“p1本身”。
<P>上面的情況可以改為直接在定義時就賦值:
<P><SPAN lang=en-us>int k;</SPAN>
<P>
<P><SPAN lang=en-us>int* p1 = &k;</SPAN>
<P><SPAN lang=en-us>int* p2 = p1;</SPAN>
<P>
<P><B>三、讓指針指向數組</B>
<P>數組本身就是地址,所以對數組變量也不用通過 <SPAN lang=en-us>& </SPAN>來取址。
<P>
<P><SPAN lang=en-us>char name[] = "NanYu";</SPAN>
<P><SPAN lang=en-us>char* p = name; //</SPAN>不用取址符<SPAN lang=en-us>
& </SPAN>
<P>
<P>或者:
<P>
<P><SPAN lang=en-us>int arr[3] = {100,99,80};</SPAN>
<P><SPAN lang=en-us>int* p = arr; </SPAN>
<P>
<P><B>四、讓指針指向一個新地址</B>
<P>
<P>前而的賦值方法都是讓指針指向一個已有的內存空間的地址。比如:<SPAN lang=en-us>int* p = &k</SPAN>;
指針變量<SPAN lang=en-us>p</SPAN>
存放的是已有的變量k的地址。其實指針也可以指向一個新開辟的內存空間,這一內存空間不歸屬于其它變量。
<P>
<P>在C++中,常用一個關鍵字:<SPAN lang=en-us><B>new</B> </SPAN>來為指針開辟一段<B>新</B>空間。比如:
<P>
<P><SPAN lang=en-us>int* p = <B>new</B> int;</SPAN>
<P>
<P>現在,指針變量p存儲著一個內存地址,該內存地址確實存在——它是由 <SPAN lang=en-us>new
</SPAN>操作符申請而得。可以這樣認為,<SPAN lang=en-us>new
</SPAN>是一位特權人物,不通過它,指針只能指向已有的“房間”;而使用了它,則可以要求系統為指針“新開辟一片空地,然后建上新房間”。
<P>有特權的人不僅僅是“new”,還有幾個系統定義的函數,及<SPAN
lang=en-us>Windows</SPAN>提供的函數,都可以實現“向系統要空間”的功能。我們將在后面專門的 章節詳細講解。
<P>
<H3><B><A name=19.5>1<SPAN lang=en-us>9</SPAN>.5</A> 地址解析 及其操作符<SPAN
lang=en-us> *</SPAN></B></H3>
<P>
<P><SPAN lang=en-us>*
</SPAN>在C,C++語言里除了起“乘號”的作用以外,前面我們還剛學了它可以在定義變量時,表明某個變量是屬于“指針類型”。現在,則要講到它還能起“地址解析”的作用。
<P>
<P>什么叫“地址解析”?假設有一<SPAN lang=en-us> int </SPAN>類型變量k:
<P>
<P><SPAN lang=en-us>int k = 100;</SPAN>
<P>
<DIV align=center>
<CENTER>
<TABLE id=AutoNumber2
style="BORDER-COLLAPSE: collapse; TEXT-ALIGN: center" borderColor=#111111
cellSpacing=0 cellPadding=0 width="49%" border=0>
<TBODY>
<TR>
<TD width="39%">內存</TD>
<TD width="61%">內存地址</TD></TR>
<TR>
<TD
style="BORDER-RIGHT: #000000 1px solid; BORDER-TOP: #000000 1px solid; BORDER-LEFT: #000000 1px solid; BORDER-BOTTOM: #000000 1px solid"
width="39%"><SPAN lang=en-us>100</SPAN></TD>
<TD width="61%"><SPAN
lang=en-us>11000000</SPAN></TD></TR></TBODY></TABLE></CENTER></DIV>
<P>
<P>方框是變量k所占用的內存。100 是該內存中存放的<B>值</B>。而<SPAN lang=en-us> 11000000</SPAN>
則是該內存的地址。
<P>
<P>“地址解析”就是 <B>地址</B>-<SPAN lang=en-us>></SPAN><B>值</B> 的解釋過程。即:通過地址
<SPAN lang=en-us>11000000 </SPAN>得到位于地址的變量。
<P>可見“地址解析(*)” 和 “取址(<SPAN lang=en-us>&</SPAN>)” 正好是一對相反的操作。
<P>
<P>這好有一比:地址解析符 * 是個郵遞員,他要根據信封上的地址,找到實際的房子。而 取址符 <SPAN lang=en-us>&
</SPAN>則是當初到你家抄下門牌號的人。
<P>
<P>看一下實際應用例子:
<P>
<P><SPAN lang=en-us>int k = 100;</SPAN>
<P><SPAN lang=en-us>int* p = &k;</SPAN>
<P><SPAN lang=en-us>int m = *p;</SPAN>
<P>
<P><SPAN lang=en-us>cout << m << endl;</SPAN>
<P>
<P>執行以上代碼,屏幕上將輸出 100。
<P>實際上也可以這樣寫,以取得相同結果:
<P>
<P><SPAN lang=en-us>int k = 100;</SPAN>
<P><SPAN lang=en-us>int* p = &k;</SPAN>
<P>
<P><SPAN lang=en-us>cout << *p << endl;</SPAN>
<P>
<P>直接輸出<SPAN lang=en-us> *p </SPAN>即可。*p 的值就是<SPAN lang=en-us> 100.</SPAN>
<P>
<P>明白了嗎? <SPAN lang=en-us>p = &k </SPAN>讓p得到k的地址,而 *p 則得到k的值。
<P>下面就考一考你<SPAN lang=en-us> & </SPAN>和<SPAN lang=en-us> *</SPAN> 的作用。
<P>
<P><SPAN lang=en-us>int k = 100;</SPAN>
<P><SPAN lang=en-us>cout << *&k << endl;</SPAN>
<P>
<P>將會輸出什么?
<P>
<P>通過地址解析得到變量,不僅僅可以“得知”該變量的值,還可直接修改該變量的值。
<P>
<P><SPAN lang=en-us>int k = 100;</SPAN>
<P><SPAN lang=en-us>int* p = &k; //p </SPAN>指向k
<P>
<P><SPAN lang=en-us>*p = -100; </SPAN>
<P><SPAN lang=en-us>cout << k << endl;</SPAN>
<P>
<P>屏幕上將輸出 -100。
<P>
<H3><B><SPAN lang=en-us><A name=19.6>19.6</A> </SPAN>上機實驗一
指向普通變量的指針和指針之間的互相賦值</B></H3>
<P>
<P>實驗一有多個步驟。
<P>
<P>第一步、將上面的代碼片段變成程序。請大家打開CB,新建空白控制臺工程,然后輸入以下代碼。
<P>
<P><SPAN lang=en-us>1) int k = 100;</SPAN>
<P><SPAN lang=en-us>2) int* p1 = &k;</SPAN>
<P>
<P><SPAN lang=en-us>3) cout << *p1 << endl;</SPAN>
<P>
<P><SPAN lang=en-us>4) system("PAUSE");</SPAN>
<P>
<P><SPAN lang=en-us>(</SPAN>行前的編號是為下面講課方便,你當然不能將它們輸入到CB中去。<SPAN
lang=en-us>)</SPAN>
<P>
<P>運行將查看結果。然后按任意鍵退出該程序。下面我們要親眼看看,指針變量p1,是否真的存放著普通變量k的地址。
<P>
<P>把斷點設在第<SPAN lang=en-us>2</SPAN>行上。<SPAN
lang=en-us>(</SPAN>輸入光標移到第二行,然后按F5<SPAN lang=en-us>)</SPAN>
<P align=center><IMG height=35 src="教學--第19章 指針一 基本概念.files/ls19.h2.gif"
width=168 border=0>
<P align=center>(設置斷點)
<P>
<P>按F9運行,程序停在斷點上,然后按<SPAN lang=en-us> Ctrl + F7 </SPAN>調出<SPAN
lang=en-us>"Evaluate/Modify"
</SPAN>對話框。該對話框可以在程序運行時觀察或強行修改某個變量的值。我們這里僅是想看看變量 k 的地址。所以如圖輸入 <SPAN
lang=en-us>&k</SPAN> ,回車后,<SPAN
lang=en-us>Result</SPAN>(結果)欄出現:0012FF88。這就是k的地址。
<P>
<P align=center><SPAN lang=en-us><IMG height=279
src="教學--第19章 指針一 基本概念.files/ls19.h2.jpg" width=402 border=0> </SPAN>
<P align=center><SPAN lang=en-us>(&k </SPAN>的值就是<SPAN lang=en-us> k
</SPAN>的內存地址<SPAN lang=en-us>)</SPAN>
<P>
<P>接下來我們該看 p1 的值。看它是否等于<SPAN lang=en-us> 0012FF88</SPAN>。刪除<SPAN
lang=en-us> &k </SPAN>,改為<SPAN lang=en-us>
p</SPAN>1,回車,怎么回事?CB竟然很不配合地顯示p1的值為 00000100
?呵,這是因為當前斷點那一行還沒有運行呢,p1現在的值是隨機的,這驗證好我們前面說的“指向不明”。
<P align=center><IMG height=78 src="教學--第19章 指針一 基本概念.files/ls19.h3.gif"
width=71 border=0>
<P align=center><SPAN lang=en-us>(</SPAN>還沒有初始化的指針p1,隨隨便便指向一個莫名的地址<SPAN
lang=en-us>)</SPAN>
<P align=center>
<P>關掉該對話框,然后按F8再運行一步。再按<SPAN lang=en-us> Ctrl + F7 </SPAN>調出上面窗口,輸入<SPAN
lang=en-us> p1,</SPAN>回車,這回顯示的的值正合我們的推想。
<P align=center><IMG height=132 src="教學--第19章 指針一 基本概念.files/ls19.h4.gif"
width=103 border=0>
<P align=center>(p1 的值,就是<SPAN lang=en-us> k </SPAN>的地址,即:<SPAN
lang=en-us>p1 </SPAN>等于 <SPAN lang=en-us>&k</SPAN>)
<P>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -