c++ primer第五版----学习笔记(六)

1.return语句

  • 返回return语句中的值(如果有的话)
  • 将控制权从被调函数移回主调函数

2.局部对象

  • 名字的作用域。是程序文本的一部分,名字在其中可见。
  • 对象的生命周期是程序执行过程中该对象存在的一段时间

(1)自动对象:只存在于块执行期间的对象

(2)局部静态对象:在程序的执行路径第一次经过对象定义语句时初始化,并且直到程序终止时才被销毁,在此期间即使对象所在的函数结束执行也不会对它有影响

size_t count_calls()
{
    static size_t ctr = 0;    //调用结束后,这个值仍然有效
    return ++ctr;
}
int main()
{
    for (size_t i = 0;i != 10;++i)
    {
        cout << count_calls() << endl;
    }
}

3.参数传递:每次调用函数时都会重新创建它的形参,并于传入的实参对形参进行初始化

  • 指针形参:指针使我们可以间接的访问它所指的对象,所以可以通过指针修改它所指对象的值
//该函数接受一个指针,然后将指针所指的值置为0
void reset(int *ip)
{
    *ip = 0;  //改变指针ip所指对象的值
    ip = 0;   //只改变ip的局部拷贝,实参并未改变
}


int i = 42;
reset(&i);                //改变i的值而非i的地址
cout << "i = " << i << endl;   //输出i = 0

  • 使用引用形参:1.改变实参的值;2.防止对象被拷贝;3.如果函数无须改变引用形参的值,最好将其声明为常量引用;4.使用引用返回额外信息
  • const形参和实参:
//1.当形参含有顶层const时,传给它常量对象或者非常量对象都可以(忽略顶层const)
//忽略顶层const带来的问题
void fcn(const int i) {/*fcn能够读取i,但是不能向i写值)*/}
void fcn(int i) {/*.....*/}  //错误:重复定义了fcn(int)

//指针或引用形参与const
//2.调用函数时,传入的实参要与函数的形参相匹配

//3.尽量使用常量引用(使用引用而非常量引用也会极大地限制函数所能接受的实参类型)

  • 数组形参:
// 1.标记指定数组长度(要求数组本身包含一个结束标记)
void print(const char *p);
//2.标准库规范(传递指向数组首元素和尾元素的指针)
void print(const int *beg, const int *end);
//3.传递一个表示数组大小的实参(专门定义一个表示数组大小的形参)
void print(const int a[], size_t size);
//4.数组形参和const(通常定义成指向const的指针,当函数要改变元素值时,才定义成指向非常量的指针
//5.数组引用形参
void print(int (&arr)[10]);
//6.传递多维数组
void print(int (*martix)[10], int rowsize);
//7.initializer_list形参(用于表示某种特定类型的值的数组)类似容器vector
void error_msg(initializer_list<string> il);

4.main:处理命令行选项(给main传递实参)

  • int main(int argc, char **argv) {...} 第二个形参是指向c风格字符串的指针;第一个形参argc表示数组中字符串的数量
  • 当实参传递给main函数后,argv的第一个元素指向程序的名字或一个空字符串,接下来的元素依次传递命令行提供的实参,最后一个指针之后的元素值保证为0
argv[0] = "prog";
argv[1] = "-d";
argv[2] = "-o";
argv[3] = "ofile";
argv[4] = "data0";
argv[5] = 0;
//当使用argv中的实参时,一定要记得可选的实参从argv[1]开始;argv[0]保存程序的名字,而非用户输入
  • 对于该部分暂时不会使用vs如何传递命令行参数。。。。(以后会的时候再写)

5.返回类型和return语句

  • 不要返回局部对象的引用或指针(函数终止意味着局部对象的引用将指向不再有效的区域)
  • 调用一个返回引用的函数得到左值(能为返回类型是非常量引用的函数的结果赋值)
  • 列表初始化返回值(返回花括号包围的值的列表)
  • 返回数组指针:
//返回数组指针的函数形式:
Type (*function(parameter_list)[dimension]

int (*func(int i))[10];
//func(int i)表示调用func函数需要一个int类型的对象
//(*func(int i))意味着我们可以对函数调用的结果执行解引用操作
//(*func(int i))[10]表示解引用func的调用将得到一个大小是10的数组
//int (*func(int i))[10]表示数组中的元素是int类型

//使用尾置返回类型
auto func(int i) -> int(*)[10] 
//func接受一个int类型的实参,返回一个实参,该指针指向含有10个整数的数组


//使用decltype
int odd[] = {1,3,5,7,9};
decltype(odd) *arrptr(int i);

//返回一个指针,该指针指向含有5个整数的数组

6.函数重载:(同一作用域内的几个函数名字相同但形参列表不同)

  • 定义重载函数:对于重载函数,它们应该在形参数量或形参类型有所不同(不允许只有返回类型不同)
  • 重载和const形参:常量引用或指针与非常量引用或指针可以形成重载
Record lookup(Account &);               //函数作用于Acoount的引用
Record lookup(const Account &);         //新函数,作用于常量引用
  • const_cast和重载(。。。。不太理解)
  • 调用重载的函数(寻找最佳匹配函数):如果有多个函数可以匹配,但都不是最佳选择,则会发生错误,称为二义性匹配
  • 重载与作用域:一旦在局部作用域中定义了一个新的函数声明,则自动屏蔽外围函数声明

7.特殊用途语言特性

  • 默认实参:通常,应该在函数声明中指定默认实参,并将该声明放在合适的头文件中
  • 内联函数和constexpr函数:
//内联函数可避免函数调用的开销;内联机制用于优化规模较小、流程直接、频繁调用的函数
//通常在函数的返回类型前加上关键字inline
inline const string&
shorterstring(const string &s1, const string &s2)
{
    return s1.size() <= s2.size() ? s1 : s2;
}

//constexpr函数:用于常量表达式的函数
constexpr int new_sz() { return 42;}
constexpr int foo = new_sz(); //正确:foo是一个常量表达式
  • 调试帮助:assert和NDEBUG
//1.预处理宏assert(expr):包含一个表达式,expr为真时,assert什么也不做
//  为假时输出信息并终止程序。包含在cassert头文件中。通常用于检查不能发生的条件
//2.assert依赖于NDEBUG的预处理变量的状态,如果定义了NDEBUG,assert什么也不做
//  默认状态下NDEBUG是未定义的。编译器也可以预先定义该变量
//3.也可以使用NDEBUG编写自己的条件调试代码,如果NDEBUG未定义,将执行#ifndef到#endif
//  之间的代码,如果定义了NDEBUG,这些代码将会忽略

void pp()
{
    #ifndef NDEBUG
        cerr << "my name is:" << __fuc__ << endl;
}
//一些c++编译器定义的调试有用的名字
//_ _func_ _:一个静态数组,存放函数的名字
//_ _FILE_ _:存放文件名的字符串字面值
//_ _LINE_ _:存放当前行号的整形字面值
//_ _TIME_ _:存放文件编译时间的字符串
//_ _DATE_ _:存放文件编译日期的字符串字面值

8.函数指针:函数指针指向函数而非对象

//使用函数指针
bool lengthCompare(const string&, const string &);  //比较两个string的长度
pf = lengthCompare;   //pf指向名为lengthCompare的函数
pf = &lengthCompare;  //等价的赋值语句:取地址符是可选的
bool b1 = pf("hello", "goodbye");  //调用lengthCompare函数

//重载函数的指针:指针的类型必须与重载函数精确匹配
void ff(int *);
void ff(unsigned int);
void (*pf1)(unsigned int) = ff;//pf1指向ff(unsigned int)
void (*pf2)(int) = ff;      //错误:没有一个ff与该形参列表匹配

//函数指针形参:直接将函数作为实参调用,它会自动转换为指针
//返回指向函数的指针:使用类型别名
using F = int(int*, int);        //F是函数类型,不是指针
using PF = int(*)(int*, int);    //PF是指针类型
PF f1(int);     //正确:PF是指向函数的指针,f1返回指向函数的指针
F *f1(int);     //正确:显示的指定返回类型是指向函数的指针
//也可以用下面方式直接声明f1
int (*f1(int))(int*, int);
auto f1(int) -> int(*)(int*, int);

9.部分习题解答

扫描二维码关注公众号,回复: 3427857 查看本文章

6.2:

(a)返回类型不匹配;     (b)函数没有表明返回类型

(c)两个v1,参数应不同    (d)必须使用花括号

6.3:

#include <iostream>
#include <string>
using namespace std;
//猜答案
string fact(char  c)
{
	switch (c)
	{
	case 'A':
		return "Ops! Wrong answer";
		break;
	case 'B':
		return "Ops! Wrong answer";
		break;
	case 'C':
		return "Ops! Wrong answer";
		break;
	case 'D':
		return "这都被你知道了!";
		break;
	}
}
int main()
{
    cout << "让你猜猜我的qq号是多少呀~" << endl;
    cout << "A: 123456789" << endl;
    cout << "B: 456789123" << endl;
    cout << "C: 987456123" << endl;
    cout << "D: 456987189" << endl;
    cout << "正确答案是? : ";
    char given_answer;
    cin >> given_answer;
    cout << fact(given_answer) << endl;
    system("pause");
    return 0;
}

6.4、6.5:

#include <iostream>
#include <string>
using namespace std;
//求某个数的阶乘
int jiec(int a)
{
	int ret = 1;
	while (a > 1)
	{
		ret *= a;
		--a;
	}
	return ret;
}

//求某个数的绝对值
int jueduiz(int a)
{
	a = abs(a);
	return a;
}
int main()
{
    int x,y;
    cout << "输入数字x,y: ";
    cin >> x>>y;
    cout << "输出x的阶乘为: "<<jiec(x) << endl;
    cout << "输出y的绝对值为: " << jueduiz(y) << endl;
    system("pause");
    return 0;
}

6.6、6.7:

#include <iostream>
#include <string>
using namespace std;
//第一次调用时返回0,以后每次调用返回1
int fact()
{
	static int my_number = 0;   //静态局部变量
	++my_number;
	if (my_number == 1)
	{
		return 0;
	}
	else
	{
		return 1;
	}
}
int main()
{
    for (int i = 0; i < 10; ++i)
    {
	cout << fact() << endl;
    }
    system("pause");
    return 0;
}

6.10:

#include <iostream>
#include <string>
#include <vector>
using namespace std;
//交换两个数
void jiaohuan(int *val1, int *val2)
{
	int a;
	a = *val1;
	*val1 = *val2;
	*val2 = a;
}
/*void jiaohuan(int &val1, int val2)
{
	int a;
	a = val1;
	val1 = val2;
	val2 = a;
}*/
int main()
{
    int val1,val2;
    cout << "input two numbers:";
    cin>> val1 >> val2;
    cout << "before change:"<< val1 << val2 << endl;
    jiaohuan(&val1,&val2);  //jiaohuan(val1,val2);
    cout << "after change:" << val1 << val2 << endl;
    system("pause");
    return 0;
}

6.11:

#include <iostream>
#include <string>
#include <vector>
using namespace std;
//判断字符串中是否存在某个指定字符,并求出该字符出现的次数
string::size_type find_char(const string &s, char c, string::size_type &occours)
{
	auto ret = s.size();
	occours = 0;
	for (decltype(ret) i = 0; i != s.size(); ++i)
	{
	    if (s[i] == c)
	    {
		if (ret == s.size())
		{
		    ret = i;
		}
		++occours;
	    }
	}
	return ret;
}
int main()
{
    string my_string;
    cout << "请输入目标字符串: ";
    cin >> my_string;
    cout << "请输入目标字符: ";
    char c;
    cin >> c;
    string::size_type val = 0;
    if (find_char(my_string, c, val) == my_string.size())
    {
	cout << "目标字符串中无" << c << "字符出现" << endl;
    }
    else
    {
	cout << "字符" << c << "第一次出现的位置为: " << find_char(my_string, c, val) << endl;
	cout << "字符" << c << "出现的次数为: " << val << endl;
    }
    system("pause");
    return 0;
}

6.13:

前者以传值方式传入参数,不能修改实参。后者以传址的方式传入参数,可以修改实参

6.15:

因为s字符串是不能被函数所修改的,所以是常量引用;c是一个临时变量,所以不需要使用引用类型;如果令occurs为常量引用,则输出occurs为0,而s可能在程序中被修改

6.17:

#include <iostream>
#include <string>
#include <vector>

//判断字符串中是否有大写字母
bool my_set(const string &s)
{
	for (int i = 0; i < s.size(); ++i)
	{
		if (s[i] >= 'A'&&s[i] <= 'Z')
		{
			return true;
		}
	}
	return false;
}

//如果字符串中出现大写字母则将其改为小写
string my_set1(string &s)
{
	for (int i = 0; i < s.size(); ++i)
	{
		if (s[i] >= 'A'&&s[i] <= 'Z')
		{
			s[i] = tolower(s[i]);
		}
	}
	return s;
}
int main()
{
    string my_string;
    cout << "请输入字符串: ";
    cin >> my_string;
    if (my_set(my_string))
    {
	cout << "字符串" << my_string << "存在大写字母." << endl;
	cout << "修改后的字符串为: " << my_set1(my_string) << endl;
    }
    else
    {
	cout<< "字符串" << my_string << "不存在大写字母." << endl;
    }
    system("pause");
    return 0;
}

6.18:

(a):

bool compare(matrix &m1, matrix &m2){/*....*/}

(b):

vector<int>::iterator chang_val(int, vector<int>::iterator){/*...*/}

6.20:

无需在函数中改变的参数应该设为常量引用

6.21:

#include <iostream>
#include <string>
#include <vector>
using namespace std;
int compare(int a, int *b)
{
	if (a >= *b)
	{
		return a;
	}
	else
	{
		return *b;
	}
}


int main()
{
    int val1,val2;
    cout << "input two numbers:";
    cin >> val1 >>val2;
    cout << "the bigger one:" << compare(val1,&val2) << endl;
    system("pause");
    return 0;
}

6.22:

#include <iostream>
#include <string>
#include <vector>
using namespace std;
void swap(int* &a,int* &b)
{
    int *c = NULL;
    c =a;
    a =b;
    b= c;
}

int main()
{
    int val1,val2;
    cout << "input two numbers:";
    cin >> val1 >>val2;
    int *p_val1 = &val1;
    int *p_val2 = &val2;
    cout << "before swap:" << *p_val1 <<" "<< *p_val2 << endl;
    swap(p_val1,p_val2);
    cout << "after swap:" << *p_val1 <<" "<< *p_val2 << endl;
    system("pause");
    return 0;
}

6.25、6.26:

#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main(int argc,char **argv)
{
    string str;
    for (int i = 1;i!= argc;++i)
    {
        str += argv[i];
        str += " ";
    }
    system("pause");
    return 0;
}

6.27:

#include <iostream>
#include <string>
#include <vector>
#include <initializer_list>
using namespace std;
void add_list(initializer_list<int> a)
{
	auto ret = 0;
	for (const auto &c:a)
	{
		ret += c;
	}
	cout << ret << endl;
}

int main(int argc,char **argv)
{
    initializer_list<int> lis{1,2,3,4,5,6,7,8,9};
    add_list(lis);
    system("pause");
    return 0;
}

6.28:

其中的elem是const string类型

6.29:

应该,减少复制次数

6.31:

局部临时变量以及局部变量的引用;在函数内部对常量引用做类似赋值拷贝等动作

6.33:

#include <iostream>
#include <string>
#include <vector>
using namespace std;
void get_vector(vector<int> a, int ix)
{
	if (ix >= 0)
	{
		cout << a[ix] << endl;
		get_vector(a, ix - 1);
	}
}
int main(int argc,char **argv)
{
    vector<int> v;
    int val1;
    while (cin >> val1)
    {
	v.push_back(val1);
    }
    auto ix = v.size() - 1;
    get_vector(v, ix);
    system("pause");
    return 0;
}

6.36、6.37、6.38:

//6.36
string(&func(string(&arrStr)[10]))[10];
//6.37
using ArrT = string[10];
ArrT& func1(ArrT& arrStr);  //使用类型别名

auto func2(ArrT& arrStr) -> string(&)[10];//使用尾置返回类型

string arrS[10];
decltype(arrS)& func3(ArrT& arrStr);//使用decltype关键字
//6.38
decltype(odd)& arrPtr(int i)
{
    return (i % 2)? odd : even;
}

6.40:

一旦函数的某个形参被赋予了默认值,它后面所有的参数都必须有默认值

6.42:

#include <iostream>
#include <string>
#include <vector>
using namespace std;
string make_plural(size_t ctr, const string&word, const string&ending = "s")
{
	return (ctr > 1) ? word + ending : word;
}

int main(int argc,char *argv[])
{
    cout << ""两单词的单数形式:"<< make_plural(1,"success","es") <<" "
            <<make_plural(1,"failure") << endl;
    cout << ""两单词的复数形式:"<< make_plural(2,"success","es") <<" "
            <<make_plural(2,"failure") << endl;
    system("pause");
    return 0;
}
 

6.46:

不能,isShorter函数两个形参都不是字面值类型

6.47:

#include <iostream>
#include <string>
#include <vector>
using namespace std;
void printVec(vector<int> &vec)
{
#ifndef NDEBUG
	cout << "vector size: " << vec.size() << endl;
#endif // !NDEBUG
	if (!vec.empty())
	{
		auto tmp = vec.back();
		vec.pop_back();
		printVec(vec);
		cout << tmp << " ";
	}
}
int main(int argc,char **argv)
{
    vector<int> vec;
    int word;
    while (cin>>word)
    {
        vec.push_back(word);
    }
    printVec(vec);
    system("pause");
    return 0;
}

6.52:

(a)类型提升                   (b)标准转换

6.54:

int fun(int a,int b);
typedef int(*p)(int a,int b);
vector<p> vec;

6.55、6.56:

#include <iostream>
#include <string>
#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 argc,char *argv[])
{
    typedef int(*p)(int a, int b);
    vector<p> vec{ add,subtract,multiply,divide };
    for (int i = 0;i<vec.size();++i)
    {
	cout << vec[i]<< endl;
    }

    system("pause");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38790716/article/details/81974213