第七章 函数
这一章对于有一定C的基础的人有一定优秀代码风格的人来说,并不是很虐。关于stdarg宏可能有些陌生,它负责可变参数列表的定义。
总结:
新式风格和旧式风格就不要提了。八百年前的事情。
函数常见的是把原型放在一个单独的文件里,当其他文件需要这个原型时,就用#include指令把这个文件包含进来,这个技巧可以使原型必需的拷贝份数降低到最低,有助于提高程序的可维护性。
return语句用于指定从一个函数返回的值,如果没有返回值,为void。
函数的参数是通过传值的方式进行转换,实际传递的实参的一份拷贝。因此,函数可以修改它的形参的拷贝,而不会改变参数原值。
数组名也是通过传值方式传递的,但它传给函数的是一个指针的拷贝。数组形参使用了下标引用操作,就会引发间接访问操作,实际访问的是数组元素。
抽象数据类型(ADT),又叫黑盒。由接口和实现两部分组成。
接口是共有,说明客户如何使用ADT所使用的功能。
实现是私有,实际执行的部分。
递归函数直接或者间接的调用自身。
有些递归比如尾部递归可以用迭代来实现,效率会高很多。尤其是斐波那契数列。
可变的参数数量和类型,他们可以用stdarg.h头文件所定义的宏来实现。可变参数能治从第一个到最后一个依次访问。
下面会弄个例子来说明可变参数。
警告:
1、错误地在其他函数的作用域内编写函数原型。
恩,注意函数的链接属性。如果在其他函数的代码块里就无法使用该函数。
2、没有为那些返回值不是整数的函数编写原型。
因为返回值的缺省值是整型。
3、在va_arg中使用错误的参数类型,导致未定义的结果。
看个例子:
#include <stdarg.h>
/* 取形参的平均值 */
float average(int n_value,...)
{
va_list var_arg;
int count;
float sum=0;
/** 准备访问可变参数 */
va_start(var_arg, n_values);
/* 添加取自可变参数列表的值 */
for(count = 0; count < n_values; count += 1)
{
sum += va_arg(var_arg, int );
}
/* 完成处理可变参数 */
va_end(var_arg);
return sum/n_values;
}
参数类型必须明确在va_arg(var_arg, ***)中说明,务必!
编程提示:
1、在函数原型中使用参数名。可以给函数的用户提供更多的信息。
请尽量使用参数名,不要这种:
int func(int , int);
从函数名到形参一坨shi。
2、抽象数据类型可以减少程序对模块实现的细节的以来,提高可靠性。
3、当递归定义清晰的这点可以补偿它的效率时,就用递归吧。
这一章对于有一定C的基础的人有一定优秀代码风格的人来说,并不是很虐。关于stdarg宏可能有些陌生,它负责可变参数列表的定义。
总结:
新式风格和旧式风格就不要提了。八百年前的事情。
函数常见的是把原型放在一个单独的文件里,当其他文件需要这个原型时,就用#include指令把这个文件包含进来,这个技巧可以使原型必需的拷贝份数降低到最低,有助于提高程序的可维护性。
return语句用于指定从一个函数返回的值,如果没有返回值,为void。
函数的参数是通过传值的方式进行转换,实际传递的实参的一份拷贝。因此,函数可以修改它的形参的拷贝,而不会改变参数原值。
数组名也是通过传值方式传递的,但它传给函数的是一个指针的拷贝。数组形参使用了下标引用操作,就会引发间接访问操作,实际访问的是数组元素。
抽象数据类型(ADT),又叫黑盒。由接口和实现两部分组成。
接口是共有,说明客户如何使用ADT所使用的功能。
实现是私有,实际执行的部分。
递归函数直接或者间接的调用自身。
有些递归比如尾部递归可以用迭代来实现,效率会高很多。尤其是斐波那契数列。
可变的参数数量和类型,他们可以用stdarg.h头文件所定义的宏来实现。可变参数能治从第一个到最后一个依次访问。
下面会弄个例子来说明可变参数。
警告:
1、错误地在其他函数的作用域内编写函数原型。
恩,注意函数的链接属性。如果在其他函数的代码块里就无法使用该函数。
2、没有为那些返回值不是整数的函数编写原型。
因为返回值的缺省值是整型。
3、在va_arg中使用错误的参数类型,导致未定义的结果。
看个例子:
#include <stdarg.h>
/* 取形参的平均值 */
float average(int n_value,...)
{
va_list var_arg;
int count;
float sum=0;
/** 准备访问可变参数 */
va_start(var_arg, n_values);
/* 添加取自可变参数列表的值 */
for(count = 0; count < n_values; count += 1)
{
sum += va_arg(var_arg, int );
}
/* 完成处理可变参数 */
va_end(var_arg);
return sum/n_values;
}
参数类型必须明确在va_arg(var_arg, ***)中说明,务必!
编程提示:
1、在函数原型中使用参数名。可以给函数的用户提供更多的信息。
请尽量使用参数名,不要这种:
int func(int , int);
从函数名到形参一坨shi。
2、抽象数据类型可以减少程序对模块实现的细节的以来,提高可靠性。
3、当递归定义清晰的这点可以补偿它的效率时,就用递归吧。