本节书摘来自华章计算机《c++语言导学》一书中的第1章,第1.8节,[美] 本贾尼·斯特劳斯特卢普 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1.8 指针、数组和引用
元素类型为char的数组可以声明如下:
类似地,指针可以声明如下:
https://yqfile.alicdn.com/cb1c2e165d6d5afd2397d5481f7754f1ecc1094c.png
" >
在声明语句中,[ ]表示“……的数组”,*表示“指向……”。所有数组的下标都从0开始,因此v包含6个元素:v[0]到v[5]。数组的大小必须是一个常量表达式(见1.7节)。指针变量中存放着一个指定类型对象的地址:
在表达式中,前置一元运算符*表示“……的内容”,而前置一元运算符&表示“……的地址”。可以用下面的图形来表示上述初始化定义的结果:
https://yqfile.alicdn.com/86b6db9aa20349861e511600f4defe900834b2d7.png
" >
考虑将一个数组的10个元素拷贝给另一个数组的任务:
https://yqfile.alicdn.com/b188c8f450d33bb47a8a1700b036098475904cb3.png
" >
上面的for语句可以这样解读:将i置为0,当i不等于10时,拷贝第i个元素并递增i。当作用于一个整型变量时,递增运算符++执行简单的加1操作。C++还提供了一种更简单的for语句,即范围for(range-for)语句,它可以用最简单的方式遍历一个序列:
https://yqfile.alicdn.com/c2a547f976a322ad625d5ca9f5854e008bf2e2d6.png
" >
上面的第一个范围for语句可以解读为“对于v的每个元素,将其从头到尾依次拷入x并打印”。注意,当我们使用一个列表初始化数组时无需指定其大小。范围for语句可用于任意的元素序列(见10.1节)。
如果我们不希望把v的值拷贝到变量x中,而只是令x引用一个元素,则可以编写如下的代码:
在声明语句中,一元后置运算符&表示“……的引用”。引用类似于指针,唯一的区别是我们无需使用前置运算符*访问所引用的值。同样,一个引用在初始化之后就不能再引用其他对象了。
当我们指定函数的参数类型时,引用特别有用。例如:
通过把参数类型定义成引用,我们在调用sort(my_vec)函数时就不必把实参拷贝给形参,而是直接在my_vec上执行操作,对它排序。
还有一种情况,我们既不想修改实参的内容,又希望节省参数拷贝的代价,此时可以使用const引用。例如:
函数使用const引用类型的参数是一个非常普遍的现象。
当用于声明语句时,运算符(如&、*和[])称为声明运算符(declarator operator):
我们的目标是确保指针永远指向某个对象,这样解引用该指针的操作就是合法的。当确实没有对象可指或者希望表达一种“没有可用对象”的含义时(比如在列表的末尾),我们令指针取值为nullptr(“空指针”)。所有指针类型都共享同一个nullptr:
通常情况下,当我们希望指针实参指向某个东西时,最好检查一下是否确实如此:
有两点值得注意:一是我们可以使用++把指针移动到数组的下一个元素;二是在for语句中如果我们不需要初始化操作,则可以省略它。
count_x()的定义假定char*是一个C风格字符串(C-style string),也就是说指针指向了一个字符数组,该数组的结尾处是0。
在旧式代码中,0和NULL都可以用来替代nullptr的功能。不过,使用nullptr能够避免混淆整数(如0或NULL)和指针(如nullptr)。
例子中用到的count_x()函数不必太复杂,我们只需对nullptr稍做检查即可。因为在上面的代码中for语句并没有执行初始化的部分,所以不妨把它改成更简单的while语句:
https://yqfile.alicdn.com/8d22d78508b957ca4ebe05197605680536bbedd4.png" >
while语句不断重复执行,直到它的条件部分变成false为止。
直接把指针作为条件检验(如while(p))的效果等同于比较该指针与空指针是否相等(如while(p!=nullptr))。