概述
练习6.22编写一个函数交换两个int指针
第一个函数以值传递的方式使用指针,所有改变都局限于函数内部,当函数执行完毕后即不会改变指针本身的值,也不会改变指针所指的内容。
第二个函数同样以值传递的方式使用指针,但是函数内部通过解引用的方式直接访问内存并修改了指针所指的内容。
第三个函数的参数形式是 int &* ,其含义是(从右向左理解),该参数是一个引用,引用的对象是内存中的一个 int 指针,使用这种方式可以把指针当成对象,交换指针本身的值。需要注意的是,最后一个函数既然交换了指针,当然解引用该指针所得的结果也会相应发生改变。
#include<iostream>
#include<string.h>
#include <vector>
#include <ctime>
using namespace std;
void SwapPointer1(int *p, int *q) {
int *temp = p;
p = q;
q = temp;
cout << "p 的值是:" << p << ",q 的值是:" << q << endl;
}
// 该函数交换指针所指的内容
void SwapPointer2(int *p, int *q) {
int temp = *p;
*p = *q;
*q = temp;
cout << "p 的值是:" << p << ",q 的值是:" << q << endl;
}
// 该函数交换指针本身的值,即交换指针所指的内存地址
void SwapPointer3(int *&p, int *&q) {
int *temp = p;
p = q;
q = temp;
cout << "p 的值是:" << p << ",q 的值是:" << q << endl;
}
int main()
{
int a=5,b=10;
int *r=&a, *s=&b;
cout << "交换前:" << endl;
cout << "r 的值是:" << r << ",s 的值是:" << s << endl;
cout << "r 所指的值是:" << *r << ",s 所指的值是:" << *s << endl;
SwapPointer1(r, s);
cout << "交换后:" << endl;
cout << "r 的值是:" << r << ",s 的值是:" << s << endl;
cout << "r 所指的值是:" << *r << ",s 所指的值是:" << *s << endl;
cout << endl;
a = 5, b = 10;
r = &a, s = &b;
cout << "交换前:" << endl;
cout << "r 的值是:" << r << ",s 的值是:" << s << endl;
cout << "r 所指的值是:" << *r << ",s 所指的值是:" << *s << endl;
SwapPointer2(r, s);
cout << "交换后:" << endl;
cout << "r 的值是:" << r << ",s 的值是:" << s << endl;
cout << "r 所指的值是:" << *r << ",s 所指的值是:" << *s << endl;
cout << endl;
a = 5, b = 10;
r = &a, s = &b;
cout << "交换前:" << endl;
cout << "r 的值是:" << r << ",s 的值是:" << s << endl;
cout << "r 所指的值是:" << *r << ",s 所指的值是:" << *s << endl;
SwapPointer3(r, s);
cout << "交换后:" << endl;
cout << "r 的值是:" << r << ",s 的值是:" << s << endl;
cout << "r 所指的值是:" << *r << ",s 所指的值是:" << *s << endl;
return 0;
}
练习6.23
根据参数的不同,为 print 函数设计几个版本。版本的区别主要体现在对指针参数的管理方式不同。
#include <iostream>
using namespace std;
// 参数是常量整型指针
void print1(const int *p) {
cout << *p << endl;
}
// 参数有两个,分别是常量整型指针和数组的容量
void print2(const int *p, const int sz) {
int i = 0;
while (i != sz) {
cout << *p++ << endl;
++i;
}
}
// 参数有两个,分别是数组的首尾边界
void print3(const int *b, const int *e) {
for (auto q = b; q != e; ++q)
cout << *q << endl;
}
int main() {
int i = 0, j[2] = {0, 1};
print1(&i);
cout << "------- a ---------" << endl;
print1(j);
cout << "------- b ---------" << endl;
print2(&i, 1);
cout << "------- c ---------" << endl;
// 计算得到数组 j 的容量
print2(j, sizeof(j) / sizeof(*j));
cout << "------- d ---------" << endl;
auto b = begin(j);
auto e = end(j);
print3(b, e);
return 0;
}
输出一个数组时,可使用如下方法
void print(const int ia[], const int sz) {
for (size_t i = 0; i != sz; ++i)
cout << ia[i] << endl;
}
二、含有可变形参的参数
initializer_list形参
可以接受相同类型的可变形参
存储在il中的参数是常量值
void error_msg(initializer_list<string> il)
{
for(auto beg=il.begin();beg!=il.end();++beg)
{
cout<<*beg<<" ";
}
cout<<endl;
}
省略符形参
void foo(parm_list,...);
void foo(...);
三、函数的返回:引用返回左值
修改字符串的其中一个字符
char &get_val(string &str,const string::size_type sz)
{
return str[sz];
}
int main()
{
string s("a values");
get_val(s,0)='A';
cout<<s;
}
返回数组指针
因为数组不能被拷贝,函数不能返回数组。不过函数可以返回数组的指针或引用。
最直接的方法是使用类型别名:
typedef int arrT[10] //arrT是一个类型别名,它表示的类型是含有10个整数的数组
using arrT = int[10];//arrT的等价声
arrT* func(int i);//返回一个指向含有10个整数的数组的指针
声明一个返回数组指针的函数
要想在声明func时不使用类型别名,必须记住被定义的名字后数组的维度
int (*p)[10]=&arr;//p是一个指针,指向含有10个整数的数组
使用尾置返回类型
auto func(int i) -> int(*)[10];//把函数的返回类型放在了形参列表之后,可以看到返回类型是一个指针
使用decltype
如果我们知道函数返回的指针将指向哪个数组,可以使用此关键字声明返回类型
decltype并不负责把数组类型转换成对应的指针,所以decltype的结果是个数组,要想表示arrPtr返回指针还必须在函数声明时加一个*符号
int odd[]={1,3,5,7,9};
int even[]={0,2,4,6,8};
//返回一个指针,该指针指向含有5个整数的数组
decltype(odd) *arrPtr(int i)
{
return (i%2)? &odd:&even;
}
练习6.36
编写一个函数声明,返回数组的引用并且该数组包含10个string对象
string (&func())[10];
func()表示调用func函数无须任何实参,(&func())表示函数的返回结果是一个引用,(&func())[10]表示引用的对象是一个维度为10的数组,string (&func())[10]表示数组的元素是string对象
练习6.37
使用类型别名:
typedef string arr[10];
arr &func();
使用尾置返回类型:
auto func() ->string (&)[10];
使用 decltype 关键字:
string str[10];
decltype(str) &func();
练习6.38
数组也是一个对象,所以可以定义数组的引用。要想为数组引用赋值,只需要把数组名赋给该引用即可
int odd[] = {1, 3, 5, 7, 9};
int even[] = {0, 2, 4, 6, 8};
// 返回一个引用,该引用所引的对象是一个含有 5 个整数的数组
decltype(odd) &arrPtr(int i){
return (i % 2) ? odd : even;
// 返回数组的引用
}
重载
const_cast和重载
//比较两个string对象的长度,返回较短的那个引用
const string &shorterString(const string &s1,const string &s2)
{
return s1.size()<=s2.size()?s1:s2;
}
这个函数的参数和返回类型都是const string的引用。我们可以对两个非常量的string实参调用这个函数,返回结果仍是const string的引用。因此需要一个新的shortString函数,当它的实参不是常量时,得到的结果是一个普通的引用
string &shorterString(string &s1,string &s2)
{
auto &r=shorterString(const_cast<const string&>(s1),
const_cast<const string&>(s2));
return const_cast<string&>(r);
}
特殊语言用途特性
1、默认实参
某函数有这样一种形参,在函数的很多次调用中它们都被赋予一个相同的值,我们把这个反复出现的值称为函数的默认实参。调用含有默认实参的函数时,可以包含该实参,也可以省略该实参。
形式如下
typedef string::size_type sz;
string screen(sz ht=24,sz wid=80,char backgrnd='');
我们可以使用多个函数来调用该函数
只能省略尾部实参
string window;
window=screen();//screen(24,80,' ');
window=screen(66);//screen(66,801,' ');
window=screen('?');//screen(63,80,' ');
调用传递一个字符值是合法的,‘?’是一个char,函数最左侧的形参的类型string::size_type是一种无符号整数类型,发生隐式转换,作为height值传递给函数,‘?’对应的十六进制0x3F,十进制63
局部变量不能作为默认实参。只要表达式的类型能转换成形参所需的类型,表达式就能作为默认实参。
sz wd=80;
char def=' ';
sz ht();
string screen(sz=ht(),sz=wd,char=def);
string window=screen(); //ht(),80,' '
用作默认实参的名字在函数声明所在的作用域内解析
void f2()
{
def='*';
sz wd=100;
window=screen();//调用screen(ht(),80,'*')
}
在函数内部改变了def值,所以对screen的调用将会传递这个更新过的值。另一方面,虽然我们的函数还声明了一个局部变量用于隐藏外层的wd,但是该局部变量与传递给screen的默认实参没有任何关系。
最后
以上就是傻傻酸奶为你收集整理的C++Primer-day1 第六章的全部内容,希望文章能够帮你解决C++Primer-day1 第六章所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复