---------
指標的詳解
---------
指標的定是
int * a;
b = 1;
a=&b
可以看出來,a這個指標變數存的是b的位址。
可以變形為int *a=&b
*d 表示訪問位置100,並取得裡面的值。
乙個常見的錯誤,int *a ;*a= 12;但是a究竟指向**呢,由於我們沒有對a進行初始化,所以我們沒有辦法**12這個值究竟存在**。如果變數是靜態的
它會被初始化為0,如果是自動的它根本不會被初始化,無論哪種情況,宣告乙個 指向整型的指標都不會建立用於儲存整型的記憶體空間。
所以程式執行這個賦值操作,將會發生什麼呢?如果你運氣好,a的賦值是個非法位址,這樣賦值語句將會出錯
標準定義了空指標,null指標,它作為一種變數特殊的指標變數,表示不指向任何東西,要使乙個指標變數變為null,你可以給他附乙個零值。為了測試乙個指標是否為空
可以將他與零值進行比較,之所以選擇零值是因為一種源**約定,就機器語言而言,null指標的實際值可能與此不同,在這種情況下,編譯器負責將零值和
內部值之間進行轉換。
null指標的概念非常有用,因為他給了你一種方法,表示某個特定的指標目前並未指向任何東西。例如乙個用於在某個陣列中查詢某個特定值的函式可能返回乙個
指向查詢到得陣列元素的指標。如果該陣列不包含指定條件的值,函式就返回乙個null指標,這個技巧允許返回值傳達兩個不同片段的資訊。首先,由沒有
找到元素,其次,如果找到他是哪個元素?
儘管這個技巧在c程式中極為常用,但是他不符合軟體工程的原則。用乙個單一的值表示兩種不同的意思是件非常危險的事情,因為將來可能造成無法弄清哪個才是
真正的意圖。在大型的程式中,這個問題更為嚴重,因為你不可能對整個設計一覽無餘。一種更為安全的策略是讓函式返回兩個獨立的值。首先是個狀態值,
是用於查詢是否成功。其次,是個指標,當狀態值提示查詢成功時,它指向的就是查詢到得值。
對指標進行解引用操作可以獲得它所指向的值,但從定義上看,null指標並未指向任何東西。因此對乙個空指標進行解引用操作是非法的。在對指標進行解引用操作
之前首先要確保它並非null指標。
警告:如果對乙個null指標進行間接訪問會發生什麼情況呢?它的結果因編譯器而異,在有的編譯器中會訪問記憶體的位置零編譯器能夠確保位置零沒有儲存任何
變數,但機器並未妨礙你訪問或修改這個位置。這種行為時非常不幸的。因為程式包含了乙個錯誤,但機器卻隱匿了它的症狀,這樣就使這個錯誤更加難找。
在其他機器上,對null指標進行間接訪問或引發乙個錯誤,並終止程式。宣布這個錯誤比隱藏這個錯誤要好的多,因為程式設計師更容易修改這個錯誤。
如果所有的指標變數(而不僅僅是位於靜態記憶體中的指標變數)能夠自動初始化為null,那是在是件幸事,但事實並非如此。不論你的機器對解引用null
指標這種行為作何反應,對所有的指標變數進行顯示的初始化是種好做法。如果你已經知道指標將被初始化為什麼位址,將他初始化為該位址,否則初始化為null
風格良好的程式會在指標解引用之前對它進行檢查,這種初始化策略可以節省大量的除錯時間
--------指標變數可以作為左值並不是因為他們是指標而是因為他們是變數。對指標變數進行間接訪問表示我們應該訪問指標所指向的位置。間接訪問指定了
乙個特定的記憶體位置,這樣我們可以把間接訪問表示式的結果作為左值使用。
*&a=25:答案是把25賦給a的值。首先&操作符取得a的位址,它是乙個指標變數(注意,使用這個指標變數並不需要知道他的實際值。)。接著,*操作符訪問其運算元所
指向的位址。在這個表示式中,運算元是a的位址,所以值25就儲存於a中。
這條語句和簡單的使用a=25有區別嗎?從功能說是相同的,但是涉及更多的操作,除非編譯器知道你在幹什麼並丟棄額外的操作,否則他所產生的目標**
將會更大、更慢。更糟糕的是,這些額外的操作符會使源**的可讀性變差
------------
指標常量
------------
假定變數a儲存於位置100下面這條語句的作用是什麼?
*100=25
它看上去是把25賦給a因為a是位置100所儲存的變數。但是這是錯誤的。這條語句實際上非法的,因為字面值100的型別是整型,而間接訪問操作只能
作用於指標型別表示式。如果確實想把25存於位置100,你必須使用強制型別轉換。
*(int *)100=25
強制型別轉換把100從整型值強制轉換為指向整型的指標,這樣對它進行間接的訪問就變成合法的了。
----------
指標的指標
-----------
例子int a=12;
int *b=&a;
int **c=&b;
*操作符是從右向左的結核性所以這個表示式相當於*(*c)我們必須從裡向外逐層求值。*c訪問c所指向的位置,我們知道他是變數b。第二個間接訪問操作符
訪問這個位置所指向的位址,也就是變數a
char ch=『q』;
char *cp=&ch;
*cp+1 由於*的優先順序高於+所以先執行間接訪問操作,再執行+
*(cp+1)指標加法運算的結果是個右值,因為他的儲存位置未清晰定義。如果沒有間接訪問操作,這個表示式將不是乙個合法的左值。然而間接訪問跟隨
指標訪問乙個特定的位置。這樣*(cp+1)可以作為左值使用,儘管cp+1本身並不是左值。間接訪問操作符是為少數幾個其結果為左值的操作符之一
------------
算術運算
------------
c指標的運算只限於兩種形式。第一種形式是:指標+-整數
標準定義這種形式只能用於指向陣列中某個元素的指標
第二種型別
指標-指標
只有當兩個指標都指向同乙個陣列中的元素時,才允許指標-指標
----------
關係運算
----------
對指標執行關係運算也是有限制的。
總結計算機記憶體中的每個位置都由乙個位址標識。通常,鄰近的記憶體組合成乙個陣列,這樣就允許儲存更大範圍的值。指標就是它的值表示記憶體位址的變數
指標變數的值並非它所指向的記憶體位置所儲存的值。我們必須使用間接訪問來獲取它所指向位置的值。對於乙個「指向整型的指標」施加間接訪問操作的
結果將是乙個整型值。
宣告乙個指標變數並不會自動分配任何記憶體。在對指標進行間接訪問前,指標必須進行初始化或者使他指向現有的記憶體或者給他分配動態記憶體。對為初始化的
指標變數執行間接訪問操作是非法的,而且這種錯誤常常難以檢測。其結果往往是乙個相關的值被修改。這種錯誤是難被除錯發現的。
除了null指標之外,再也沒有任何內建的記法來表示指標常量。在極少見的情況下我們偶爾需要使用指標常量,這是我們可以通過把乙個整型值強制
轉換為指標型別來建立它。
在指標上可以執行一些有限的算術運算
然而指標只有作用於陣列中其結果才是可**的。對任何並非指向陣列元素的指標執行算數運算是非法的。如果乙個指標減去乙個整數後,運算結果
產生的指標所指向的位置在陣列第乙個元素之前那麼他是非法的。
如果兩個指標在乙個陣列之內是可以進行相減的。
任何指標之間都可以進行比較測試他們相等還是不等。如果兩個指標都指向同乙個陣列中的元素那麼他們之間可以執行=等關係運算,用於判斷他們在
陣列中的相對位置,對兩個不相關的指標執行關係運算,其結果是定義的。
-------------
警告的總結
1.錯誤的對乙個未初始化的指標變數進行解引用
2.錯誤的對乙個null指標進行解引用
3.向函式錯誤的傳遞null指標
4.未檢測到指標表示式的錯誤,從而導致不可預料的結果。
5.對乙個指標進行減法運算,使他非法的指向了陣列第乙個元素的前面得位置
--------------
**********====
提示的總結
**********====
乙個指標應該只有一種意思
如果指標並不指向任何有意義的東西,就把它設定為null.
為什麼char *p=「aaaa」;
printf(「%s\n」,p);正確
printf("%s\n",*p);出現段錯誤
首先對於乙個陣列而言,變數名a,表示乙個這個陣列的引用,
也就是首位址。對已指標p表示的是指標當前的位址。*p是這個位址下的值。
對於a[0],這個元素而言,他是陣列的第乙個元素,它現在表示的是乙個值,
用陣列下標表示,如果它想賦給乙個指標的話,那麼就必須使用位址符&,即
p=&a[0],這裡的p是乙個指標
int *i;
int a=10;
i=&a;
printf("%d\n",*i);正確
printf("%d\n",i);列印位址
這裡的i是乙個指標 i表示首位址,%d列印的是值所以需要使用i的間接訪問
C語言基礎四 指標
指標表示乙個位址,什麼型別的指標就應該指向什麼型別的記憶體空間,例如int 型別的指標就應該指向乙個int型別的空間。int a 7 int p null 指標的定義 p a 指標的繫結 p 5 指標的解引用對於同型別指標p1,p2,一般有這幾種運算 p1 3,p1 3,p2 p1 int a 5 ...
C語言基礎(9) 指標
指標與陣列 指標變數定義的一般形式 型別 指標變數名符號 在變數宣告語句中是指標型別說明符,前面的型別用於宣告指標可以指向哪種型別的變數,稱為指標的基型別。例如 int pt1 int pt2 int a 520 int pt a 用 運算子可以獲取指標變數所指向變數的內容,該運算子被稱為指標變數間...
C語言指標(2) 指標的應用
include include void swap int x,int y intmain 執行結果 交換前a 1,b 2 交換後a 2,b 1 請按任意鍵繼續.可以用乙個指標變數指向乙個陣列元素。例如 int a 10 int p a 0 當然定義時也可寫成 int p a include inc...