6 函数
6.1 函数基础
- 函数包含 : 返回类型,函数名字,0个或多个形参
- 调用运算符:()
编写函数
调用函数
#include<iostream>
using std::cin; using std::cout; using std::endl;
int fact(int val)
{
int ret = 1;
while (val > 1)
ret *= val--;
return ret;
}
int main()
{
int j = fact(5);
cout << "5! is" << j << endl;
return 0;
}
函数的调用顺序:实参5传递给形参val,执行fact函数直到return ret,再用ret初始化j,回到主函数顺序运行
- return作用:1 将return 语句中的值返回 2 将控制权返回主调函数
形参和实参
实参是形参的初始值
- 实参的类型必须与形参相匹配
- 提供实参需满足1)能与形参转换 2)数量一致
函数形参列表
-
形参列表可为空:
-
多个形参,必须声明每个形参类型:
任意两个形参不能同名
函数返回类型不能是数组
6.1.1 局部对象
- 对象的生命周期:
- 局部变量:形参和函数体内部定义的变量,仅在函数作用域内可见
自动对象
只存在于块执行期间的对象,如形参。
- 如形参不初始化,执行默认初始化,会产生未定义的值
局部静态对象
- static类型:第一次被初始化后,直至程序终止才会被销毁
6.1.2 函数声明
-
函数只能定义一次但可多次声明
函数声明:无需函数体,只需声明后加上分号
函数定义:包含函数体
-
函数三要素:返回类型,函数名,形参类型
在头文件中进行函数声明
6.1.3 分离式编译
6.2 参数传递
- 当形参为引用类型时,它对应的实参类型被引用传递或函数被传引用调用,即引用形参是其对应实参的别名
- 当实参的值拷贝给,则称实参被值传递或函数被传值调用
6.2.1 传值参数
-
初始化一个非引用变量时,初始值拷贝给变量,不会影响初始值
-
传值参数的机理与初始化非引用变量一样
指针形参
6.2.2 传引用参数
- 和其它引用一样,引用形参绑定初始化它的对象
使用引用避免拷贝
- 比较两个string长度时,为避免输入string类型过长,使用引用形参比较明智
使用引用形参返回额外信息
- 函数需返回多个值时可使用引用形参
统计字符串的字母出现次数和第一次出现位置
#include<iostream>
using std::cin; using std::cout; using std::endl; using std::string;
string::size_type find_char(const string& s, char c, string::size_type& occurs)
{
auto ret = s.size();
occurs = 0;
for(decltype(ret)i=0;i!=s.size();i++)
{
if (s[i] == c)
{
if (ret == s.size())
ret = i;
occurs++;
}
}
return ret;
}
int main()
{
string::size_type ctr;
string s("Hello");
auto index = find_char(s, 'o', ctr);
cout << s << endl;
cout<< ctr << endl;
return 0;
}
6.2.3 const形参和实参
- 和其它初始化过程一样,实参初始化形参时,会忽略顶层const的性质,传给形参的是否是const都无所谓
- 顶层,底层const在实际运用时有区别,但作为形参时类型相同
- 允许我们定义具有相同名字的函数,但其形参列表应有明显区别
指针或引用实参与const
- 可以使用非常量初始化底层const对象,但反之不行
尽量使用常量引用
- 尽量将不想改变的形参定义为const
由于&s对应字面值Hello World则会报错
6.2.4 数组形参
- 数组的两个特殊性:
1.不允许拷贝数组
2.通常会将数组转换为指针 - 向函数传递数组实际上是传递数组的指针
管理指针的三种技术:
使用标记指定数组长度
#include<iostream>
using std::cout; using std::cin; using std::endl; using std::string;
void print(const char* cp)
{
if (cp)
while (*cp)
cout<<* cp++;
}
int main()
{
char j[5] = { 'a','b','c','d' };
print(j);
return 0;
运用char型数组以0结尾,结合判断语句,输出整个数组,仅对char型数组有用
使用标准库范围
#include<iostream>
#include<iterator>
using std::cout; using std::cin; using std::endl; using std::string;
void print(const int* beg, const int* end)
{
while (beg != end)
cout << *beg++<<endl;
}
int main()
{
int j[5] = { 1,2,3,4,5 };
print( std::begin(j), std::end(j));
return 0;
}
运用迭代器,将两个指针分别指向数组的首尾,依次输出元素
显示传递一个表示数组大小的形参
#include<iostream>
#include<iterator>
using std::cout; using std::cin; using std::endl; using std::string; using std::end; using std::begin;
void print(const int ia[], size_t size)
{
for (size_t i = 0; i < size; i++)
cout << ia[i] << endl;
}
int main()
{
int j[] = { 1,2 };
print(j, end(j) - begin(j));
return 0;
}
运用形参表示数组大小,依次输出数组成员
数组形参和const
- 当不需要对数组元素改写时,数组形参应指向const指针,除此之外,才定义为非常量指针
数组引用形参
- 形参可以是数组的引用:
传递多维数组
6.2.5 main: 处理命令行选项
#include<iostream>
using std::cin; using std::cout; using std::endl;
int main(int argc,char* argv[])
{
cout << "argc=" << argc << endl;
for (int i = 0; i < argc; i++)
cout << "argv["<< i << "]=" << argv[i]<<endl;
return 0;
}
6.2.6 含有可变形参的函数
initializer_list函数
如果函数的实参数量未知,但类型相同,则可用initializer_list形参
- initializer_list对象中的值永远是常量值,无法改变其值