第六章 函数
练习6.1
形参是定义函数的时候使用的参数,是用来接收调用这个函数时所传递的参数,这个参数就是实参。
练习6.2
//(a) 函数返回类型有误, string 型不能转化为 int 型
string f() {
string s;
//...
return s;
}
//(b) 没有指定返回类型
void f2(int i) { /*...*/ }
//(c) 形参不能有同名
int calc(int v1, int v2) { /*...*/ }
//(d) 函数的操作必须在一个语句块中
double square (double x) {
return x * x;
}
练习6.3
//输出一个数的小数部分
double fact (double x) {
x = x - static_cast<int>(x);
return x;
}
练习6.4
#include <iostream>
using namespace std;
long long fact (int x) {
long long an = 1;
while (x != 0)
an = an * x--;
return an;
}
int main(){
int x;
cin >> x ;
long long ans;
ans = fact(x);
cout << ans << endl;
return 0;
}
练习6.5
int abs(int x) {
return x > 0 ? x : -x;
}
练习6.6
形参和函数体内部定义的变量统称为局部变量。形参属于自动对象,在函数开始时申请空间,并被实参初始化,在函数结束时销毁。其他在函数内定义的普通变量在其定义时申请空间,若定义中不含初始值,则执行默认初始化,并在函数结束时销毁。而局部静态变量在程序第一次经过其定义语句时被创建,若没有被显式地初始化,则执行值初始化,但不受函数终止的影响,直到程序终止时才被销毁。
int ohayo (int x) {
int xx;
xx = x + 1;
static int wen = 1;
wen += xx;
return wen;
}
练习6.7
int wat () {
static int a = 0;
if (a != 0)
a = 0;
return a++;
}
练习6.8
//chapter6.h
int abs (int x);
long long fact (int x);
练习6.9
//fact.cc
#include "chapter6.h"
int abs(int x) {
return x > 0 ? x : -x;
}
long long fact (int x) {
long long an = 1;
while (x != 0)
an = an * x--;
return an;
}
//factmain.cc
#include <iostream>
#include "chapter6.h"
using namespace std;
int main(){
int x;
long long ans;
cin >> x;
x = abs(x);
ans = fact(x);
cout << ans << endl;
return 0;
}
练习6.10
#include <iostream>
using namespace std;
void swapp (int *a, int *b){
int temp;
temp = * a;
* a = * b;
* b = temp;
}
int main(){
int c,d;
cin >> c >> d;
swapp(&c, &d);
cout << c << ' ' << d << endl;
return 0;
}
练习6.11
void reset (int &i){
i -= i;
}
练习6.12
#include <iostream>
using namespace std;
void swapp (int &a, int &b){
int temp;
temp = a;
a = b;
b = temp;
}
int main(){
int c,d;
cin >> c >> d;
swapp(c, d);
cout << c << ' ' << d << endl;
return 0;
}
练习6.13
void f(T)
仅把实参的值传递给形参,函数中形参的任何改变都不会影响到实参。
void f(&T)
实参被引用传递给形参,实参与函数中的形参同变化。
练习6.14
%¥&……%&¥#¥#¥%@¥#@%¥#……
练习6.15
由于 s 是 string 类型, string 对象有可能比较长,应该避免拷贝,所以是引用类型,同时 s 在函数中不发生变化,所以是常量引用。同时,由于 s 是常量引用的类型,可以在函数调用时,用字面值初始化 s。
c 只是用来标记,所以只需要普通引用。
因为希望借助 occurs 来额外返回出现的次数,所以使用引用类型。
练习6.16
函数调用时,不能直接用常量字面值来初始化形参。
bool is_empty(const string &s) { return s.empty(); }
练习6.17
//判断是否含有大写字母
bool upperornot (const string &s) {
for (auto c : s) {
if (c >= 'A' && c <= 'Z')
return true;
}
return false;
}
//全改成小写形式
void todowner (string& s) {
for (auto &c : s) {
if (c >= 'A' && c <= 'Z')
c -= ('A' - 'a');
}
}
不一样,前者只需判断,不要求改变字符串,所以使用常量引用。
练习6.18
//(a)比较两个矩阵是否相等
bool compare (matrix &a, matrix &b);
//(b)迭代改变那某容器的元素
vector<int>::iterator change_val (int a, vector<int>::iterator b);
练习6.19
只有(a)不合法,calc函数声明时只有一个形参。
练习6.20
当某个形参可以使用 const 的时候,就尽量定义成常量引用 。这样可以避免形参错误地被改变。
练习6.21
int bigger (const int a, const int *b) {
return a > * b ? a : * b;
}
练习6.22
void swapp (const int * &p1, const int * &p2) {
int * temp;
temp = p1;
p1 = p2;
p2 = temp;
}
练习6.23
&#(@)#@#HHUF$V@GF@F!
练习6.24
数组会被转换成指针传递到函数中,所以形参中定义的数组的维度其实是无关的。因此不能直接在函数中的循环次数简单的设为10次,如果传递的数组中元素少于10个,就会输出无关的结果。
练习6.25 & 练习6.26
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char** argv)
{
string str;
cout << argc << endl;
for (int i = 0; i != argc; ++i) {
str += argv[i];
str += " ";
}
cout << str << endl;
}
练习6.27
int sumup (initializer_list<int> lis) {
int sum = 0;
for (auto c : lis)
sum += c;
return sum;
}
练习6.28
循环中的 elem 属于对字符串的常量引用。
练习6.29
看情况啊,如果 initializer_list 中的元素易于被拷贝,那么就不需要声明成引用类型。
练习6.30
(Code::Blocks)
..\temp.cpp|10|error: return-statement with no value, in function returning ‘bool’ [-fpermissive]|
练习6.31
返回局部对象的引用无效。
在返回常量引用时,若返回的是一个局部临时量,就无效。
练习6.32
合法。给 ia 数组的十个元素赋予与下标相等的值。
练习6.33
int outputvec (vector<int>::iterator vbeg, vector<int>::iterator vend) {
if (vbeg != vend) {
cout << * vbeg << endl;
outputvec(++vbeg, vend);
}
return 1;
}
练习6.34
如果输入的实参为正,则无影响。但如果输入的实参为负,则该函数会无限递归下去。
练习6.35
val– 表达式返回的仍是 val 的原值。
练习6.36
string (&func(string (&arr)[10])[10];
练习6.37
//使用类型别名
typedef string (&arr)[10];
arr func (arr in);
//使用尾置返回类型
auto func (arr in) -> string (&)[10];
//使用 decltype 关键字
string str[10];
decltype(str) &func (decltype(str) &in);
练习6.38
int odd[] = {1, 3, 5, 7, 9};
int even[] = {2, 4, 6, 8, 0};
decltype(odd) &arrptr(int i) {
return (i % 2) ? return odd : even;
}
练习6.39
(a) 和 (b) 不合法。(c) 合法。
练习6.40
(a)合法。
(b)不合法,wd 和 backgnd 都必须有默认实参。
练习6.41
(a)不合法。ht 没有默认实参,所以在调用时,声明 ht 对应的实参。
(b)合法合理。
(c)合法,但是与程序员初衷不符。 ’ * ’ 被传递给了 wd 。
练习6.42
#include <iostream>
#include <string>
using namespace std;
string make_plural(size_t ctr, const string &word,
const string &ending = "s") {
return (ctr > 1) ? word + ending : word;
}
int main()
{
cout << "single: " << make_plural(1, "success", "es") << ' '
<< make_plural(1, "failure") << endl;
cout << "plural: " << make_plural(2, "success", "es") << ' '
<< make_plural(2, "failure") << endl;
return 0;
}
练习6.43
都会放在头文件中。
练习6.44
inline bool isShorter(const string &s1, const string &s2) {
return s1.size() < s2.size();
}
练习6.45
¥%¥%¥#%%!#¥#%!¥#%!¥#%%!
练习6.46
不能。因为函数返回值时调用的 size 函数,该函数不是 constexpr 类型。
练习6.47
#include <iostream>
#include <string>
#include <vector>
//#define NDEBUG
using namespace std;
using iter = vector<int>::iterator;
int outputvec (iter vbeg, iter vend) {
#ifndef NDEBUG
cerr << "Size of the vec is " << vend - vbeg << "." << endl;
#endif // NDEBUG
if (vbeg != vend) {
cout << * vbeg << endl;
outputvec(++vbeg, vend);
}
return 1;
}
int main (void) {
vector<int> vec{1, 2, 3, 4, 5, 6, 7};
iter vbegin = vec.begin();
iter vend = vec.end();
outputvec(vbegin, vend);
return 0;
}
练习6.48
不合理啊,assert 函数应该在 while 循环里才有用。
练习6.49
候选函数是在函数调用时,被选中的重载函数集中的函数。
可行函数是在候选函数中能被调用中所提供的一组实参调用的函数。
练习6.50
(a) 不合法,二义性。
(b) void f(int);
(c) void f(int, int);
(d) void f(double, double = 3.14);
练习6.51
#include <iostream>
using namespace std;
void f(){
cout << "____" << endl;
}
void f(int) {
cout << "int" << endl;
}
void f(int, int) {
cout << "int, int" << endl;
}
void f(double, double = 3.14) {
cout << "double, double" << endl;
}
int main (void) {
//f(2.56, 42);
f(42);
f(42, 0);
f(2.56, 3.14);
}
练习6.52
(a) 通过类型提升实现的匹配。
(b) 通过算数类型转换实现的匹配。
练习6.53
(a) 合法。
(b) 合法。
(c) 不合法,两者的形参都对应 char * 类型的实参。
练习6.54 & 练习6.55 & 练习6.56
#include <iostream>
#include <vector>
using namespace std;
int func(int, int);
int add (int a, int b) {
return a + b;
}
int substract (int a, int b) {
return a - b;
}
int multiply (int a, int b){
return a * b;
}
int divide (int a, int b) {
return a/b;
}
int main (void) {
vector<decltype(func) * > vec{add, substract, multiply, divide};
for (auto f : vec)
cout << f(4, 3) << endl;
}