#include "stdafx.h"
#include
#include"Chapter.h"
using namespace std;
void swap(int*d1, int* d2) {//形参类型是指针
int temp;
temp = *d1;
*d1 = *d2;
*d2 = temp;
}
void swap(int& d1, int& d2) {//形参类型是引用
int temp;
temp = d1;
d1 = d2;
d2 = temp;
}
unsigned absolut(int data) {//取绝对值函数
return abs(data);
}
int main()
{
int n,result;
cout << "input two intgret number:" << endl;
cin >> n >>result;
cout << "before switch" << " n=" << n << endl;
cout << "result=" << result << endl;
//swap(&n, &result);//形参为指针类型
swap(n, result);//形参为引用类型
cout << "n=" << n << endl;
cout << "result=" << result << endl;
system("pause");
return 0;
}
作用:
(1)可以作用于实参,改变实参的值
(2)避免拷贝大的数据类型,低效,有些数据类型不支持拷贝,比如I/O
(3)函数返回引用可以返回多个值
string::size_type find_char(const string& s, char c, string::size_type& occurs) {//变量串
auto posi = s.size();
for (decltype(posi) i = 0;i != s.size();i++) {
if (s[i] == c) {
if (posi == s.size())
posi = i;
occurs++;
}
}
return posi;
}
//判断是否是一个句子
bool is_sentence(const string& s) {
string::size_type n=0;
return find_char(s, '.', n) == s.size() - 1&&n==1;//句号在串末尾,且只有一个句号
}
int main()
{
string s = "huangbinhase";//常量串
string::size_type n = 0,position = 0;
position = find_char(s, 'u', n);
cout << "the rank of fist charter 'u' is:" << position << endl;
cout << "the number of 'u' is:" << n << endl;
cout << "the s is a sentence Y/N?" << endl;
if (is_sentence(s))cout << 'Y' << endl;
else
cout << 'N' << endl;
system("pause");
return 0;
}
注意:在visual studio 15中,常量串传给变量串的引用竟然不报错:
(关于顶层和底层const的补充)
底层:是指最终指向的值(*p=4,顶层是4,底层为p,大小为存放4的内存单元的地址)
顶层:指针本身为常量(一般为地址.)
1、尽量使用常引用
(1)说明了常引用不能改变实参的值。
(2)可以扩大实参的接受范围,如果为普通引用就不能接受实参是const类型的数据
习题判断是否有大写字母:
#include
#include
using namespace std;
int main()
{
string s = "huanginhase";
cout << "is there upper charter in string s ,Y/N?" << endl;
for (auto &i : s) {
if (isupper(i)) {//如果发现了大写字母,立即跳出循环,输出Y
cout << "Y" << endl;
break;
}
if (i == s.at(s.size() - 1))//如果i已经扫描到了s最后一个元素,则说明没大写字母
cout << 'N' << endl;
}
system("pause");
return 0;
}
(1)不允许拷贝数组
(2)使用数组是会转化为指针
void print(const int*)
void print(const int[])
void print(const int [10])
这三个函数是等价的(函数并不知道数组有几个元素,通常穿数组时,还有穿数组元素个数)
(1)c风格字符串’\n’结尾,只适用于有明显标记的数组,具有局限性
(2)使用标准库bigin(),和end()函数。例如: print(begin(数组名), end(数组名));
(3)显示传递数组大小的形成(end(i)-begin(j))
1,声明形式
void print(int (&arr)[10]);
注意此时print函数知道传递的数组大小为10个元素,如果实参元素个数不为10,则报错。
agv第一个字符串是程序名,从第二个开始才是真正接受的参数
//编写main函数,接受两个参数,把实参的内容连成一个string输出
#include "stdafx.h"
#include
#include//c风格字符串函数头文件
//strlen(s),strcmp(s1,s2),strcat(s1,s2)
using namespace std;
int main(int argc, char** argv)
//第二个形参为c风格字符串,第一个参数代表字符串个数
{
strcat_s(argv[1],200, argv[2]);//第二个参数缓冲区大小
puts(argv[1]);
cout << endl;
system("pause");
return 0;
}
调用cmd,运行结果:
动机:有时候我们无法提前预知向函数传递几个实参
处理不同实参数量的函数,C++提供了两方法:
(1)initializer_list 模板类型,此时所有的实参类型相同
(2)可变参数模板,可实现实参类型不同的情况(后面再讨论)
initializer_list有点像vector类,但是inilializer_list对象元素永远是常量。
#include "stdafx.h"
#include
#include
//#include//无法打开,该编译器不支持该类
#include
using namespace std;
//输出错误信息函数
void error_msg(vector<string> alam) {//由于vs15中inilializer_list类文件不支持,故用vector类来模拟
for (auto beg = alam.begin();beg != alam.end();++beg)
cout << *beg << ' ';//单词之间用空格符隔开
cout << endl;
}
int main()
{
string expect="huangbin", actual="huangbin";
if (expect != actual)//不相等,则两者都输出
error_msg({ "functonX", expect, actual });//三个参数
else //相等则表示正常
error_msg({ "functionX", "okay" });//调入两个参数
system("pause");
return 0;
}
##### 省略符形参
void foo(parm_list,...);
void foo(...); //省略符号放到最后
return语句有两种形式:
//无返回值
return;//只能用在返回值为void的函数中,可以用在提前退出,
//有返回值类型
return expression;
返回值类型必须与函数返回值类型相等,或者能隐形的转换
#include "stdafx.h"
#include
#include
using namespace std;
//判断两字符中,一个是另一个的前缀
bool str_subrange(const string& str1, const string& str2) {
if (str1 == str2) return true;
auto size = (str1.size() < str2.size()) ? str1.size() : str2.size();//以短字符串长为限
for (decltype(size) i = 0;i != size;++i)
if (str1[i] != str2[i])return false;
return true;//注意循环后必须含有此return语句,不然未定义
}
int main()
{
string s1 = "haing", s2 = "shiena";
if (str_subrange(s1, s2))cout << "OK" << endl;
if (!str_subrange(s1, s2))cout << "NO" << endl;
system("pause");
return 0;
}
string make_plural(size_t ctr,const string &word,const string& ending){
return (ctr>1)?word+ending:word;
}
拷贝word或者两种之和,复制给调用点临时变量
如果返回时引用类型,则是返回值得别名,所以引用类型或者指针的返回类型千万不能是局部对象。因为函数执行完后,该变量都被销毁,成为也指针。
const string &manip() {
string ret;
if (!ret.empty())
return ret;//严重错误,返回局部对象引用
else
return "Empty";//发生严重错误,"empty"是个临时局部变量
}
该函数运行会发生异常,编译不会报错!
//函数的返回类型为指针、引用、类的对象,可以用调用的结果来访问结果对象的成员
auto sz=shorterString(s1,s2).size();//满足左结合率
调用一个返回类型为引用的函数得到左值,可以给它复制:
char& get_val(string& s1);
get_val(s)='s';//合法,但不实用
C++11新标准规定,函数可以返回花括号包围的列表,该列表也用来对返回的临时变量进行初始化。
string expect, actual;
vector<string> process() {
if (expect.empty())
return{};
else if (expect == actual)
return{ "functionX","ok" };//列表初始化vector对象
else
return{ "functionX",expect,actual };
}
例子:
vector<string> si=process();//函数的返回值初始化si
如果返回类型是类类型,则由类本身定义初始值如何使用。
如果函数的返回值不为空,则必须返回一个值。但是main函数是个例外,允许main函数没有return语句,因而在函数末尾编译器隐式插入一条return 0语句。
定义返回数组指针或引用类型的函数,方法一;
(1)类型别名
typedef int arrT[10];//arrT是一个类型别名,它表示的类型含 有10个元素
using arrT=int[10];//与上等价
arrT* func(int i);//返回一个指向含有10个整数的数组的指针
int arr[10];//arr是一个含有10个元素的数组
int *p[10];//p是一个含有10个指针的数组
int (*p)[10];//p是一个指向含有10个元素的指针
第2种方法,不用类型别名:
type (*function(parameter_list))[dimension]//一般格式
int (*func(int i))[10];//例子,与上面一样效果
第3种方法;使用位置返回类型(C++11)
auto func(int i)->int(*)[10];//把返回类型放到了形参列表之后,可以清楚的看出返回的类型
第4种方法:decltype()
int odd[10];
decltype(odd) *arrPtr(int i);//注意decltype(odd)的结果是个数组,不负责转换成指针,所以还需家个*
同理引用类型定义:
typedef string (&str10)[10];
//using s10=string (&)[10];
string huang[9] = {"hang","hianeie",""};
str10 b = huang;//类型不匹配,编译报错,一个是9个元素一个是10个元素,但是当huang[10],就好了
与数组进行对比来看
typedef int str10[10];
//using str10 = int [10];
int huang[10] = {10,2,3,3,3,2,21,4,3,5};
str10 b;
b = huang;//编译通不过,因为对于编译器来说huang的个数不确定的,只是一个指针,但是b的类型一定是10个元素的,类型不匹配
//完全编译通过,运行正确
typedef int (&str10)[10];
int huang[10] = { 9,8,9,3,4,4,3,2,1,23};
str10 b = huang;
void faction(int,int);
void faction(const int,const int);//函数重复定义了,因为这两个函数对实参没有什么要求,常量和非常量都可以
void faction(int&,int&);
void faction(const int&, const int&);//两个是不一样的函数,第一个如果实参是常量就不接收,非常量的话,首先调用第一个函数,虽然第二个函数也可以用。
调用函数首先总是在同一区域内找是否有该函数声明,如果找到了,就会忽略外层的同名函数,尽管内层函数参数不匹配,外层匹配。也不会去调用外层的同名函数。
typedef string::size_type sz;
string screen(sz ht=24,sz wid=80,char backgrand=' '};
如果调用者不给的实参,则该函数,就用默认值。
不过注意:一旦某个形参被赋予了默认值,它后面的形成必须有默认值
所以要想最后个实参传值,前面的形成必须也给传值。
所以设计默认实参时,最好把那些不怎么改动的形参放在形参列表后面,经常需要个性化的形参放在前面。