1776
的記憶體單元緊跟在地址為1775
的單元之後,並位於地址為1777
的單元之前,它比地址776
晚一千個單元,比地址2776
早一千個單元。
|
|
myvar
的地址分配給foo
;透過在變數myvar
名前加上取地址運算子(&
),我們不再是將變數本身的內容分配給foo
,而是其地址。myvar
被放置在記憶體地址1776
。
|
|
25
賦給了myvar
(我們假設其記憶體地址為1776
的變數)。myvar
的地址(我們假設為1776
)賦給了foo
。myvar
中包含的值賦給了bar
。這是一個標準的賦值操作,正如在前面的章節中已經多次完成的那樣。&
)的出現。*
)來實現的。該運算子本身可以讀作“指向的值”。
|
|
baz
等於foo
指向的值”,並且該語句實際上會將值25
賦給baz
,因為foo
是1776
,而1776
指向的值(根據上面的示例)是25
。foo
指的是值1776
,而*foo
(在識別符號前有一個星號*
)指的是儲存在地址1776
的值(在本例中為25
)非常重要。請注意包含或不包含解引用運算子的區別(我已經添加了關於這兩個表示式如何讀取的解釋性註釋)。
|
|
&
是取地址運算子,可以簡單地讀作“地址”。*
是解引用運算子,可以讀作“指向的值”。&
獲得的地址可以用*
解引用。
|
|
|
|
myvar
執行的賦值操作是myvar=25
。第二個表示式使用了取地址運算子(&
),它返回myvar
的地址,我們假設其值為1776
。第三個表示式有些顯而易見,因為第二個表示式為真,並且對foo
執行的賦值操作是foo=&myvar
。第四個表示式使用了解引用運算子(*
),可以讀作“指向的值”,而foo
指向的值確實是25
。foo
指向的地址保持不變,以下表達式也將為真:
|
|
char
時與指向int
或float
時具有不同的屬性。一旦解引用,就需要知道型別。為此,指標的宣告需要包含指標將指向的資料型別。type * name;
type
是該指標指向的資料型別。此型別不是指標本身的型別,而是指標指向的資料的型別。例如:
|
|
int
,第二個指向char
,最後一個指向double
。因此,儘管這三個示例變數都是指標,但它們的型別實際上是不同的:分別為int*
、char*
和double*
,具體取決於它們指向的型別。*
)僅表示它是一個指標(它是其型別複合說明符的一部分),不應與前面看到的解引用運算子混淆,後者也用星號(*
)表示。它們只是用同一個符號表示的兩個不同的東西。
|
|
firstvalue is 10 secondvalue is 20 |
firstvalue
和secondvalue
設定任何值,它們最終都透過使用mypointer
間接設定了值。它是這樣發生的:&
)將firstvalue
的地址賦給mypointer
。然後,將mypointer
指向的值賦為10
。由於此刻mypointer
指向firstvalue
的記憶體位置,這實際上會修改firstvalue
的值。mypointer
重複了對secondvalue
的過程。
|
|
firstvalue is 10 secondvalue is 20 |
*
)。p1
和p2
的表示式,其中包含和不包含解引用運算子(*
)。使用解引用運算子(*)的表示式的含義與不使用該運算子的表示式截然不同。當該運算子出現在指標名稱之前時,表示式引用的是所指向的值;而當指標名稱沒有該運算子時,它引用的是指標本身的值(即,指標指向的地址)。
|
|
*
),以便兩者都能擁有型別int*
(指向int
的指標)。這是必需的,因為優先順序規則。請注意,如果程式碼是:
|
|
p1
確實是int*
型別,但p2
是int
型別。在這種情況下,空格完全無關緊要。但無論如何,對於對宣告多個指標感興趣的大多數指標使用者而言,記住每個語句有一個星號就足夠了。甚至更好:為每個變數使用不同的語句。
|
|
|
|
mypointer
和myarray
將是等效的,並且將具有非常相似的屬性。主要區別在於mypointer
可以被賦以不同的地址,而myarray
永遠不能被賦以任何值,並且將始終代表相同大小的20個int
型別元素的塊。因此,以下賦值無效:
|
|
|
|
10, 20, 30, 40, 50, |
[]
)被解釋為指定陣列元素的索引。實際上,這些方括號是已知的偏移運算子的解引用運算子。它們就像*
一樣解引用其後面的變數,但它們還將括號內的數字加到被解引用的地址上。例如:
|
|
a
是指標時,當a
是陣列時也是如此。請記住,如果是一個數組,它的名稱可以用作指向其第一個元素的指標。
|
|
|
|
myptr
),而不是所指向的值(即*myptr
)。因此,上面的程式碼不應與以下程式碼混淆:
|
|
*
)(第2行)僅表示它是一個指標(它是其型別複合說明符的一部分),不應與解引用運算子(第3行)混淆。這兩者碰巧都使用相同的符號:*
。一如既往,空格無關緊要,並且從不改變表示式的含義。
|
|
char
的大小始終為1位元組,short
通常比char
大,而int
和long
更大;這些的確切大小取決於系統。例如,讓我們假設在一個給定的系統中,char
佔用1位元組,short
佔用2位元組,long
佔用4位元組。
|
|
1000
、2000
和3000
,分別。
|
|
mychar
將包含值1001。但並非顯而易見的是,myshort
將包含值2002,而mylong
將包含3004,儘管它們都只被遞增了一次。原因是,當向指標加一時,指標被指向相同型別的下一個元素,因此,它指向的型別的大小(以位元組為單位)會被新增到指標中。
|
|
++
)和遞減(--
)運算子,它們都可以作為表示式的字首或字尾使用,行為略有不同:作為字首時,遞增發生在表示式求值之前;作為字尾時,遞增發生在表示式求值之後。這也適用於遞增和遞減指標的表示式,這些表示式可以成為更復雜的表示式的一部分,而這些表示式還包括解引用運算子(*
)。回想一下運算子優先順序規則,我們可以記得字尾運算子(如遞增和遞減)的優先順序高於字首運算子(如解引用運算子(*
))。因此,表示式:
|
|
*(p++)
。它的作用是增加p
的值(因此它現在指向下一個元素),但由於++
被用作字尾而不是字首,因此整個表示式的求值結果是先前由指標指向的值(在遞增之前它指向的地址)。
|
|
|
|
++
的優先順序高於*
,因此p
和q
都會遞增,但由於兩個遞增運算子(++
)都用作字尾而不是字首,因此賦給*p
的值是*q
,然後在p
和q
都遞增之前。然後兩者都遞增。這大致相當於:
|
|
const
即可。例如:
|
|
p
指向一個變數,但以const
限定的方式指向它,這意味著它可以讀取所指向的值,但不能修改它。另請注意,表示式&y
的型別是int*
,但這被賦給了一個型別為const int*
的指標。這是允許的:指向非const的指標可以隱式轉換為指向const的指標。但反過來則不行!作為一種安全功能,指向const
的指標不能隱式轉換為指向非const
的指標。const
元素的指標的一個用途是作為函式引數:一個接受指向非const
的指標作為引數的函式可以修改作為引數傳遞的值,而一個接受指向const
的指標作為引數的函式則不能。
|
|
11 21 31 |
print_all
使用指向常量元素的指標。這些指標指向它們無法修改的常量內容,但它們本身不是常量:也就是說,指標仍然可以遞增或被賦以不同的地址,儘管它們不能修改它們所指向的內容。const
的第二維新增到指標:指標本身也可以是const
的。這是透過將const
附加到指向的型別(在星號之後)來指定的:
|
|
const
與指標的語法確實很棘手,並且識別最適合每種用途的案例通常需要一些經驗。無論如何,儘早正確掌握const
與指標(和引用)的結合非常重要,但如果您是第一次接觸const
和指標的混合,則不必過於擔心掌握所有內容。後續章節將出現更多用例。const
與指標語法的混淆度,const
限定符可以放在指向型別的前面或後面,具有完全相同的含義:
|
|
const
順序只是風格問題。本章使用字首const
,因為出於歷史原因,這似乎更為普遍,但兩者完全等效。各自風格的優點仍在網際網路上激烈爭論。cout
,初始化字串以及初始化字元陣列。const char
型別(作為字面量,它們永遠不能被修改)。例如:
|
|
"hello"
字面量表示的陣列,然後將指向其第一個元素的指標賦給了foo
。如果我們設想"hello"
儲存在從地址1702開始的記憶體位置,我們可以將前面的宣告表示為:foo
是指標,其值為1702
,而不是'h'
或"hello"
,儘管1702
確實是這兩者的地址。foo
指向一個字元序列。由於指標和陣列在表示式中的行為基本相同,因此foo
可以用來訪問字元,方式與以 null 結尾的字元序列的陣列相同。例如:
|
|
'o'
(陣列的第五個元素)。*
):
|
|
7230
、8092
和10502
,這可以表示為:c
,它是一個指向指標的指標,可以用於三個不同的間接級別,每個級別都對應一個不同的值:c
的型別是char**
,值為8092
。*c
的型別是char*
,值為7230
。**c
的型別是char
,值為'z'
。void
指標是一種特殊的指標型別。在C++中,void
表示型別的缺失。因此,void
指標是指向沒有型別的值的指標(因此長度和解引用屬性也是不確定的)。void
指標具有極大的靈活性,因為它們可以指向任何資料型別,從整數值或浮點數到字元字串。作為交換,它們有一個很大的限制:它們指向的資料不能直接解引用(這是合乎邏輯的,因為我們沒有型別可以解引用),因此,void
指標中的任何地址都需要在解引用之前轉換為指向具體資料型別的其他指標型別。
|
|
y, 1603 |
sizeof
是C++語言整合的一個運算子,它返回其引數的大小(以位元組為單位)。對於非動態資料型別,此值是常量。因此,例如,sizeof(char)
為1,因為char
的大小始終為1位元組。
|
|
p
和q
均未指向已知包含值的地址,但以上任何語句都不會導致錯誤。在C++中,指標可以取任何地址值,無論該地址處是否實際存在內容。可能導致錯誤的是解引用此類指標(即實際訪問它們指向的值)。訪問此類指標會導致未定義的行為,從執行時錯誤到訪問隨機值。nullptr
。
|
|
p
和q
都是空指標,這意味著它們顯式地指向“無”,並且它們都相等比較:所有空指標都與其他空指標相等。在舊程式碼中,經常可以看到定義的常量NULL
被用來表示空指標值:
|
|
NULL
在標準庫的幾個標頭檔案中定義,並被定義為某個空指標常量值(如0
或nullptr
)的別名。void
指標混淆!空指標是任何指標都可以取的值,表示它指向“無”;而void
指標是一種指標型別,它可以指向沒有特定型別的位置。一個是指標中儲存的值,另一個是指標指向的資料型別。()
中,並在名稱前插入一個星號(*
):
|
|
8 |
minus
是指向具有兩個int
型別引數的函式的指標。它被直接初始化為指向subtraction
函式:
|
|
![]() 字元序列 | ![]() 目錄 | ![]() 動態記憶體 |