C++ primer笔记

2018.1.3 第六章

main 函数命令处理

agv第一个字符串是程序名,从第二个开始才是真正接受的参数

//编写main函数,接受两个参数,把实参的内容连成一个string输出
//#include "stdafx.h"
#include<iostream>
#include<cstring>//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;
}

2018.1.4

6.26 含有可变形参的函数

动机:有时候我们无法提前预知向函数传递几个实参 
处理不同实参数量的函数,C++提供了两方法: 
(1)initializer_list 模板类型,此时所有的实参类型相同 
(2)可变参数模板,可实现实参类型不同的情况(后面再讨论)

1、 initializer_list形参

initializer_list有点像vector类,但是inilializer_list对象元素永远是常量。

#include "stdafx.h"
#include<iostream>
#include<string>
//#include<inilializer_list>//无法打开,该编译器不支持该类
#include<vector>
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(...); //省略符号放到最后

6.3 返回类型和return语句

return语句有两种形式:

//无返回值
return;//只能用在返回值为void的函数中,可以用在提前退出,
//有返回值类型
return expression;

 
 
  • 1
  • 2
  • 3
  • 4

6.3.2 有返回值函数

返回值类型必须与函数返回值类型相等,或者能隐形的转换

#include "stdafx.h"
#include<iostream>
#include<string>
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<string>对象
    else
        return{ "functionX",expect,actual };
}

 
 

例子:

vector<string> si=process();//函数的返回值初始化si
 
 
  • 1

如果返回类型是类类型,则由类本身定义初始值如何使用。

主函数main的返回值

如果函数的返回值不为空,则必须返回一个值。但是main函数是个例外,允许main函数没有return语句,因而在函数末尾编译器隐式插入一条return 0语句。

 递归循环

计算阶乘

int factorial (int val)
{
    if (val>1)
         return factorial (val-1)*val;
    return 1;
}

6.3.3 返回数组指针

定义返回数组指针或引用类型的函数,方法一; 
(1)类型别名

typedef int arrT[10];//arrT是一个类型别名,它表示的类型含                            有10个元素
using arrT=int[10];//与上等价
arrT* func(int i);//返回一个指向含有10个整数的数组的指针
   
   
  • 1
  • 2
  • 3
声明一个返回数组的指针的函数
int arr[10];//arr是一个含有10个元素的数组
int *p[10];//p是一个含有10个指针的数组
int (*p)[10];//p是一个指向含有10个元素的指针
   
   
  • 1
  • 2
  • 3

第2种方法,不用类型别名:

type (*function(parameter_list))[dimension]//一般格式
int (*func(int i))[10];//例子,与上面一样效果
   
   
  • 1
  • 2

第3种方法;使用位置返回类型(C++11)

auto func(int i)->int(*)[10];//把返回类型放到了形参列表之后,可以清楚的看出返回的类型
   
   
  • 1

第4种方法:decltype()

int odd[10];
decltype(odd) *arrPtr(int i);//注意decltype(odd)的结果是个数组,不负责转换成指针,所以还需家个*
   
   
  • 1
  • 2

同理引用类型定义:

typedef string (&str10)[10];
//using s10=string (&)[10];
string huang[9] = {"hang","hianeie",""};
str10 b = huang;//类型不匹配,编译报错,一个是9个元素一个是10个元素,但是当huang[10],就好了
   
   
  • 1
  • 2
  • 3
  • 4

与数组进行对比来看

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;
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

6.4 函数的重载

重载和const形参
void faction(int,int);
void faction(const int,const int);//函数重复定义了,因为这两个函数对实参没有什么要求,常量和非常量都可以


void faction(int&,int&);
void faction(const int&, const int&);//两个是不一样的函数,第一个如果实参是常量就不接收,非常量的话,首先调用第一个函数,虽然第二个函数也可以用。
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

6.4.1 重载与作用域

调用函数首先总是在同一区域内找是否有该函数声明,如果找到了,就会忽略外层的同名函数,尽管内层函数参数不匹配,外层匹配。也不会去调用外层的同名函数。

6.5特殊用途的语言特性

6.5.1 默认实参
typedef string::size_type sz;
string screen(sz ht=24,sz wid=80,char backgrand=' '};
   
   
  • 1
  • 2

如果调用者不给的实参,则该函数,就用默认值。 
不过注意:一旦某个形参被赋予了默认值,它后面的形成必须有默认值 
所以要想最后个实参传值,前面的形成必须也给传值。 
所以设计默认实参时,最好把那些不怎么改动的形参放在形参列表后面,经常需要个性化的形参放在前面。


6.5.2 内联函数和constexpr函数
内联:前面加 inline
constexpr:是指能用于常量表达式的函数。

6.5.3 内联函数和constexpr函数
assert 预处理宏:内容为真时无反应,为假时停止执行。
DDEBUG预处理变量:开头加上如下,如果遇到则执行包含内容

#define chapter6

#ifndef chapter6
{}
#endif

6.6 函数匹配
重载函数如果分不出最优,则返回二义性

6.6.1 实参类型转换
所有算术类型转换级别一样

6.7 函数指针
函数指针指向函数。
bool (*pf)(int,int)

使用函数指针
bool b1=pf(1,2);
bool b2=*pf(1,2);
bool b3=LengthCompare(1,2);
以上三个式子含义相同
函数指针也可以直接作为形参使用

返回指向函数的指针
using F=int(int*,int);
using PF=int(*)(int*,int);

PF fl(int);
F *fl(int);//两者等价

//也可以定义如下
int (*fl(int))(int*,int);
//使用尾置返回类型方式
auto fl(int) -> int(*)(int*,int);













  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值