10.6 保护数组内容

在编写处理诸如int这样的基本类型的函数时,可以向函数传递int数值,也可以传递指向int的指针。通常我们直接传递数值;只有需要在函数中修改该值时,我们才传递指针。对于处理数组的函数,只能传递指针,原因是这样能使程序的效率更高。如果通过值向函数传递数组,那么函数中必须分配足够存放一份原数组的拷贝的存储空间,然后把原数组的所有数据复制到这个新数组中。如果简单地把数组的地址传递给函数,然后让函数直接读写原数组,程序的效率会更高。

这种技术也会带来一些问题。通常C传递数据的值,其原因是要保证原始数据的完整性。函数使用原始数据的一份拷贝,这样它就不会意外地修改原始数据。但是,由于处理数组的函数直接操作原始数据,所以它能够修改原数组。有时候这正是我们所需要的,例如下面这个函数的功能就是给数组中的每个元素加上同一个数值。

广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元

阅读 ‧ 电子书库

阅读 ‧ 电子书库

因此,下面的函数调用将使数组prices里的每个元素增加2.5:

阅读 ‧ 电子书库

该函数改变了数组的内容。之所以可以改变数组的内容,是因为函数使用了指针,从而能够直接使用原始数据。

然而也许其他的函数并不希望修改数据。例如下面这个函数的功能是计算数组中所有元素的和,所以它不应该改变数组的内容。然而由于ar实际上是一个指针,所以编程上的错误可以导致原始数据遭到破坏。例如,表达式ar[i]++就会导致每个元素的值增加1:

阅读 ‧ 电子书库

10.6.1 对形式参量使用const

在K&R C中,避免此类错误惟一的方法就是警惕不出错。ANSI C中有另一种方法。如果设计意图是函数不改变数组的内容,那么可以在函数原型和定义的形式参量声明中使用关键字const。例如sum()的原型和定义应该如下:

阅读 ‧ 电子书库

这告知编译器:函数应当把ar所指向的数组作为包含常量数据的数组对待。这样,如果您意外地使用了诸如ar[i]++之类的表达式,编译器将会发现这个错误并生成一条错误消息,通知您函数试图修改常量。

需要理解的是这样使用const并不要求原始数组是固定不变的;这只是说明函数在处理数组时,应把数组当作是固定不变的。使用const可以对数组提供保护,就像按值传递可以对基本类型提供保护一样;可阻止函数修改调用函数中的数据。总之,如果函数想修改数组,那么在声明数组参量时就不要使用const;如果函数不需要修改数组,那么在声明数组参量时最好使用const。

请参看程序清单10.14中的程序,其中一个函数显示数组,另一个函数对数组的每个元素乘上一个给定的数值。因为第一个函数不需要修改数组,所以使用const;因为第二个函数需要修改数组,所以不使用const。

程序清单10.14 arf.c程序

阅读 ‧ 电子书库

阅读 ‧ 电子书库

输出结果如下:

阅读 ‧ 电子书库

请注意两个函数都是void类型的。函数mult_array()确实使数组dip得到了新的值,但不是使用return机制实现的。

10.6.2 有关const的其他内容

前面我们讲过可使用const来创建符号常量:

阅读 ‧ 电子书库

以上也可以使用#define指令实现。但使用const还可以创建数组常量、指针常量以及指向常量的指针。程序清单10.4说明了使用关键字const保护数组的方法:

阅读 ‧ 电子书库

如果随后的程序代码试图改变数组,您将得到一个编译时的错误消息:

阅读 ‧ 电子书库

指向常量的指针不能用于修改数值,考虑下列代码:

阅读 ‧ 电子书库

第二行代码把pc声明为指向const double的指针。这样,就不可以使用pc来修改它所指向的数值。

阅读 ‧ 电子书库

无论是采用数组符号还是指针符号,都不能使用pd修改所指向数据的值。但请注意因为rates并没有声明为常量,所以仍可以使用rates来修改其数值。另外要注意,还可以让pc指向其他地址:

阅读 ‧ 电子书库

通常把指向常量的指针用作函数参量,以表明函数不会用这个指针来修改数据。例如,程序清单10.14中函数show_array()的原型可以如下定义:

阅读 ‧ 电子书库

关于指针赋值和const有一些规则需要注意。首先,将常量或非常量数据的地址赋给指向常量的指针是合法的:

阅读 ‧ 电子书库

然而,只有非常量数据的地址才可以赋给普通的指针:

阅读 ‧ 电子书库

这样的规则是合理的。否则,您就可以使用指针来修改被认为是常量的数据。

这些规则的实践结果是:像show_array()这样的函数可以接受普通数组和常量数组的名称作为实际参数,因为两种参数都可以赋给指向常量的指针:

阅读 ‧ 电子书库

但是,像mult_array()这样的函数不能接受常量数组的名称作为参数:

阅读 ‧ 电子书库

因此,在函数参量定义中使用const,不仅可以保护数据,而且使函数可以使用声明为const的数组。

const还有很多用法。例如:您可以使用关键字const来声明并初始化指针,以保证指针不会指向别处,关键在于const的位置:

阅读 ‧ 电子书库

这样的指针仍然可用于修改数据,但它只能指向最初赋给它的地址。

最后,可以使用两个const来创建指针,这个指针既不可以更改所指向的地址,也不可以修改所指向的数据:

阅读 ‧ 电子书库