16
17 // In f, xPtr is a poin er to an integer constant 18 void f( const int *xPtr ) 19 {
20 *xPtr = 100; // cannot modify a const object 21 }
输出结果:
Compiling FIG05 12.CPP:
Error FIG05 12.CPP 20: Cannot modify a const object Warning FIGOS_12.CPP 21: Parameter 'xPtr' is never used
图5.12 试图通过常量数据的非常量指针修改数据
众所周知,数组是累计数据类型,用同一名称存放相同类型的相关数据项。第6章将介绍另一种形式的累计数据类型——结构(structure),也称为记录(record)。结构可以用同一名称存放不同类型的相关数据项(例如,存放公司每个员工的信息)。调用带数组参数的函数时,数组模拟按引用调用自动传递给函数。但结构则总是按值调用,传递整个结构的副本。这就需要复制结构中每个数据项目并将其存放在计算机函数调用堆栈中的执行时开销(函数执行时用函数调用堆栈存放函数调用中使用的局部变量)。结构数据要传递绐函数时,可以用常量数据的指针(或常量数据的引用)得到按引用调用的性能和按值调用对数据的保护。传递结构的指针时,只要复制存放结构的地址。在4字节地址的机器上,只要复制4字节内存而不是复制结构的几百或几千字节。 性能提示5.7
要传递结构之类的大对象时,可以用常量数据的指什(或常量数据的引用)得到按引用调用的性能和按值调用对数据的保护。
非常量数据的常量指针总是指向相同的内存地址,该地址中的数据可以通过
指针修改。这里的数组名是默认的。数组名是数组开头的常量指针,数组中的所有数据可以用数组名和数组下标访问和修改。非常量数据的常量指针可以接收数组为函数参数,该函数只用数组下标符号访问数组元素。声明为const的指针应在声明时初始化(如果是函数参数,则用传入函数的指针初始化)。图5.13的程序想修改常量指针,指针ptr的类型声明为int *const,图中的声明表示“ptr是整数的常量指针”,指针用整型变量x的地址初始化。程序要将y的地址赋给ptr,但产生一个错误消息。注意数值7赋
给*ptr时不产生错误,说明ptr所指的值是可修改的。 常见编程错误5.6
声明为const的指针不在声明时初始化是个语法错误。
常量数据的常量指针的访问权限最低。这种指针总是指向相同的内存地址,该内存地址的数据不能修改。数组传递到函数中,该函数只用数组下标符号读取,而不能修改数组。图5.14的程序演示声明指针变量ptr为const int* const,表示“ptr是常量整数的常量指针”。图中显示了修改ptr所指数据和修改存放指针变量的地址时产生的错误消息。注意输出ptr所指的值时不产生错误,因为输出语句中没有进行修改。
1 // Fig. 5.13:fig05 13.cpp
2 // Attempting to modify a constant pointer to 3 // non-constant data 4 #include
6 int main() 7 {
8 int x, y; 9
10 int * const ptr = &x; // ptr is a constant pointer to an 11 // integer. An integer can be modified
12 // through ptr, but ptr always points 13 // to the same memory location. 14 *ptr = 7; 15 ptr = &y; 16
17 return 0; 18 }
输出结果:
Compiling FIG05 13.CPP:
Error FIG05 13.CPP 15: Cannot modify a const object Warning FIGOS_13.CPP 18: 'y' is declared but never used
图5.13修改非常量数据的常量指针
1 // Fig. 5.141 fig05 14.cpp
2 // Attempting to modify a constant pointer to 3 // constant data. 4 #include
6 int main() 7 {
8 int x = 5, y; 9
10 const iht *const ptr = &x; // ptr is a constant pointer to a 11 // constant integer, ptr always 12 // points to the same location 13 // and the integer at that 14 // location cannot be modified.
15 eout << *ptr << endl; 16 *ptr = 7; 17 ptr = &y; 18
19 return 0; 20 }
输出结果:
Compiling FIG05 14.CPP:
Error FIG05_14.CPP 16: Cannot modify a const object Error FIG05_14.CPP 17: Cannot modify a const object Warning FIG05_14.CPP 20: 'y' is declared but never used
图5.14 修改常量数据的常量指针
5.6 按引用调用的冒泡排序
下面将图4.16的冒泡排序程序修改成用两个函数bubbleSort和swap(如图5.15)。函数bubbleSort进行数组排序,它调用函数swap,变换数组元素array[j)和array[j+1]记住,C++强制函数之间的信息隐藏,因此swap并不能访问bubbleSort中的各个元素。由于bubbleSort要求swap访问交换的数组元素,因此bubbleSort要将这些元素按引用调用传递给swap.每个数组元素的地址显式传递。
尽管整个数组自动按引用调用传递,但各个数组元素是标量,通常按值调用传递。因此,bubbleSort对swap调用中的每个数组元素使用地址运算符(&),如下所示的语句:
swap( &array[ j ], array[j+ 1]);
实现按引用调用。函数swap用指针变量element1Ptr接收&array[j]。由于信息隐藏,swap并不知道名称&array[j],但swap可以用*element1Ptr作为&array[j]的同义词。这样,swap引用*element1Ptr时,实际上是引用bubbleSort中的
&array[j]。同样,swap引用*element2Ptr时,实际上是引用bubbleSort中的array[j+1]。虽然swap不能用: hold = array [ j ];
array[ j ] = array[ j + 1 ]; array[ j + 1 ] = hold;
但图5.15中的swaP函数用 hold = * element1Ptr; *element1Ptr = *element2Ptr; *element2Ptr = hold; 达到相同的效果。
1 // Fig. 5.15: fig05_15.cpp
2 // This program puts values into an array, sorts the values into 3 // ascending order, and prints the resulting array. 4 #include
7 void bubbleSort{ int *, const int ); 8
D int main(} l0 {
11 const int arraySize = 10;
12 int a[ arraySize ) = { 2, 6, 4, 8, 10, 12, 89, 68, 45, 37 }; 13 int i; 14
15 cout << \16
17 for ( i = 0; t < arraySize; i++ )