更新时间:2016.12.26
内容:3.3,3.4,3.6.
更新时间:2016.12.15
内容:第六章部分内容
更新时间:2016.12.12
内容:第四章,第五章第5节
更新时间:2016.12.5
内容:第三章第五节数组,第五章1-4节
第二章 变量和基本类型
本章讲的是主要是数据类型
2.1基本内置类型
- 基本内置类型
分为整形(包括字符和布尔型)和浮点型。
类型名 含义 最小尺寸 wchar_t 宽字符型 8位 char16_t Unicode字符 16位 char32_t Unicode字符 32位 short 短整型 16位 int 整型 16位 long 长整型 32位 long long 长整型 32位 long double 扩展精度浮点数 10位有效数字 注:此外还有bool,char,float,double四种基本类型。
short类型与pascal中integer类型范围相同。C++语言规定一个int至少和一个short一样大,一个long至少和int一样大。Int占16个字节是指它占的最小空间。具体空间与编译器决定。
带符号类型和无符号类型
除布尔型和扩展字符型外,其他整型可以划分为带符号和不带符号两种。带符号的基本类型表示范围为2^(n-1)(n表示占用空间位),不带符号的是2^n。但是signed char理论上可以表示-127至127区间内值,但大多数现代计算机将表示的范围定位-128至127.类型转换
初始类型 | 转换类型 | 情况 |
---|---|---|
非boolean | boolean | 为0则为false否则为true |
boolean | 非boolean | true则转成1,false则转成0; |
浮点数 | 整型 | 截取整数部分 |
整数 | 浮点型 | 小数部分为0,但如果整型所占空间过大,精度会有损失 |
超出范围的值n | 无符号数 | n对无符号数的最大正值取模 |
超出范围的值n | 有符号数 | 未定义的(undefined) |
注意:请勿混用带符号类型和无符号类型:如果表达式中既有带符号类型又有不带符号类型,当带符号类型取值为负可能会出错。
- 字面值常量
字面值常量(literal constant),“字面值”是指只能用它的值称呼它,“常量”是指其值不能修改。每个字面值都有相应的类型,3.14是double型,2是int型。只有内置类型存在字面值。
整形和浮点型
可以把整形字面值写成十进制,八进制(前缀为0)和十六进制(0x)三种形式。浮点型字面值默认是一个double,表现为一个小数或以科学计数法表示的指数。其中指数部分用E或e表识。
字符和字符串字面值
用单括号括起来的一个字符称为char型字面值,用双括号括起来的字符串叫做字符串型字面值。字符串实际上是字符数组,且编译器在每个字符串末尾加上\0。
转义序列
名称 转义符号 换行符 \n 纵向制表符 \v 反斜线 | 回车符 \r 横向制表符 \t 退格符 \b 问号 \? 进纸符 \f 报警(响铃)符 \a 双引号 \” 单引号 \’ 例如:
std::cout<<'\n';//转到新的一行 std::cout<<"\tHi!\n"
也可以用泛化的转义序列
指定字面值类型
前缀 含义和类型 u Unicode16字符 char16_t U Unicode32字符 char32_t L 宽字符 wchar_t u8 UTF-8 char 后缀 最小匹配类型 u or U unsigned l or L long ll or LL long long f or F float l or L long double
布尔型字面值和指针字面值
true和false是布尔型字面值
nullptr是指针字面值
2.2变量
- 定义
- 初始值
- 列表初始化
C++11中,列表初始化成为新标准的一部分。可以用花括号来初始化变量
int sadsds=0;
int sdasdd={0};
int sadasd{0};
int asdasd(0);
//以上四种写法都可以
但是,当使用列表初始化且初始值存在丢失风险的信息,编译器会报错。
long double ld=3.1415926536;
int a{ld},b={ld};//错误
int c(ld),d=ld;//正确
- 默认初始化
变量声明和定义
C++语言支持分离式编译,声明和定义被区分开来。声明是使得程序所知,而定义是创建与名字关联的实体。
如果只声明,不定义,则:extern int i;//声明但不定义
如果只声明不定义,初始化时会引发错误
静态类型
C++是一种静态类型语言,含义实在编译阶段检查类型。其中检查类型的过程称为类型检查。变量命名规范和要求
1.体现实际含义
2.一般用小写字母(常量用大写)
3.用户自定义类名一般以大写字母开头
4.如果由多个单词组成,则应有明显区分。如studentMain或student_main
5.变量命名不能用到保留字,详细内容:C++保留字
6.由字母、数字、下划线组成,必须以字母或下划线开头。变量作用域
分为全局作用域和块作用域。全局作用域的名字应声明在所有花括号之外。嵌套的作用域
被包含的作用域称为内层作用域,包含着别的作用域的作用域称为外层作用域。当处于内层时,如果有两个分别在内外的同名变量(一个全局,一个块),此时调用的是内层变量。
例如:#include<iostream> int reused=42; using namespace std; int main() { int unique=0; cout<<reused<<" "<<unique<<endl; //输出 42 0 int reused=0; cout<<reused<<" "<unique<<std<<endl; //输出 0 0 cout<<::reused<<" "<<unique<<endl; //此时显式的地访问全局变量reused;输出42 0; return 0; } //P44页的样例
所以如果可能用到某全局变量,不要取同名。
2.3复合类型
本章介绍了C++中的引用类型和指针类型。
引用类型
此处指的引用是左值引用。通过将声明符写成&d的形式来定义引用类型。引用即别名:引用并非对象,而是为一个已经存在的对象所起的另外一个名字。
所以可以用引用修改变量的值。
但是,引用类型的初始值必须是一个对象,且类型必须一致。
int &www=1;//不正确
float q=30.1;
int &wwa=q;//q必须是一个int对象
具体可以看看http://www.cnblogs.com/Mr-xu/archive/2012/08/07/2626973.html这个博文
- 指针类型
1.获取地址:需使用取地址符(&);对象不能取地址;类型也要匹配;
2.指针值必须处于以下四种状态,且编译器不负责检查指针值的情况。
1.指向一个对象
2.指向紧邻对象所占空间的下一个位置
3.空指针
4.无效指针
3.访问:指针可以用解引用符(*)访问;当为*p赋值时,即在给p指针所指的对象赋值;解引用仅适用于确实指向了某个对象的有效指针。
4.空指针:初始化指针可以避免一些错误。可以用nullptr或0来使指针成为空指针,也可用NULL,但须预处理。
include cstdlib
...
int *p=NULL;
...
在C++11标准下,最好使用nullptr。
5.指针用于条件表达式:
当指针有一个合法的值,就能用于条件表达式。任何非0指针的布尔值都是true,0指针则为false。
6.void*指针:*void的指针能够指向任何对象。
7.定义注意:
int *p1,p2//这个语句中P2是一个int类型的变量。
int *p1,*p2//两个都是指针类型
int* p1,p2//这个写法只针对p1这个变量,也就是说,p2仍然是int类型。
8.指向指针的指针和引用:
指针可以嵌套多层,比如:
int i=1;
int *p1=&i;
int **p2=&i;//如果这边少写了一个*,得到的就是p1的值即i的地址
//下面是指向指针的引用
int i=42;
int *p;
int *&r=p;//r是p这个指针的引用
r=&i;//给r赋值i的地址就是让p指向i
*r=5;修改p指向对象i的值
2.4Const修饰符
本节写的不是很完整..
1.const可以定义常量
2.默认状态下const对象仅在文件内有效,如果在多个文件中出现了同名的const对象,等同于在不同文件分别定义了独立变量。若只要一个const对象,就要对const变量不管声明还是定义都添加extern关键字。
3.对const 引用、指针注意事项:
int i=42;
const int &a=i;
int &b=a*4;//编译器会报错
//....
// int *p=&a;需用下面的指向常量的指针来指向const常量
const int *p=&a;
//指向常量的指针也可以指向非常量;
const int *p1=&i;
//....
//当然还有常量(const)指针 *const
int *const cutErr=&i;
4.顶层const和底层const
对一般的变量而言,const都是顶层const,无法被更改。而对于向指针这样的变量,才存在顶层const和底层const。
int x=5;
int const *p=&x;
//这是一个指向常量的指针,不能改变它所指的对象。
int *const p=&x;
//这是一个固定指向变量x地址的指针。该指针不能改变它所指的地址。
int const *p就是一个底层const,而int *const p则是一个顶层const。
常量的顶层const**不能**赋值给非常量的底层const。
int a= 5;
const int *p=&a;
//int *p2=p 错误,不能将底层const指针赋值给非顶层const指针
const int *p2=*p;
//正确,可以将底层const指针复制给顶层const
当使用const-cast函数时,需要分辨顶层const或底层const。因为const_cast只能改变运算对象的底层const。
int b=4;
const int *p=&b;
int *p2=const_cast<int *>(p);
//正确
*p2=5;
5.constexpr和常量表达式
- 常量表达式:比如
const int dog=100;
const int doge=dog+1;
constexpr变量
能够判断一个初始值到底是不是变量表达式。指针和constexpr
如果在constexpr声明中定义了一个指针,限定符仅仅对指针有效,而对所指对象无效。const int *p=nullptr;//这是一个指向整形变量的指针 constexpr int *q =nullptr;//这是一个指向整数的常量指针
2.5处理类型
2.6自定义数据结构
这个有点像类的简化版。
#include<string>
using namespace std;
enum color{red,blue,white,black,yellow};
...
struct dog{
string name="No Name";//可以赋初值
unsigned age;
color d_color;
};//注意 这边有个分号
int main()
{
dog dog1;
dog1.name="MDHD"
return 0;
}
第三章 字符串、向量和数组
3.1 using声明
用using声明可以隐式调用函数,但是如果加载了多个库,有同名函数冲突时必须显式调用。
3.2 String类型
使用string类型时需调用类库String
- 初始化
有以下几种初始化方法:
代码 | 含义 |
---|---|
string s1 | 默认初始化 |
string s1(s1)和string s1=s2 | s1是s2的一个副本 |
string s1(“value”) | s1是字面值value的一个副本 |
- string对象上的操作(部分)
代码 | 含义 |
---|---|
os< < | 把s写入输出流os中,并返回os |
is>>s | 从is中读取字符串赋给s,字符串以空白分隔,返回is |
getline(is,s) | 从is中读取一行赋给s,返回is |
s.empty | s为空返回true,否则返回false |
s.size | 返回字符串长度 |
s1+s2 | 返回s1和s2连接以后的结果 |
s[n] | 返回s中第n个字符的引用 |
s1==s2 | 判断s1和s2是否完全一样 |
<,<=,>,>= | 利用字符字典序比较 |
string对象的操作
1.string对象以空格结束,所以如果用cin读入一个“What the”到s1,那么s1=What
2.如果要无限获取string对象,
可以用如下代码:int main() { string s; while (cin>>s) cout<<s<<endl; //只有当读到文章结束标记才会停止读入 return 0; }
3.用getline读取一整行
getline函数的第一个参数是输入流,第二个参数是字符串。getline函数能读入内容直到遇到换行符为止(换行符也被读入),但string内不含换行符。int main() { string s; while (getline(cin,s)) cout<<s<<endl; return 0; }
4.empty和size操作
5.string::size_type类型
size操作会返回一个string::size_type类型,而不是无符号类型或int类型。string::size_type是一个无符号类型。如果一个表达式中有size()函数就不要用int了。处理string对象的字符
以下函数可以判断和处理string对象中的每一个字符
可以用范围for语句遍历字符串s1="a_doge"; for (auto c:s1) { /** 写语句**/ }
但是,如果想改变字符串内的字符,需使用引用类型。
s1="a_doge"; for (auto &c:s1) { c= toupper(c);//把s中所有字母置为大写形式 }
如果只想处理部分字符,可以用下标来直接访问。(注意:字符串对象的下标必须大于等于0并小于s.size(),而s.size()-1是最后一个字符是/0,也就是换行符)。
也可以用迭代的方式for (decltype(s.size())) index=0; index!=s.size() && !isspace(s[index]);index++) s[index]=toupper(s[index]); //NOIP用不了..
其中index的类型是由decltype决定的。
还可以用下标执行随机访问(略,P85页)
3.3 容器
要使用容器,应包含头文件
- 定义和初始化
列表初始化:可以用花括号进行初始化
创建指定数量元素
花括号和圆括号的区别
//列表初始化
vector<string> a={"dog","cat","mice"};
//vector<string> a=("dog","cat","mice");圆括号则不能初始化
//创建指定数量的元素
vector<string> b(10,"hi");
//创建十个"hi"的字符串,如果不加第二个参数,则初始化为默认值
//
vector<int>v1(10);//v1有10个元素
vector<int>v2{10};//v1有一个元素为10
vector<int>v3(100,2);//v3有100个元素,每个为2
vector<int>v4{100,2};//v4有2个元素,分别是100和2
- 向vector对象中添加元素
利用成员函数push_back添加元素
int x;
vector<int> v1;
while (cin>>x)
v1.push_back(x);
//在容器v1尾端加入x
- 其他vector操作
注意:vector内的已存在对象可以直接访问,但不能通过下标添加对象。
3.4 迭代器
- 使用迭代器
begin和end是两个迭代器。begin指向第一个元素,end指向最后一个元素的后一个元素。此处的begin,end都是指针。
string s="Hello";
cout<<*s.begin;//输出H;
cout<<*s.end;//输出 ;
迭代器有许多运算符:
迭代器也有很多类型:
vector<int>::iterator it;//it可读写容器
string::iterator it2;//it2能读写string对象中的字符
vector<int>::const_iterator it3;
//it3只能读元素,不能读字符
string::const iterator it4;
//it4只能读字符,不能读元素
- 3.4.2迭代器运算
3.5 数组
定义和初始化
数组元素个数必须是一个常量表达式(比如n+1就不是,n也不是,因为编译器没法在编译时确定它们的值)。
在C++11中,可以用costexpr来让编译器计算它的值,从而使变量变成一个常量表达式。比如:unsigned h=1; const unsigned hh=2; constexpr unsigned hhh=3; int arr[h];//错误 int arr2[hh];//正确 int arr3[hhh];//正确
也可以显式初始化数组元素,也就是枚举数组元素。
int a1[]={0,1,2}; int a2[10000]=(0,1,2); int a3[2]={0,1,2};//从零开始 char a4[]=“C++”//可以 编译会腾出空间来把字符分开 const char a5[4]="Hello"//错误 空间不够
注意: C++中不能像pascal那样直接对数组拷贝或赋值。
int arr[100]; int *arr2[100]; &a1[10]= ;//不存在引用的数组 int (*a2)[100]=&arr;//a2指向一个含有100个整数的数组 int (&a3)[100]=&arr;//a3引用一个含有100个整数的数组 //以上两个数组的大小需与指向或引用的数组一样大。 int *(&a4)[100]=arr; a4是一个对arr的引用,里面有100个指针
by the way,数组每个元素的内存空间并不一定是连续的。指针和数组
数组的元素可以通过取地址符得到指向该地址的指针;同时,如果直接用数组名字,等价于数组首元素的地址。int a[2]={1,3};; int *p=a;//等价于p=&a[0] //还可以这样写 //int *p(a); //当使用decltype关键字时,上述转换不会发生。(decltype用来查询表达式数据类型,不过好像dev c++用不了)
指针可以当做迭代器用。给一个指针加上或减去一个整数,得到的结果还是指针。但注意不要超出数组范围。这个规则适用于空指针。空指针允许加上或减去一个值为0的常量表达式
int a[10]; int *p=a; ++p;//指针指向a数组的第二个元素a[1] p+=3;//向后移动三个元素,第五个元素 //注意:*(p+3)是取(p+3)位置元素的值,*p+3则是取p位置的值并加上3 //数组还可以用下标运算,且能够处理负值。而string和vector则只能处理负值. int* p=&a[2]; int j=p[1];//p[1]等价于*(p+1); int k=p[-2];//p[-2]即是p[0];
可以用begin函数和end函数来获取数组的首元素和尾元素(注意:Dev c++不能用,这是C++11的内容)。
C风格字符串
《C++Primer》中不推荐适用c风格字符串,因为容易引发BUG。
c中的string头文件名在C++中是cstring,而C++的是string。
与旧代码的借口
//
3.6 多维数组
多维数组实际上是数组的数组。
类型别名可以简化多维数组的指针
using int1=int[4];
typeof int int1[4];
//两者等价
第四章 表达式
定义:表达式由一个或多个运算对象组成,对表达式求值将得到一个结果。字面值和变量是最简单的表达式。
比较重要的:运算符的重载(提及),一元和二元运算符,左值和右值。
C++的表达式要么是左值,要么是右值。一个对象的左值是对象的身份(在内存中位置),右值是对象的值(内容)。
4.1 基础
这节比较简单,主要讲了优先级和结合律,求值顺序。
4.2 算术运算符
一元正号(+)表示正,一元减号(-)表示负。
%表示取模。
4.3 逻辑和关系运算符
相等(==)
记得写两个等号。如果写一个,编译也能过。因为只写一个表示赋值,赋值成功则为true。逻辑非(!)
只有它的结合律是在右边的,其他都在左边。
4.4 赋值运算符
4.5 递增和递增运算符
++i 指的是先加,再进行运算;i++是先进行运算,再给i加上1。
int a=5;int b=6; cout<<(a++)+b<<"\n";\\输出12,此时a等于6 int a=5;int b=6; cout<<(++a)+b<<"\n";\\输出11,此时a等于6 //以下是C++ primer上的一个建议 cout<<*iter++<<endl; cout<<*iter<<endl;++iter //两行语句是等价的,但上面那行更简洁。
4.6 成员访问运算符
4.7 条件判断符
格式
判断表达式?表达式1:表达式2;
if和条件判断符
其中如果判断为true执行1,否则执行2。条件运算符允许嵌套。但是如果嵌套太多层,会影响代码的可读性,不如用if嵌套。因此条件运算符适用于嵌套较少的情况,可以使代码更简洁。
- 条件判断符的低优先级
//c++ primer上的示例。
cout<<((grade<60)?"fail":"pass");
//输出pass或者fail
cout<<(grade<60)?"fail":"pass";
//输出1或者0(即判断cout语句是否为true)
cout<<grade<60?"fail":"pass";
//错误,该语句变成比较cout和60
4.8 位运算符
位运算符比较神奇,能大大提高运算效率。对于优化程序作用很大。
- 移位运算符
分为左移和右移。即把该数向左或向右移动N个为,在十进制中表现为乘上或除以2^n(除法会先降到不大于这个数的最大2次幂,会损耗一定精度)。当然,右移也可以直接去掉最后面的几个二进制位。 位求反运算符
把所有的1变成0,0变成1.位与,位或,位异或运算符
这三个都是二元的。
与:同为1才为1,否则为0;
或:同为0才为0,否则为1;
异或:不同为1,反之为0;应用
以下转载自 lzm风雨无阻 的博客
http://www.cnblogs.com/lzmfywz/archive/2013/03/16/2963873.html
(1) 按位与– &
1 清零特定位 (mask中特定位置0,其它位为1,s=s&mask)
2 取某数中指定位 (mask中特定位置1,其它位为0,s=s&mask)
(2) 按位或– |
常用来将源操作数某些位置1,其它位不变。 (mask中特定位置1,其它位为0 s=s|mask)
(3) 位异或– ^
1 使特定位的值取反 (mask中特定位置1,其它位为0 s=s^mask)
2 不引入第三变量,交换两个变量的值 (设 a=a1,b=b1)
目 标 操 作 操作后状态
a=a1^b1 a=a^b a=a1^b1,b=b1
b=a1^b1^b1 b=a^b a=a1^b1,b=a1
a=b1^a1^a1 a=a^b a=b1,b=a1
二进制补码运算公式:
-x = ~x + 1 = ~(x-1)
~x = -x-1
-(~x) = x+1
~(-x) = x-1
x+y = x - ~y - 1 = (x|y)+(x&y)
x-y = x + ~y + 1 = (x|~y)-(~x&y)
x^y = (x|y)-(x&y)
x|y = (x&~y)+y
x&y = (~x|y)-~x
x==y: ~(x-y|y-x)
x!=y: x-y|y-x
x < y: (x-y)^((x^y)&((x-y)^x))
x <=y: (x|~y)&((x^y)|~(y-x))
x < y: (~x&y)|((~x|y)&(x-y))//无符号x,y比较
x <=y: (~x|y)&((x^y)|~(y-x))//无符号x,y比较
应用举例
(1) 判断int型变量a是奇数还是偶数
a&1 = 0 偶数
a&1 = 1 奇数
(2) 取int型变量a的第k位 (k=0,1,2……sizeof(int)),即a>>k&1
(3) 将int型变量a的第k位清0,即a=a&~(1<
4.9 sizeof运算符
返回一条表达式或一个类型名字所占字节数。
4.10 逗号运算符
4.11 类型转换
- static_cast
转换任何具有明确定义的类型转换(不能有底层const)
double slope=static_cast(j); - const_cast
去掉const性质
- reinterpre_cast
通常为运算对象的位模式提供较低层次的重新解释
- reinterpre_cast
4.12 运算符优先级表
第五章 语句
简单语句
包括空语句(;),复合语句(块)({})条件语句
if语句
if () { ;} if () ; else //以及嵌套If
switch语句
例:int a; switch (a){ case 1:/* */;break; case 2:/* */;break; //... default:/* */;break; }
default标签可以处理所有情况都不符合的情况。
如果去掉break,程序为从头执行到尾,相当于几个if语句。迭代语句
while语句while (/*条件*/) /* 语句*/
适用于未知迭代次数或箱子啊循环结束后访问循环控制变量
for语句for(1初始化;2条件;3表达式) 4语句 //或 for(declaration:expression) statment;
for语句执行顺序是下图。
for语句的初始化部分可以有不止一个变量,用,隔开定义。
for语句的头三个部分都可以省略。如果省略条件部分,则条件默认为true(一直运行)
第二种for语句叫做范围for语句,expression表示的必须是一个序列。declaration定义一个变量。
do while语句do /* 语句*/ while(/*条件*/); 所以计算1至100的数之和的程序为 int i=1,total=0; do{ total+=i; i++; } while (i<=100);
与while语句类似,但先运行后判断
- 跳转语句
break语句
跳出本层迭代循环或switch语句
continue语句
跳过本次迭代循环,进入下一次
goto语句
语法形式:goto label
label的形式为标识符加一个冒号,如:hh:
使用goto语句可能会使程序变得难以理解,也会造成一些难以发现的错误。 异常处理语句
通过try语句和catch语句捕捉可能出现的异常,以下是一个示例。#include<iostream> #include<stdexcept> using namespace std; int main() { for (int i, j; cout << "Input two integers:\n", cin >> i >> j; ) { try { if (j == 0) throw runtime_error("divisor is 0"); cout << i / j << endl; } catch (runtime_error err) { cout << err.what() << "\n"; } } return 0; }
第六章 函数
6.1函数基础
- 局部静态对象
定义为static类型,可以使局部变量的生命周期贯穿函数调用及之后的时间。 函数声明
返回类型,函数名,形参类型是函数的三要素。函数声明也称作函数原型。函数声明就像这样:max(int a,int b);
函数声明一般被省略,但也可写出方便阅读。
6.2参数传递
形式参数和实际参数
形式参数简称形参,实际参数简称实参。形式参数是在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传递的参数。
实际参数是在调用时传递给函数的参数。——百度百科比如:
int max(int x,int y) { if (x>y) return x; else return y; } int main() { int a;int b; int c=max(a,b); return 0; }
a,b是实参,x,y是形参。x,y是局部变量,只能用于函数块内。如果试图引用它可能会引发错误。
函数中对形参的所有操作都不会影响实参。指针形参
我们可以通过改变指针形参的值来改变实参。//C++ primer上的程序 void reset(int *ip) { *ip=0;//改变了ip所指对象的值 ip=0;//只改变了ip的局部拷贝,实参未被改变。 } int main() { int i=42; reset(%i);//i的值被改变为0; return 0 }
传引用参数
本小节讲的是如何用引用传递参数。void h(int &number) { number=100; } ... int a=0; h(a);//a的值被改变
书中建议,应使用引用避免拷贝。因为拷贝大的类类型对象或容器对象比较低效,甚至不支持拷贝。因此如果函数无需改变引用形参的值,最好将其声明常量引用。
比如如果要比较string对象,就可以用引用。//primer上的样例 bool isShorter(const string &s1,const string &s2) { return s1.size()<s2.size(); }
也可以用形参来返回额外信息。比如我们想让一个函数返回多个值。一种方法是定义一个新的数据类型,使它包含多个成员。或者传入一个额外的引用实参,令其保存数据。
//primer上的样例 //这是string中的一个成员函数。可以在API中找到 string::size_type find_char(const string &s,char c,string::size_type &occurs) { auto ret=s.size(); occurs=0; for (decltype(ret) i=0;i!=s.size();++i) { if (s[i]==c) { if (ret== s.size()) ret=i; ++occurs; } } return ret; }
CONST和形参
当实参初始化形参时会忽略掉顶层const,形参的顶层const被忽略掉了。当形参有顶层const时,传给它常量对象或非常量对象都是可以的。
当使用参数引用时最好用常量引用。数组形参
管理指针型形参的三种常用技术:
1.使用标记管理形参。
2.使用标准库规范(如begin end函数)
3.显式传递一个表示数组大小的形参//primer上的样例 void print(int (&arr)[10]) { for (auto elem:arr) cout<<elem<<endl; } //注意:&arr两端的括号必不可少。 //f(int &arr[10])表示将arr声明成了引用的数组,而不是数组的引用。
MARK
这小节的不太懂 ,以后再回来看main:处理命令行选项
main函数的两个变量int argc和char **argv
6.3返回类型和return
return 有两种形式return和return 表达式。
无返回值函数
无返回值函数实际上用的是return的第一种形式。也可以第二种形式,但表达式必须是另一个返回void的函数。有返回值函数
不要返回局部对象的引用或指针。引用返回的是左值。
//From C++ Primer char &get_val(string &str,string::size_type ix) { return str[ix]; } int main() { string s("a value"); cout<<s<<endl;//输出a value get_val(s,0)='A'; cout<<s<<endl;//输出A value }
列表初始化返回值
C++11标准规定,函数可以返回花括号包围的值的列表也用来表示函数返回的临时量进行初始化。如果列表为空,临时量执行值初始化;否则返回的值由返回类型决定。主函数main的返回值
如果我们在主函数中不写return,编译器会隐式地帮我们插入一条返回0的return语句。
main函数不能调用它自己(C++标准)。如果愿意的话也是可以递归的…返回数组指针
6.5特殊用途语言特性
内联函数
用法:在函数的返回类型前加上关键字 inline 。
感觉就是用函数名替代某段代码,有时候的确挺方便的。constexpr函数
以上两者最好定义在头文件中。
6.6函数匹配
候选函数,可行函数。