第6章 函数
练习6.1
实参是函数调用的实际值,是形参的初始值
练习6.2
- (a)返回类型不匹配
int f()
{
int s;
//...
return s;
}
- (b)无返回类型
void f2(int i) {/*...*/}
- (c)形参不能同名
int clac(int v1,int v2) {/*...*/}
- (d)函数体要用花括号括起来
double square(double x) {return x*x;}
练习6.3
#include <iostream>
using namespace std;
int fact(int val);
int main()
{
cout << fact(5) << endl;
return 0;
}
int fact(int val)
{
int ret = 1;
while (val > 1)
{
ret *= val--;
}
return ret;
}
练习6.4
#include <iostream>
using namespace std;
int fact(int val);
int main()
{
cout << "Please enter a number: " << endl;
int i = 0;
cin >> i;
cout << fact(i);
}
int fact(int val)
{
int ret = 1;
while (val > 1)
{
ret *= val--;
}
return ret;
}
练习6.5
#include <iostream>
using namespace std;
double myAbs(double val);
int main()
{
cout << "Please enter a number: " << endl;
double i = 0;
cin >> i;
cout << myAbs(i);
}
double myAbs(double val)
{
if (val > 0)
return val;
else
return - 1 * val;
}
练习6.6
形参定义在函数形参列表里面;局部变量定义在代码块里面;局部静态变量在程序的执行路径第一次经过对象定义语句时初始化,并且直到程序终止时才被销毁
#include <iostream>
#include <string>
using namespace std;
void fun(int val);
int main()
{
fun(3);
fun(8);
fun(5);
fun(7);
}
void fun(int val)
{
static int p = 0;
int ret = val;
while (ret > 1)
{
cout << "*";
--ret;
}
cout << " " << ++p <<" Times"<< endl;
}
练习6.7
#include <iostream>
using namespace std;
int pplus();
int main()
{
cout << pplus() << endl;
cout << pplus() << endl;
cout << pplus() << endl;
}
int pplus()
{
static int p = 0;
return p++;
}
练习6.8
Chapter6.h文件
int fact(int val);
double myAbs(double val);
练习6.9
fact.cpp文件
#include "Chapter6.h"
int fact(int val)
{
int ret = 1;
while (val > 1)
{
ret *= val--;
}
return ret;
}
factMain.cpp文件
#include <iostream>
#include "Chapter6.h"
using namespace std;
int main()
{
cout << fact(5);
return 0;
}
练习6.10
#include <iostream>
using namespace std;
void mySwap(int* a, int* b);
int main()
{
int i = 99, j = 1;
cout << i << " " << j << endl;
mySwap(&i, &j);
cout << i << " " << j << endl;
return 0;
}
void mySwap(int* a, int* b)
{
int temp = 0;
temp = *a;
*a = *b;
*b = temp;
}
练习6.11
#include <iostream>
using namespace std;
void reset(int& val);
int main()
{
int i = 100;
cout << i << endl;
reset(i);
cout << i;
return 0;
}
void reset(int& val)
{
val = 0;
}
练习6.12
#include <iostream>
using namespace std;
void swap(int& a, int& b);
int main()
{
int i = 999, j = 888;
cout << i << " " << j << endl;
swap(i, j);
cout << i << " " << j << endl;
return 0;
}
void swap(int& a, int& b)
{
a = a + b;
b = a - b;
a = a - b;
}
引用更易于使用,更加简洁
练习6.13
void f(T)的参数通过值传递,在函数中 T 是实参的副本,改变T不会影响到原来的实参void f(T&)的参数通过引用传递,在函数中的T是实参的引用,T的改变也就是实参的改变
练习6.14
交换两个整数的值时,形参应该是引用类型,当实参是右值时,形参不应该是引用类型
练习6.15
s是常量引用是因为,string字符串可能很大,使用引用效率较高,而函数并不会改变s,故使用常量。c是普通char,是因为c可能会是一个右值,故不能是引用。occurs是普通引用是因为,函数要改变它,故用引用,也因此不能是常量。
练习6.16
常量字符串和字符串字面值无法作为该函数的实参,改为
bool is_empty(const string &s) {return s.empty();}
练习6.17
#include <iostream>
#include <string>
using namespace std;
bool isBig(const string &s);
string toSmall(string &s);
int main()
{
if (isBig("huShun"))
{
cout << "yes" << endl;
}
else
{
cout << "no" << endl;
}
string s = "HUsHuN";
cout << toSmall(s);
return 0;
}
bool isBig(const string &s)
{
for (char ch : s)
{
if (isupper(ch))
return true;
}
return false;
}
string toSmall(string &s)
{
for (char &ch : s)
{
ch = tolower(ch);
}
return s;
}
不一样,isBig不改变s,为常量引用,toSmall改变s,为普通引用
练习6.18
- (a)
bool compare(matrix&,matrix&); - (b)
vector<int>::iterator change_val(int,vector<int>::iterator);
练习6.19
- (a)非法,形参数量不匹配
- (b)合法
- (c)合法
- (d)合法
练习6.20
应该尽量将引用形参设为常量引用,除非有明确的目的是为了改变这个引用变量。如果形参应该是常量引用,而我们将其设为了普通引用,那么常量实参将无法作用于普通引用形参
练习6.21
#include <iostream>
using namespace std;
int whoBig(const int i, const int *j);
int main()
{
int a = 100, b = 108;
cout << whoBig(a, &b);
return 0;
}
int whoBig(const int i, const int *j)
{
return i > *j ? i : *j;
}
应该是const int*
练习6.22
#include <iostream>
using namespace std;
void swapAdd(int *&p1, int *&p2);
int main()
{
int i = 999, j = 0, *p1 = &i, *p2 = &j;
cout << *p1 << " " << *p2 << endl;
swapAdd(p1, p2);
cout << *p1 << " " << *p2 << endl;
}
void swapAdd(int *&p1, int *&p2)
{
int *temp = p1;
p1 = p2;
p2 = temp;
}
练习6.23
#include <iostream>
using namespace std;
void print(const int i);
void print(const int *arr, int i);
int main()
{
int i = 0, j[8] = { 0,1,9,14,45 };
print(i);
cout << endl;
print(j,8);
return 0;
}
void print(const int i)
{
cout << i;
}
void print(const int *arr, int i)
{
for (int n = 0; n < i; ++n)
cout << arr[n] << " ";
}
练习6.24
当数组作为实参的时候,会被自动转换为指向首元素的指针。因此函数形参接受的是一个指针。如果要让这个代码成功运行,可以将实参改为数组的引用
void print(const int (&ia)[10])
{
for (size_t i = 0; i != 10; ++i)
cout << ia[i] << endl;
}
练习6.25
#include <iostream>
#include <string>
int main(int argc, char **argv)
{
std::string str;
for (int i = 1; i != argc; ++i)
str += std::string(argv[i]) + " ";
std::cout << str << std::endl;
return 0;
}
练习6.26
#include <iostream>
#include <string>
int main(int argc, char **argv)
{
std::string str;
for (int i = 1; i != argc; ++i)
str += std::string(argv[i]) + " ";
std::cout << str << std::endl;
return 0;
}
练习6.27
#include <iostream>
using namespace std;
int sum(initializer_list<int> il);
int main()
{
cout << sum({ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
return 0;
}
int sum(initializer_list<int> il)
{
int sum = 0;
for (auto beg = il.begin(); beg != il.end(); ++beg)
sum += *beg;
return sum;
}
练习6.28
const string&
练习6.29
应该使用常量引用类型。initializer_list对象中的元素都是常量,我们无法修改initializer_list对象中的元素的值
练习6.30
编译器错误信息:
练习6.31
当返回局部变量的引用时无效。当我们希望返回的对象被修改时,返回常量的引用无效。
练习6.32
合法,get函数返回数组各元素的引用
练习6.33
#include <iostream>
#include <vector>
using namespace std;
typedef vector<int>::const_iterator itc;
void print(itc first,itc last);
int main()
{
vector<int> ivec = { 0,9,8 };
print(ivec.cbegin(),ivec.cend());
return 0;
}
void print(itc first, itc last)
{
if (first == last)
return;
cout << *first << " ";
print(++first, last);
}
练习6.34
如果val小于0,则递归调用永远不会结束
练习6.35
val–返回改变前的值的副本,即一直传入相同的值来调用函数,函数永不结束
练习6.36
string (&func())[10];
练习6.37
- 类型别名:
using str_arr=string[10];str_arr& func(); - 尾置返回类型:
auto func()->string(&)[10]; - decltype关键字:
string s[10];decltype(s)& func();
尾置返回类型更好,更简洁明了
练习6.38
decltype(odd)& arrPtr(int i)
{
return (i % 2) ? odd : even;
}
练习6.39
- (a)非法,顶层const无法区分形参
- (b)非法,不允许两个函数除返回类型外其他所有的要素都相同
- (c)合法,接受一个double型指针,返回一个double型指针
练习6.40
- (a)合法
- (b)非法,一旦某个形参被赋予了默认值,它后面的所有形参都必须有默认值
练习6.41
- (a)非法,ht需要实参
- (b)合法
- (c)合法,但有违初衷,'*'会转换为int型赋给wd
练习6.42
#include <iostream>
#include <string>
using namespace std;
string make_plural(int ctr, const string &word, const string &ending = "s")
{
return (ctr > 1) ? word + ending : word;
}
int main()
{
cout<< make_plural(1, "success", "es") << " "
<< make_plural(1, "failure") << endl;
cout<< make_plural(2, "success", "es") << " "
<< make_plural(2, "failure") << endl;
return 0;
}
练习6.43
- (a)头文件,这是一个内联函数的定义
- (b)头文件,这是一个函数声明
练习6.44
inline bool is_shorter(const string &lft, const string &rht)
{
return lft.size() < rht.size();
}
练习6.45
一般来说,内联机制用于优化规模小、流程直接、频繁调用的函数
练习6.46
不能。constexpr函数的返回值类型及所有形参都得是字面值类型
练习6.47
#include <iostream>
#include <vector>
using namespace std;
using Iter = vector<int>::const_iterator;
#define NDEBUG
void print(Iter first, Iter last)
{
#ifndef NDEBUG
cout << "vector size: " << last - first << endl;
#endif
if (first == last)
return;
cout << *first << " ";
print(++first, last);
}
int main()
{
vector<int> vec{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
print(vec.cbegin(), vec.cend());
return 0;
}
练习6.48
不合理
练习6.49
候选函数:与被调用函数同名,其声明在调用点可见
可行函数:其形参数目与本次调用提供的实参数量相等,每个实参的类型与对应的形参类型相同,或者能转换成形参的类型
练习6.50
首先对这四个函数编号依次为1,2,3,4号
- (a)3号和4号,非法,二义性
- (b)2号和4号,合法,2号最匹配
- (c)3号和4号,合法,3号最匹配
- (d)3号和4号,合法,4号最匹配
练习6.51
#include <iostream>
using namespace std;
void f() { cout << 1 << endl; }
void f(int) { cout << 2 << endl; }
void f(int, int) { cout << 3 << endl; }
void f(double, double = 3.14) { cout << 4 << endl; }
int main()
{
f(2.56, 42);
f(42);
f(42, 0);
f(2.56, 3.14);
return 0;
}
练习6.52
- (a)类型提升
- (b)算术类型转换
练习6.53
- (a)合法
- (b)合法
- (c)非法,实参类型会忽略顶层const
练习6.54
int fun(int,int);
vector<decltype(fun)*> v;
练习6.55
#include <iostream>
#include <vector>
using namespace std;
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int multiply(int a, int b) { return a * b; }
int divide(int a, int b) { return b != 0 ? a / b : 0; }
int main()
{
int func(int, int);
vector<decltype(func)*> v;
v.push_back(add);
v.push_back(subtract);
v.push_back(multiply);
v.push_back(divide);
for (auto i : v)
{
cout << i(6, 2) << " "; // 8, 4, 12, 3
}
cout << endl;
return 0;
}
练习6.56
8, 4, 12, 3