学习笔记所用
本文部分内容参考了:C++Primer第五版——习题答案+详解(完整版)
6.1
见形参和实参的区别是什么
1、函数定义方式不同
形参出现在函数定义中,在整个函数体内都可以使用, 离开该函数则不能使用。
实参出现在主调函数中,进入被调函数后,实参变量也不能使用。
2、使用原理不同
函数的形参列于函数声明中,在函数定义的函数体内使用。当函数调用时,形参(任何种类的)是一类将被填充的空白或是占位符。
实参是用来填充形参的。当函数被调用时,形参列在函数名后面的括号里。执行函数调用时,实参被传递给形参。
3、传值调用和引用调用不同
传值调用和引用调用指的是用于参数传递过程中的一种机制。传值调用中,只使用了实参的值。传值调用机制里,形参是一个局部变量,其初始值为相应实参的值。在引用调用机制里,将实参的地址传递给形参,从表面上看是以实参变量取代形参,因此任何发生在形参上的改变实际上都发生在实参变量上。
6.2
a: 函数类型与return返回的参数类型不对应
b: 缺少函数类型
c: 形参名不能相同
d: 缺少花括号'{}'
6.3
#include
using namespace std;
int fact(int n) {
if (n <= 1) return 1;
int x = 1;
for (auto i = 2; i <= n; i++) {
x *= i;
}
return x;
}
int main()
{
cout << fact(5);
return 1;
}
6.4
#include
#include
using namespace std;
int fact(int n) {
if (n <= 1) return 1;
int x = 1;
for (auto i = 2; i <= n; i++) {
x *= i;
}
return x;
}
int main()
{
int sr;
string s;
do {
cout << "请输入一个数: ";
cin >> sr;
cout << "阶乘为:" << fact(sr)<<endl;
cout << "是否继续?继续请输入y" << endl;
cin >> s;
} while (s[0]=='y');
return 1;
}
6.5
#include
#include
using namespace std;
int jdz(int n) {
return (n>=0)?n:(-n);
}
int main()
{
int sr=-5;
cout << jdz(sr);
return 1;
}
6.6
解释形参、局部变量和静态局部变量的差别
(1)形参的作用域为整个函数体,而普通(非静态)局部变量和静态局部变量的作用域为:从定义处到包含该变量定义的块的结束处。
(2)形参由调用函数时所传递的实参初始化;而普通(非静态)局部变量和静态局部变量通常用初始化式进行初始化,且均在程序执行流程第一次经过该对象的定义语句时进行初始化。静态局部变量的初始化在整个程序执行过程中进行一次。
(3)形参和普通(非静态)局部变量均属自动变量,在每次调用函数时创建,并在函数结束时撤销;而静态局部变量的生命期却跨越了函数的多次调用,它在创建后直到程序结束时才撤销。
6.7
#include
#include
using namespace std;
int jdz() {
static int i = -1;
i++;
if (i == 0) return 0;
else return i;
}
int main()
{
for (int i = 0; i < 10; i++)
{
cout << jdz() << endl;
}
return 1;
}
6.8
//头文件
#pragma once
#include
#include
using namespace std;
int fact(int n);
int jdz(int n);
//源文件
#include
#include
#include "Chapter6.h"
using namespace std;
int jdz() {
static int i = -1;
i++;
if (i == 0) return 0;
else return i;
}
int fact(int n) {
if (n <= 1) return 1;
int x = 1;
for (auto i = 2; i <= n; i++) {
x *= i;
}
return x;
}
int main()
{
return 1;
}
6.10
#include
#include
using namespace std;
void jh(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main()
{
int a = 1, b = 2;
cout << "a=" << a << "b=" << b << endl;
jh(&a, &b);
cout << "a=" << a << "b=" << b;
return 1;
}
6.11
#include
#include
using namespace std;
void reset(int &a) {
a = 0;
}
int main()
{
int a = 1;
reset(a);
cout << a;
return 1;
}
6.12
#include
#include
using namespace std;
void jh(int &a, int &b) {
int temp = a;
a = b;
b = temp;
}
int main()
{
int a = 1, b = 2;
cout << "a=" << a << "b=" << b << endl;
jh(a, b);
cout << "a=" << a << "b=" << b;
return 1;
}
//引用的方法更好:1.传入的实参不需要传入地址。2.在函数体修改时也不需要解引用。3.也更容易与不修改实参值区分开,需要修改就加引用,不需要就不加。
6.13
//第一个是值传递,在函数修改,实参不会改变。
//第二个是引用传递,在函数体修改,实参也会跟着改变。
6.14
实参如果是常量就不可以使用引用类型。
如果是变量,使用不使用引用,看目的是否要修改实参的值。
6.15
我们在函数体不想要修改s,所以s是常量引用,与之想法occurs是普通引用
s是引用类型是避免拷贝,occurs是为了修改实参
s如果是普通引用,没有问题
occurs是常量引用会发生错误,达不成目的。
6.16
传入的s是普通引用
优点:可以修改实参。
缺点:会限制函数所能接受的实参类型。完善方法:把他改为常量引用。
6.17
#include
#include
#include
using namespace std;
bool pd(const string &s) {
for (auto i : s) {
if (i >= 'A' && i <= 'Z') return true;
}
return false;
}
void tolow(string &s) {
int jl = 'A' - 'a';//求出来A到a的距离
for (auto &i : s) {
if (i >= 'A' && i <= 'Z') {
i -= jl;
}
}
}
int main()
{
string s="adASddsVDad";
tolow(s);
cout << s;
return 1;
}
6.18
bool compare(const matrix m1,const matrix m2);
vector<int>::iterator change_val(int i,vector<int>::iterator i);
6.19
a: 不合法,参数数量不对应
b: 合法
c: 合法
d: 合法
6.20
不需要改变实参的值的时候应该是常量引用。
1:会给函数的调用者一个误导,认为函数可以修改它的实参的值。
2:会限制函数所能接受的实参类型。
3:在调用该函数的时候有可能发生错误。
6.21
#include
using namespace std;
int bj(int a, int* b) {
return(a > (*b)) ? a : (*b);
}
int main()
{
int a = 1, b = 2;
cout << bj(a, &b);
return 1;
}
6.22
#include
using namespace std;
void bj(int *(&a), int* (&b)){
int* temp = a;
a = b;
b = temp;
}
int main()
{
int a = 1, b = 2;
int* pa = &a, * pb = &b;
bj(pa, pb);
cout << *pa << *pb;
return 1;
}
6.23
void print(int .int [2]);
6.24
没有问题,循环输出长度为10的整形数组的值。
6.27
#include
#include
using namespace std;
void qh(initializer_list<int> a) {
int sum = 0;
for (auto i : a) {
sum += i;
}
cout << sum;
}
int main(int argc, char** argv)//实参列表
{
initializer_list<int> a = { 1,2,3 };
qh(a);
return 0;
}
6.28
string &;
6.29
不需要,应为initializer_list对象中的元素永远是常量值,不能修改。
6.30
“str_subrange”: 函数必须返回值
6.31
返回的引用不是指向函数外的变量都无效。
返回的引用不是指向函数外的常量都无效。
6.32
没有问题,输出0,1,2,3,4
6.33
#include
#include
#include
using namespace std;
int sv(vector<int>::iterator i, vector<int>::iterator e) {
if (i != e) {
cout << *i << " ";
return sv(++i, e);//注意是++i,不是i++
}
return 1;
}
int main(int argc, char** argv)//实参列表
{
vector<int> a = {1,2,3,4,5};
sv(a.begin(), a.end());
return 0;
}
6.34
结果是0
6.35
会先传入val,就会死循环,要么改为--val要么就是val-1;
6.36
string(& fun(vector<string> s))[10];
6.37
//1
typedef string ssS[10];
ssS& func();
//2
auto func()->string(&)[10];
//3
string s[10];
decltype(s) & func();
6.38
decltype(odd)& arrPtr(int i) {
return (i % 2) ? odd : even;
}
6.39
a: 非法
b: 非法,除了返回类型都一样。
c: 合理
6.40
b,一个形参被赋予默认值后,它之后的形参都要被赋予默认值。
6.41
a: 非法,没有给ht实参,它没有默认值
b: 合法
c: 合法但是初衷不同,初衷是想把'*'赋值给bckgrnd,实际赋值给了wd
6.43-6.48
感觉自己是个菜鸡(逃),大佬写的很好,可以看一下。C++Primer第五版 第六章习题答案(41~50)
6.49
候选函数:本次调用对应的重载函数集中的函数。
特征:1. 与被调用的函数同名。2. 其声明在调用点可见
可行函数:从候选函数中选出能被这组实参调用的函数。
特征:1.形参数量与本次调用提供的实参数量相等。(含有默认形参,去掉默认形参对应相等也可以)
2.每个实参的类型与之对应的形参类型相同。
6.50
a: 不合法,存在二义性
b: 合法
c: 合法
d: 合法
6.51
#include
#include
#include
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(int argc, char** argv)
{
f();
f(2);
f(1, 3);
f(2.1, 3.2);
return 0;
}
6.52
a: 3 类型提升
b: 4 类型转换
6.54
#include
#include
#include
using namespace std;
//1
int sy(int, int) {
return 1;
}
typedef decltype(sy)* psy;
int main(int argc, char** argv)
{
vector<psy> a;
return 0;
}
6.55-6.56
#include
#include
#include
using namespace std;
//1
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; }
typedef int(*psy)(int a, int b);
int main(int argc, char** argv)
{
vector<psy> a = { add,subtract,multiply,divide };
for (auto i : a) {
cout << i(4, 2) << endl;
}
return 0;
}