c++ Primer(第五版) 课后题答案(六)

6.1

       实参和形参的区别?
      形参在函数定义的形参表中进行定义,是一个变量,其作用域为整个函数。
      而实参出现在函数调用中,是一个表达式。
      进行函数调用时,用传递给函数的实参对形参进行初始化。


6.2

      (a)函数所定义的返回值类型是 int类型,而实际上return返回的表达式的类型是string
     类型,两个类型不同,而string类型又不能隐式转换为int类型。
修改:
string f()
           {
         string  s;
         //......
          return s;
            }
  (b) 因为该函数定义中没有指定的返回值类型,在标准C++中,定义函数时不指定返回值类型
 是非法的。
 修改:
 int f2(int i) {/*......*/ }
  (c) 任意两个形参都不能同名,而且缺少左花括号。
 修改:
 int calc(int v1, int v2) {/*.....*/ }
  (d)缺少一对括住函数体的花括号
 修改:
 double square(double x) { return x * x; }


6.3

#include

using namespace std;
int fact(int s,int s2)
{
	s += s2;
	s *= s2;
	return s;
}
int main()
{
	cout << "输入两个整数:" << endl;
	int num1, num2;
	cin >> num1 >> num2;
	int j = fact(num1, num2);
	cout << "j = " << j << endl;
	return 0;
}

6.4

     

#include 

using namespace std;

int fact(int val)
{
	int ret = 1;
	while (val>1)
	{
		ret *= val--;
		
	}
	return ret;
}
int main()
{
	cout << "Enter a number : " << endl;
	int  num = 0;
	cin >> num;
	int  j = fact(num);
	cout << num << "的阶乘为: " << j << endl;
	return 0;
}

6.5

 

#include

using namespace std;

int abs(int val)
{
	if (val >=0)
	{
		return val;
	} 
	else
	{
		return 0 - val;
	}
}
int main()
{
	cout << "输入任意一个整数: " << endl;
	int num1 = 0;
	cin >> num1;
	int num2 = abs(num1);
	cout << "|" << num1 << "|" << "=" << num2 << endl;
	return 0;

}

    

6.6

     解释形参,局部变量和静态变量的差别。
解答:
    从本质上说,三者均属于局部作用域中的变量,其中,局部变量又可分为普通(非静态)局部变量和静态局部变量。它们的差别在于:
    (1)形参的作用域为整个函数,而普通局部变量和静态局部变量的作用域为:从定义处到包含该变量定义的块的结束处。
    (2)形参由调用函数时所传递的实参初始化;而普通局部变量和静态局部变量通常用初始化式进行初始化,且均在程序执行流程第一次经过该对象的定义语句时进行初始化。静态局部变量的初始化在整个程序执行的过程中只进行一次。
   (3)形参和普通局部变量均属于自动变量,在每次调用函数是创建,并在函数结束时撤销;而静态局部变量的生命周期跨越了函数的多次调用,它在创建后直到程序结束时才撤销。
//例如 如果需要连续输出1到X之间的所有整数的阶乘  可用如下程序:

#include
using namespace std;
//用于辅助求阶乘的函数
int fac(int x)
{
    static int result = 1;    //静态变量
    result *= x;
    return result;
}

int main()
{
   int upLmt;       //upLmt为普通局部变量
   cout <<"Enter value of upper limit : "<> upLmt;
   //依次输出1到X之间的所有阶乘
   for(int i = 1;i <= upLmt; ++i)
       cout <

6.7

   

#include

using namespace std;
bool   fct()
{
	static int cnt = 0;	
	++cnt;
	/*if (cnt>1)
	{
	return 1;
	}
	else
	{
	return 0;
	}*/
	bool i = cnt > 1 ?  1: 0;
	return i;
}
int main()
{
	int i = 0;
	int cnt2 = 1;
	while (i <3)
	{
		if (fct()== 1)
		{
			cout << "函数调用 " << ++cnt2 << "次" << endl;
		}
		else
		{
			cout << "函数调用 1 次" << endl;
		}
		++i;
	}
	return 0;
}

6.10

#include

using namespace std;
int swp(int* p1, int* p2)        //该函数交换p1,p2所指的项
{
	int a = *p1;
	*p1 = *p2;
	*p2 = a;
	return 0;
}

int main()
{
	cout << "输入两个整数:" << endl;
	int num1, num2;
	cin >> num1 >> num2;
	swp(&num1, &num2);
	cout << "num1 = " << num1 << "num2 = " << num2 << endl;
	return 0;
}


6.11

#include

using namespace std;
int reset(int & r)            //将数字重置为0
{
	r = 0;
	return r;
}
int main()
{
	int val = 0;             //要重置的数字
	int preVal = 0;          //用于保存输入的数字
	cout << "Enter a number :" << endl;
	cin >> val;
	preVal = val;        //保存重置前的数字
	int val1 = reset(val);         //
		cout << preVal << "重置后: " << val1 << endl;
	return 0;
}

6.12

#include

using namespace std;
int swp(int &p1, int &p2)        //该函数交换p1,p2所指的项
{
	int a = p1;
	p1 = p2;
	p2 = a;
	return 0;
}

int main()
{
	cout << "输入两个整数:" << endl;
	int num1, num2;
	cin >> num1 >> num2;
	swp(num1, num2);
	cout << "num1 = " << num1 << "num2 = " << num2 << endl;
	return 0;
}

/*
   使用引用更容易使用些,容易理解。

*/

6.13

         void f(T)
         void f(&T)
        说明一下两种函数声明的区别:

        前者声明的是T类型的形参,在f中修改形参的值 不会影响调用f时所传递的实参的值。
        后置声明的是T类型的引用形参。在f中修改形参的值实际上相当于修改调用f时所传递的实参的值。


6.14

        什么时候将形参定义为引用形参?
      (1)如果希望通过函数调用修改实参的值,就应该将形参定义为引用类型。
      例如:
              void swap(int &v1,int &v2)
                       {
                        int tmp = v2;
                        v2 = v1;
                        v1 = tem;
                       }
    (2)除了以上这种函数外,为了一次函数调用获得多个结果值,也可以用引用形参。
     (3)另外,在向函数传递大型对象时,为了避免复制实参,以提高效率,以及无法复制的类类型(其复制构造函              数为 private的类类型)作为形参类型时,也应该将形参定义为引用形参。但这时候使用形参的目的是为了避              免复制实参,所以应该将形参定义为const引用。

     什么时候不应该将形参定义为引用形参?
        如果不需要通过函数调用修改实参的值,就不应该将形参定义为引用类型。
        例如,在求绝对值的函数abs中。形参就不宜定义为引用类型。


6.16

         bool is_empty(string& s) { return s.empty(); }
        其局限在于:此处用引用形参可以避免复制实参。但是没有将
        形参定义为const引用,从而导致不能使用字符串字面值来调用
        该函数。(因为非const引用形参只能与完全同类型的非const
         对象关联)。
        更正为:
        bool is_empty(const string& s){ return s.empty(); }


6.17

#include 
#include
#include

using namespace std;

bool capital(const string& str)     //函数判断字符串中是否含有大写字母
{
	bool rember_bool = false;
	for (auto &c :str)             //用范围for遍历字符串
	{
		if (1 == isupper(c))
		{
			rember_bool = 1;
			break;
		}
	}
	return rember_bool;
}
string lwr(string& str)         //函数将大写字母转化为小写字母
{
	for (auto &c : str)
		c = tolower(c);
	return str;                //返回string类型
}
int main()
{
	string s1 ;
	cout << "Enter a string : " << endl;
	cin >> s1;
	cout << ((capital(s1) == 1 )? "字符串中含有大写字母" : "字符串不含有大写字母" )<< endl;
	cout << s1 << " 大写转化成小写后的形式: " << lwr(s1) << endl;
	return 0;
}

6.18

#include
#include
using namespace std;

//比较两个MaMatrix类型变量的大小关系
bool compare(Matrix &,Matrix&);

//改变相应的变量的数值
vector::iterator change_val(int, vector::iterator);
int main()
{
	return 0;
}


6.19

double calc(double);
int count(const string&, char);
int sum(vector::iterator, vector::iterator, int);
vector vec(10);

(a)calc(23.4, 55.1);
(b)count("abcde", 'a');
(c)calc(66);
(d)sum(vec.begin(), vec.end(), 3.8);

(b)(c)(d)都合法。
(a)不合法。cala函数只有一个形参,而调用该函数值却传递了两个实参

6.20

          引用形参什么时候应该是常量引用?如果形参应该是常量引用,而我们设为普通引用,会发生什么情况?
          一:(1)如果函数无需改变引用形参的值,最好将其定义为常量引用。
                 (2)如果使用常量引用形参,函数所能接受的实参类型将加大。例如:可以把
                          const对象,字面值,或者需要类型转换的对象传递给常量引用形参。
         二:   把函数不会改变的形参定义成普通引用,会给函数的调用者一种误导,即函数可以修改它的实参的值。此                     外,使用引用而非常量引用也会极大地限制函数所能接受的实参的类型。
                    例如:不可以把const对象,字面值,或者需要类型转换的对象传递给普通的引用形参。


6.21

   

int compare(int val, const int *pval)
{
	return ((val > *pval) ? val : *pval;)
}

/*该函数无需修改指针形参所指向的值,因此,为了保护指针形参
所指向的值,将指针形参定义为指向const对象的指针。*/

6.22

void  swap(int * x,int *y)
{
	int temp;
	temp = *x;
	*x = *y;
	*y = temp;
}

6.23

#include
using namespace std;

//void print( int[]);
//void print( int[2]);
int  print( int* val)
{
	return *val * 2;
}
int main()
{
	int i = 0;
	int j[2] = { 0, 1 };
	int k = print(&i);
	int l = print(j);
	cout << "i = " << k<< endl;
	cout << "j[0] =" << l << endl;
	return 0;
}


6.24

           描述下面这个函数的行为。如果代码存在问题,请指出并改正

void print(const int ia[10])
{
	for (size_t i = 0; i != 10; i++)
	{
		cout << ia[i] << endl;
	}
}

          给 print函数的是一个数组,实参自动的转换成指向数组首元素的指针。然后再被调函数print中,通过for循环
          遍历每个值。
          存在问题:print(const int ia[10]) 这里的维度表示我们期望数组含有多少元素,实际上不一定。当实参是一个二           维数组 

          如:j[2] = { 0, 1 };
          此时,调用print(j)函数就会错误。,因为实参不是含有十个整数的数组。


6.26

 

#include
using namespace std;
int main(int argc, char **argv)
{
	cout << "arguments passed to main(): " << endl;
	for (int i = 0; i != argc;++i)
	{
		cout << argv[i] << endl;
	}
	return 0;
}

6.27

#include
#include
using namespace std;
int sum( initializer_list i)    //函数对所有元素进行相加
{
	int cnt = 0;
	for (auto &c:i)
	{
		cnt += c;
	}
	return cnt;
}
int main()
{
	initializer_list int_list{1, 2, 3, 4,5};
	cout << "列表中所有元素的和为: " << sum(int_list) << endl;
	return 0;
}


6.28

         const int &类型变量


6.29

        在范围for循环中使用initializer_list对象时,应该将循环变量声明成引用类型。

        这是因为考虑到复制实参的问题,声明成引用,可以避免复制实参,提高了效率。

6.30

        

#include
#include
#include

using namespace std;

bool str_subrange(const string &str1,const string &str2)
{
	if (str1.size() == str2.size())
	{
		return str1 == str2;
	}
	auto size = (str1.size() < str2.size()) ? str1.size() : str2.size();
	for (decltype(size) i = 0; i != size; ++i)
	{
		if (str1[i] != str2[2])
			return;                     //没有返回值,编译器报告这一错误
	}

}
int main()
{
	return EXIT_SUCCESS;
}

6.31

         什么情况下返回的引用无效,什么情况下返回常量的引用无效?
         解答:
        (1)当返回局部对象的引用时,返回的引用无效。因为,当函数结束时,局部对象和临时对象所占用的空间也                    就随之释放掉了,所以返回引用指向一个不再可用的内存空间。
       (2)当我们希望返回的对象被修改时,返回的常量引用无效。

6.32

      

#include 
#include

using namespace std;
int &get(int *arry, int index)      //函数合法
{
	return arry[index]; 
}

int main()
{
	int ia[10];
	for (int i = 0; i != 10; ++i)                //修改返回的对象的值
	{
		get(ia, i) = i;
	}
	for (int i = 0; i != 10; ++i)
	{
		cout << ia[i] << endl;
	}
	return EXIT_SUCCESS;
}

6.33

     

#include

using namespace std;

//递归函数,输出vector对象的内容
vector vec(const vector& vec_str,vector::iterator iter)
{
	
	if (iter != vec_str.end())
	{
		cout << *iter << endl;
		return vec(vec_str, iter + 1);
	}
	return{};                     //返回一个空vector对象
}
int main()
{
	vector  str{"Hello","World"};
	vec(str, str.begin());
	return EXIT_SUCCESS;
}

6.34

       如果函数factorial的终止条件为:
        if(val != 0)
       会发生什么情况?

       解答:
      会出现这样问题,如果实参为负数X,则理论上该函数会求得X*(X-1)*....*(int型能表示的最小负数)*(int型能表示         的最大正数)*(int型能表示的最大正数-1)*....*1这样的结果,但实际上运行时会因为递归函数调用次数过多而         发生程序栈溢出。使得程序无法继续执行。
      而当实参为负数时,原factorial函数求得的结果应该为1.


6.35

      

//当传入的值是 val--时,程序运行错误。
//出现死循环。
//如:相当于val = val-- ;
//    val的值保持不变。
//
#include

using namespace std;

int factorial(int val)
{
	if (val >1)
	{
		return factorial(val--) * val;
	}
	return 1;
}
int main()
{
	int num = 0;
	cin >> num;
	cout << factorial(num) << endl;
	return 0;
}


6.36   不知道如何写   求告诉




6.37

     

#include
#include
#include
using namespace std;
string arr[10];
//string(&arrRef)[10] = arr;
//类型别名
string (& func())[10];
//尾置返回类型
auto fun()->string (&)[10];
//decltype关键字
decltype(arr) &f();
int main()
{
	return EXIT_SUCCESS;
}


6.38

       

#include
#include

using namespace std;

//返回数组的引用
int odd[] = { 1, 3, 5, 7, 9 };
int even[] = { 0, 2, 4, 6, 8 };
decltype(odd) &arrPtr(int i)
{
	return (i % 2) ? odd : even;
}

//decltype(odd) *arrPtr(int i)
//{
//	return (i % 2) ? &odd : &even;     //返回一个指向数组的指针
//}
int main()
{
	return EXIT_SUCCESS;
}

6.39

       (a) int calc(int, int);

            //计算两个数的值,
           //因为const为顶层,所以重复声明了int calc(int, int);
                 int calc(const int, const int);    
           ( b) int get();
            //返回一个double类型。 
            //重复声明了int get();
               double get();
           (c) int *reset(int *);
               //将double类型的指针所指的变量的值重置,返回double类型的指针
              //两个函数为重载函数

       double *reset(double *);


6.40

     下面的哪个声明是错误的?为什么?
 (a) int ff(int a, int b = 0, int c = 0);
 (b)   char *init(int ht = 24, int wd, char backgrnd);


 (b)的声明有错误  
    原因:一旦某个形参被赋予了默认值,它其后的所有形参都必须有默认值


6.41


//char *init(int ht, int wd = 80, char backgrnd = ' ');
//(a)  init();
//(b)  init(24,10);
//(c)  init(14,'*');
//
//(a)不合法,因为调用函数时必须显式指定至少一个实参
//(b)调用合法,也完全符合程序猿的初衷
//(c)调用合法,但是不符合程序员的初衷。‘*’是一个char类型,可以转化成 int类型在传递给形参wd.


6.42

    

#include
#include

using namespace std;

//如果ctr不为1则返回word的复数版本
string make_plural(size_t ctr, const string &word,
	                           const string &ending = "s")
{
	return (ctr = 1) ? word : word + ending;
}
int main()
{
	cout << "Singular version: " << make_plural(1, "success", "es")
		<< "\t\t plural version: "
		<< make_plural(0, "success", "es") << endl
		<< "Singular version: " << make_plural(1, "failure")
		<< "\t\t plural version: "
		<< make_plural(0, "failure") << endl;
	return 0;
}

6.43

你会把下面哪个声明和定义放在头文件中?哪个放在源文件中?为什么?


(a) inline bool eq(const BigInt&, const BigInt&){.....};
(b) void putValues(int *arr,int size);


二者均应放在头文件中。
(b)是函数声明,适合放在头文件中。
(a)虽然是一个函数定义,但这是一个内联函数定义,应该放在头文件中。因为:内联函数的定义对编译器而言必须是可见的,以便编译器能够在调用点内联展开函数的代码,这样一来,仅有函数的原型是不够的。而且内联函数有可能在程序中定义不止一次,这时必须保证在所有源文件中,其定义是完全相同的。把内联函数的定义放在头文件中,可以确保在调用函数时所使用的定义是相同的,并且保证在调用点该函数的定义对编译器是可见的。


6.44

#include

using namespace std;

inline bool isShorter(const string &s1, const string&s2)
{
	return s1.size() < s2.size();
}
int main()
{
	return 0;
}

6.49

  什么是候选函数?什么是可行函数?
解答:
     候选函数是指调用点上其声明是可见的而且与被调函数同名的函数。
可行函数是指从候选函数中选出的函数,必须满足下列条件:函数的形参数目与该函数调用实参数目相同,每个实参类型必须与对应形参的类型匹配,或者可以隐式转换成对应形参的类型。


6.50

(a)可行函数是void f (int,int)和 void f(double,double = 3.14).该调用不合法。存在二义性。即可将2.56转换为 int 型而调用前者,亦可将42转换为 double型而调用后者。
(b)可行函数是 void f(int) 和 void f(double, double = 3.14).该调用合法。最佳匹配函数是 void f(int)。
(c)可行函数是 void f(int ,int )和 void f(double, double = 3.14).调用合法,最佳匹配函数是void f(int ,int )
(d)可行函数是 void f(int ,int )和 void f(double, double = 3.14).调用合法,最佳匹配函数是void f(double, double = 3.14)


6.51

#include

using namespace std;
void f()
{
	cout << "调用函数为  void f();  " << endl;
}
void f(int)
{
	cout << "调用函数为  void f(int);  " << endl;
}
void f(int, int)
{
	cout << "调用函数为  void f(int , int);  " << endl;
}
void f(double, double = 3.14)
{
	cout << "调用函数为  void f(double, double = 3.14);  " << endl;
}
int main()
{
	/*f(2.56, 42);*/
	f(42);
	f(42, 0);
	f(2.56, 3.14);
	return 0;
}


6.52

(a)通过类型提升(实参由char 型转换为 int 型)实现匹配
(b)通过标准转换(实参由 double 型转换为 int 型)实现匹配


6.53

//(a)(b第二个声明的效果是:声明了一个重载的calc函数
(a) int calc(int&, int&);
int calc(const int&, const int&);
(b) int calc(char*, char*);
int calc(const char*, const char*);
//(c)中第二个的声明是对第一个的重复声明。因为当形参以副本传递(即按值传递)
//     时,不能基于形参是否为const来实现函数重载
(c) int calc(char*, char*);
int calc(char* const, char* const);

6.54

#include
#include

using namespace std;

int faction(int, int);



int main()
{
	
	using pf = int(*)(int, int);
	vector  vect;
	return 0;
}


6.55-----6.56

 

#include
#include

using namespace std;

//加法函数
int count_add(int val1, int val2)
{
	/*cout << "进行加法运算,输入两个整数: " << endl;
	cin >> val1 >> val2;*/
	return val1 + val2;
}
//减法函数
int count_sub(int val1, int val2)
{
	return val1 - val2;
}
//乘法函数
int count_mul(int val1, int val2)
{
	return val1*val2;
}
//除法函数
int count_div(int val1, int val2)
{
	return val1/val2;
}



int main()
{
	using pf = int(*)(int, int);      //pf 是指针类型
	vector  vect{ count_add, count_sub, count_mul, count_div };
	for (auto &c : vect)
	{
		cout << c(4,2) << endl;
	}
	return 0;
}
























你可能感兴趣的:(c++,Primer,课后题答案(更新中。。。。))