9.1 函数的定义和调用
9.1.2 函数调用
(在C语言中,“强制转换成void”是对“抛弃”的一种客气说法。)使用(void)可以使别人清楚编写者是故意抛弃返回值的,而不是忘记了。
9.2 函数声明
9.3 实际参数
9.3.1 实际参数的转换
C语言允许在实际参数的类型与形式参数的类型不匹配的情况下进行函数调用。管理如何转换实际参数的规则与编译器是否在调用前遇到函数的原型有关。
- 编译器在调用前遇到原型。就像使用赋值一样,每个实际参数的值被隐式地转换成相应形式参数的类型。例如,如果把int类型的实际参数传递给期望得到double类型数据的函数,那么实际参数会被自动转换成double类型。
- 编译器在调用前没有遇到原型。编译器执行默认的实际参数提升:(1)把float类型的实际参数转换成double类型,(2)执行整值提升,即把char类型和short类型的实际参数转换成int类型。(C99实现了整数提升。)
- 在C99中,调用square之前不提供声明或定义是错误的。
9.3.2 数组型实际参数
数组经常被用作实际参数。
- 当形式参数是一维数组时:可以(而且是通常情况下)不说明数组的长度,实际参数可以是元素类型正确的任何一维数组。:
int f(int a[]) /* no length specified */ { ... }
可惜的是,C语言没有为函数提供任何简便的方法来确定传递给它的数组的长度;如果函数需要,我们必须把长度作为额外的参数提供出来。
- 当形式参数是多维数组时,声明参数时只能省略第一维的长度。
9.3.3 变长数组形式参数(C99)
- 这一特性允许我们用非常量表达式指定数组的长度。变长数组也可以作为参数。如果使用变长数组形式参数,我们可以明确说明数组a的长度就是n:
int sum_array(int n, int a[n]) { ... }
//这个是错误的
int sum_array(int a[n], int n) /*** WRONG ***/ { ... }
- 对于新版本的sum_array函数,其函数原型有好几种写法。
int sum_array(int n, int a[n]); /* Version 1 */
int sum_array(int n, int a[*]); /* Version 2a */
int sum_array(int, int [*]); /* Version 2b */
int sum_array(int n, int a[]); /* Version 3a */
int sum_array(int, int []); /* Version 3b 但是让括号为空不是一个很好的选择,因为这样并没有说明n和a之间的关系。*/
9.3.4 在数组参数声明中使用static(C99)
C99允许在数组参数声明中使用关键字static
在下面这个例子中,将static放在数字3之前表明数组a的长度至少可以保证是3:
int sum_array(int a[static 3], int n) { ... }
最后,关于static还有一点值得注意:如果数组参数是多维的,static仅可用于第一维(例如,指定二维数组的行数。)
9.3.5 复合字面量(C99)
在C99中,可以使用复合字面量来避免该问题,复合字面量是通过指定其包含的元素而创建的没有名字的数组。下面调用sum_array函数,第一个参数就是一个复合字面量:
total = sum_array((int []){3, 0, 3, 4, 1},5);