个人练习可能有误,勿要全信,请实践检验。
练习6.7:编写一个函数,当它第一次被调用时返回0,以后每次被调用返回值加1.
#include <iostream>
using namespace std;
//练习6.7:编写一个函数,
//当它第一次被调用时返回0,以后每次被调用返回值加1.
unsigned int func() {
//静态局部变量---直到程序消亡才消亡
static unsigned int callCount = 0;
return callCount++;
}
int main() {
int i = 2;
while (i--) {
cout << "func函数被调用次数:"
<< func()
<<endl;
}
cout << "输入任意字符后按回车继续:";
char var;
while (cin >> var) {
cout << "func函数被调用次数:"
<< func()
<< "输入ctrl+z结束"
<< endl;
}
return 0;
}
#ifndef CHAPTER6_H_INCLUDED //if not define 用于防止二次包含头文件
#define CHAPTER6_H_INCLUDED
/...../
#endif //!CHAPTER6_H_INCLUDE
在头(.h)文件中进行声明 .cpp 文件中进行实现
练习6.10 编写一个函数,使用指针形参交换两个整数的值。在代码中调用该函数并输出交换后的结果,以验证函数的正确性。
#include <iostream>
using namespace std;
/*
练习6.10 编写一个函数,使用指针形参交换两个整数的值。
在代码中调用该函数并输出交换后的结果,以验证函数的正确性。
*/
void swapIntNuM(int *Num1,int *Num2) {
int temp = 0; //用于暂时存储
temp = *Num1;
*Num1 = *Num2;
*Num2 = temp;
}
int main() {
int testNum1 = 0, testNum2 = 9;
cout << "交换之前数1和数2: "
<< testNum1 <<" " << testNum2 << endl;
//函数形参所使用的是指针,因此要使用取址符
swapIntNuM(&testNum1, &testNum2);
cout << "交换之后数1和数2: "
<< testNum1 << " " << testNum2 << endl;
return 0;
}
(时间:22/12/26 晚,写博客的第一步)
练习6.11 编写并验证自己的reset函数
void reset(int& ip)
{
ip = 0;
}
int main() {
int testNum = 25;
reset(testNum);
cout << testNum;
return 0;
}
练习 6.12 改写6.10 指针改成引用
void swapIntNuM(int &Num1,int &Num2) {
int temp = 0; //用于暂时存储
temp = Num1;
Num1 = Num2;
Num2 = temp;
}
练习 6.13 T是某类型的名字,说明一下两个声明的区别:一个是void f(T) ,另一个是void f(T&)
前者传值参数,后者是传引用参数。 前者函数内无法对外部的实参产生影响,后者可以。
练习 6.14 举一个形参应该是引用类型的例子,在举一个形参不能是引用类型的例子。
当需要对实参产生修改的情况,需要使用引用类型,如练习6.12,还可以避免传值可能产生的拷贝构造调用的资源开销或大量赋值的情况(例如string),最后还可以用其返回值。
其它情况,例如算数运算一类可以使用传值参数。
练习 6.15
练习 6.16
未加const,意味着函数内程序可以修改s,同时传参数时受到限制,无法将常量字符串、const对象 传给普通引用参数
Bool is_empty(const string &s) {return s.empty();}
练习 6.17 编写一个函数,判断string对象中是否含有大写字母。编写另一个函数,把string对象全都改成小写形式。
for (auto c : str) c++11 特性 :auto 自动获取类型;for range 在范围内for循环;
第一个使用const因为string字符串不需要改变
第二个需要对string字符串进行改变
#include <iostream>
using namespace std;
bool is_Upper(const string& str)
{
for (auto c : str) {
if (isupper(c)) return true;
}
return false;
}
bool str_ToLower( string& str)
{
for (auto &c : str) {
c = tolower(c);
}
return true;
}
int main() {
string testStr = "Hello,Fighting.";
if (is_Upper(testStr)) {
str_ToLower(testStr);
}
cout << testStr << endl;
return 0;
}
练习 6.18
bool compare(matrix &ma1,matrix &ma1)
//以某种方式比较这matrix两个的参数,并返回结果
Vector<int>::iterator change_val(int val,vector<int>::iterator vec )
//修改迭代器所指位置的值,返回一个迭代器
- (a)不合法,参数过多 (b)合法,两个参数均符合 (c)合法,自动转换 (d)合法,前两个都相对应,第三个强行转化后出现误差。
练习 6.20 当需要对实参进行修改,形参使用普通引用类型。当实参不需要修改时,形参最好使用const进行限定,好处在于防止误修改,同时可以接受const限定的对象或类型和字面常量。
(22/12/27 晚 有所收获,从现在开始做就不算晚,别再左右看,勉励向前)
练习 6.21 编写一个函数,令其接受两个参数:一个是int型,另一个是int指针。函数比较int和int指针所指向的值,返回较大的那个。
#include <iostream>
using namespace std;
int comp(int num1, int* num2) {
return num1 > *num2 ? num1 : *num2;
}
int main() {
int a = 1, b = 32;
cout << comp(a,&b) << endl;
return 0;
}
练习 6.22: 编写一个函数,令其交换两个int指针。
#include <iostream>
using namespace std;
void swap(int **p, int **q) { //可以用引用 int* &
int* temp; //交换两个指针所指向的值
temp = *p;
*p = *q;
*q = temp;
}
int main() {
int a = 1, b = 32;
int* p,*q;
p = &a;
q = &b;
cout << q<<" "<<p << endl;
swap(&q, &p);
cout << "交换后" << endl;
cout << q << " " << p << endl;
return 0;
}
练习 6.23
练习 6.24
打印int类型容量为10的数组。操作存在危险,在传入过大数组的时候,无法完整输出数组,而传入的数组较小时(即小于10个的范围),则会产生越界操作。可以将增添一位形参,用于操作者直接给出数组大小。
练习 6.25 编写一个main函数,令其可以接受两个实参。把实参内容连接成一个string对象并输出出来。
#include <iostream>
using namespace std;
int main(int argc ,char **argv) {
string str;
for (int i = 0; i != argc; i++) {
str += argv[i];
}
cout << str << endl;
return 0;
}
练习 6.26 编写一个程序,使其接受本节所示的选项;输出传递给main函数的实参内容。
#include <iostream>
using namespace std;
int main(int argc ,char **argv) {
for (int i = 0; i != argc; ++i) {
cout << "argv["<<i<<"]:"<<argv[i] << endl;
}
return 0;
}
练习 6.27 编写一个函数,它的参数是initializer_list<int> 类型的对象,函数功能是计算列表中所有元素的和。 initializer_list<T> 对象的值永远都是常量值,永不能改变;
#include <iostream>
using namespace std;
int sum(initializer_list<int> val) {
int sum = 0;
for (initializer_list<int>::iterator it = val.begin();
it != val.end(); it++) {
sum += *it;
}
return sum;
}
int main(int argc ,char **argv) {
//使用列表初始化的方式
cout << sum({ 1,2,3,4 }) << endl;
}
练习 6.29
练习 6.30 返回值为无,违反规则,再者存在还未开展功能就函数返回而结束的情况。
练习 6.31 什么情况下返回有效?什么情况下返回常量的引用有效?
返回的是已存在的元素则有效,如静态或全局变量,局部中临时变量因函数的结束将会消亡,因此返回此类引用将显得无效。
希望返回的对象不被修改时,可以返回对常量的引用。
(22/12/28 晚 不够努力,无严于律己)
合法;每次循环将get函数所返回的引用(arry数组的元素)进行赋值。
练习 6.33 编写一个递归函数,输出vector对象的内容
#include <iostream>
#include <vector>
using namespace std;
void func(vector<int>* vInt,vector<int>::iterator it) {
if (vInt->end() != it) {
cout << *it << endl;
func(vInt, ++it);
}
}
int main(int argc ,char **argv) {
vector<int> vc1 = {1,2,3,4,5};
func(&vc1, vc1.begin());
}
练习6.34 函数形参若获取为负数,将直接返回零,若改为题中所设将不会停止递归。
练习 6.35
练习 6.36 编写一个函数声明,使其返回数组的引用并且该数组包含10个string对象。不用使用尾置返回类型、decltype或类型别名
String (&func()) [10]
练习 6.37
typedef string arr[10];
arr& func();
auto func() -> string(&) [10]
String str[10]
decltype(str) &func()
练习 6.38
decltype(odd) &arrPtr(int){
return (i%2)?odd:even;
}
- 第二个声明非法,无法与第一个区别开来
- 第二个声明非法,无法与第一个区分出来,需要形参有区别。
- 两者是重载关系。
当前面的是有默认参数后面必须也使用默认参数。
a非法,无添加参数,至少需要一个(b) 合法使用了前两个,第三个为默认的
(c)合法,但是第二个参数由字符转化为int型
(22/12/29 晚 加油啊,还不算老咧)
练习 6.43 你会把下面的那个声明和定义放在头文件中?哪个放在源文件中?为什么?
内联函数的声明和定义应该放在头文件中,因为内联函数的定义对编译器必须是可见的。
函数声明应该在头文件。
练习 6.44 只需要在普通函数的前面加入inline,即设为内联函数。内联函数在在编译时将会展开,从而节省函数调用的开销。
练习 6.45 何时适合使用内联函数?
当某个普通函数代码小且使用频繁时较为适合使用内联函数,以省去函数调用的开销。
练习 6.46 constexpr函数:函数的返回类型以及所有形参的类型都得是字面值类型,而且函数体中必须有且只有一条return语句;
无法构成一个常量表达式
练习 6.47 vInt.size();
练习 6.48 assert(expr) ; 首先对expr求值,如果表达式为假,输出信息并终止程序的运行,若为真,则什么都不做。常用于检查“不能发生”的情况
用户向字符串s进行输入操作并判断是否与sought相等,等有输入且s不等于sought时一直循环。
练习 6.49 程序中有许多重载函数,当我们在调用时需要进行函数匹配。第一步选定本次调用对应的重载函数集,集合中的函数被称为候选函数。候选函数:与被调用函数同名,其声明在调用点可用。可行函数:形参和实参数目相同,类型相同或者可以进行转换。
练习 6.50 编译面对具有二义性的函数调用时将会拒绝,若有最佳匹配就调用最佳匹配(形参数量和类型都匹配),没有就选择没有二义性的可行函数。
练习 6.51 输出相对应形参的数量和类型即可。
练习 6.52 匹配等级:精确匹配、const匹配、类型提升匹配、算数类型转化、类类型转换
练习 6.53 说明下列每组声明中的第二条语句会产生什么影响,指出哪些不合法(如果有的话)
- 进行const限制,函数内无法改变所引用参数的值。合法,引用类型的形参是否引用的常量,属于底层const,可以区分。
- 合法,形参是否指向了常量,属于底层const。
- 非法,是指针类型的形参本身是否为常量,属于顶层const无法区分两个函数。
(22/12/30 晚 是不是效率有些低了)
练习 6.54 编写函数的声明,令其接受两个int形参并且返回类型也是int,然后声明一个vector对象,令其元素是指向该函数的指针。
int func(int,int);
vector<decltype(func ) *> vf;
#include <iostream>
#include <vector>
using namespace std;
int func(int a, int b) {
cout << a << " " << b << endl;
}
int main() {
vector<decltype(func)*> vF;
vector<int(*)(int, int)> vF2;
}
练习 6.55 编写四个函数 ,分别对两个int值执行加、减、乘、除运算,在前一题的基础上创建vector对象进行保存函数指针。
#include <iostream>
#include <vector>
using namespace std;
int func(int a, int b) {
cout << a << " " << b << endl;
return 0;
}
int func1(int a, int b) {
return a + b;
}
int func2(int a, int b) {
return a - b;
}
int func3(int a, int b) {
return a * b;
}
int func4(int a, int b) {
return a / b;
}
int main() {
vector<decltype(func)*> vF;
decltype(func) *p1 = func1;
int(*p2)(int, int) = &func2;
vF.push_back(&func1);
vF.push_back(p2);
vector<int(*)(int, int)> vF2;
vF2.push_back(&func3);
vF2.push_back(&func4);
}
练习 6.56调用上述vector对象中的每个元素并输出其结果。
练习 6.56调用上述vector对象中的每个元素并输出其结果。
#include <vector>
using namespace std;
int func(int a, int b) {
cout << a << " " << b << endl;
return 0;
}
int func1(int a, int b) {
return a + b;
}
int func2(int a, int b) {
return a - b;
}
int func3(int a, int b) {
return a * b;
}
int func4(int a, int b) {
return a / b;
}
int main() {
vector<decltype(func)*> vF;
decltype(func) *p1 = func1;
int(*p2)(int, int) = &func2;
vF.push_back(&func1);
vF.push_back(p2);
vector<int(*)(int, int)> vF2;
vF2.push_back(&func3);
vF2.push_back(&func4);
cout << vF[0](3, 4) << endl;
cout << vF[1](3, 4) << endl;
for (auto p : vF2) {
cout << p(3, 4) << endl;
}
}
(22/12/31 晚 好好学习最好的时间或许实在十年前,但如今只能退而求其次,其次就是今天。)
喝好鸡汤,吨吨吨。
走在路上,不断准备,抓好机会。