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
函数:
|
|
![]() 字符序列 | ![]() 目录 | ![]() 动态内存 |