先过一过基础
1.main函数的返回类型必须为int
2.在大多数系统中,main的返回值被用来指示状态,0表示成功,非0值的含义由系统定义,通常用来指出错误类型
3.#include指令必须在所有函数外,且必须和文件名在同一行
4.注释界定符不能嵌套
5.char 8 long 16 long long 32
其中long long 是C++11的新定义的
6.尽量不要混用无符号和有符号的类型
7. 0开头为8进制,0x为16
8. 列表初始化的好处:
当使用内置类型的变量进行列表初始化时,如果存在信息丢失风险编译器将会报错,比如 long double ld=3.1415926;
int a{ld};将会报错
9.定义变量若没初始化则会被默认初始化,由其具体类型决定,如果是内置的类型,那么由其定义的位置决定,定义于任何函数体外的内置变量会被初始化为0,函数体内部的内置类型不会被初始化,会出错,而类的变量则由类确定初始化方式,绝大多数类都hi吃无需显示初始化定义对象,如string可以不指定初值,而有些类需要。因此对于内置类型尽量都初始化
10.为了支持分离式编译(将程序分为多个文件),需要在各个文件之间共享代码,需要用extern关键字来声明:例如 extern int i;此时代表声明 i而非定义i,如果此时在声明后面加入了初始值,那么此时就抵消了extern的作用了,而且在函数体内部是不允许为其提供初始值的
而且注意当有多个文件的全局变量都有同样的变量名,再用extern会报错,因为编译器并不知道你声明的是哪一个,因此这种情况要尽可能避免
11.如果要使用某一个变量,那么这个变量只能被定义一次,但可以被多次声明
12.C++是一种静态类型的语言,在编译阶段检查类型
13.所有标识符仅有字母,数字和下划线,其中数字不能开头
14.命名规范:{
1.标识符应尽量体现实际意义
2.变量用小字母开头,用户定义的类用大写开头
3.多单词尽量第一个用小写开头后面用大写开头
}
指针这边由于内容比较多,我直接新开了一篇整理
15.常量表达式:在编译过程时就能得到的表达式。
而在一般情况下,我们要去判断一个表达式是否为常量表达式太过繁琐,因此在C++11的新标准种,出现了一种新的类型,constexpr变量(const expression) ,声明为该类型的变量会被自动检测是否为常量表达式,而且还有constexpr函数,具体后面会提到,而且constexpr和const变量一样都需要初始化。
由于constexpr变量的值是能在编译时得到的,因此其类型必须有所限制,否则编译器看不懂,比如算数类型,引用,指针,但是指针的初始值必须是0或者nullptr,或者是存储在某个固定地址的对象(比如某个全局变量,注意局部变量没有固定地址,具体后续会提到)
注意的是这里constexpr和const有部分不一样
const int *p=nullptr;
constexpr int *q=nullptr;
上一句表示的是p是指向常量的指针,q是常量指针
16.C++11新出了一种类型说明符 auto,可以根据表达式自动推出变量类型,因此,auto也必须有初值
但有时候auto也不一定能和初始值的类型完全一样(比如当引用被当作初始值的时候,auto的类型是它绑定的元素的类型而不是引用)
而且auto一般会忽略顶层const,要想使其不忽略,需要再前面加一个const
const int ci=10;
const auto t=ci;
不过值得一提的是 auto的引用是可以保留顶层const
17.与auto类似的,C++11还有一个类型说明符:decltype(),它可以推断某个表达式的类型:比如:
decltype(f()) sum=x;
sum的类型就是f()的类型
与auto有区别的是decltype不会吞掉引用和顶层const
但即便如此,如果真的想吞掉引用怎么办呢,答案是在后面加1个0即可
decltype(r+0) b;
而且还有一些要注意的地方,如果加上括号或者有解引用操作,那么得到的结果就是引用 比如
int i=42,*p=&i,&r=i;
decltype(*p) x;
decltype((i)) y;
x和y都是引用类型
18.头文件不要包含using 声明,否则容易产生冲突
19.string 默认初始化是没有任何字符的
几种容易忘的用法:
getline(is,s);读一行,is表示istream
这里的string对象的==或!=与java的有点不同,这里直接比较的是所有字符,对大小写敏感,而java里的String比较的是地址
而且对于>和<号,比较的是字典序,即先比较长度再从头到尾比较单一字符的大小
20.string里的size函数实际上返回的不是int或者unsigned int,实际上返回的是string::size_type类型,首先它是一个无符号类型,而且足以存放任意string对象的大小。要注意的是,用这个类型的时候,也就是用x.size()去作为表达式的一部分的时候,尽量要用无符号类型做,否则可能会有意外情况,比如
string s="abcde";
int n=-10;
cout<<(s.size()<n);
得到的结果是1,这是因为n转化为了无符号型的值
要注意的是虽然string可以支持相加操作,也支持和字面值相加,但字面值和字面值之间并不支持相加,也就是说在相加时要保证加号两边至少有一个string类型,而且与java不同,这里的字面值必须是字符或者字符串。而且字符串字面值的类型并非string。
21.要遍历string对象的每个字符,虽然可以直接直接for循环遍历,用下标访问,但C++11提供了一种新方法,更加简洁:
string str("hello");
for(auto c:str){
cout<<c<<endl;
}
而要改变字符,只需要加用引用即可
注意的是在C++ 11以前如果vector嵌套定义的话,那么两个>>需要用空格隔开,但C++11不用
vector<vector<int>> c;
这个语句在C++11之前会报错,但11不会
23.在C++11的新标准里,可以为数据成员提供一个类内初始值,在创建一个对象的时候,没有被初始化的数据成员将被默认初始化
24.vector的默认初始化也为空,在C++11中提供了一种新的初始化方式:列表初始化,即用花括号,然后里面的元素都用逗号隔开,如
vector<string> v1{"i","love","c++"};
一般情况下,有很多初始化方式,而且都可以,有几种情况比较特殊,一个是拷贝初始化只能提供一个初始值,二是如果提供的是类内初始值,那么必须用花括号形式的初始化,三是如果提供的是初始元素值的列表,那么要用花括号而不能用圆括号,如
:
vector<string> v1{"i","love","c++"}; //正确
vector<string> v1("i","love","c++"); //错误
25.vector的比较也是和字典序一样,下标和size也和string类似,但注意别用下标来添加vector元素
26.迭代器:iterator,一般是用来访问容器里面的元素的,与指针类似,也提供了对对象的间接访问,使用方法: begin成员函数和end成员函数,begin返回容器的指向第一个元素的迭代器, end返回指向最后元素的下一个元素的迭代器,也称为尾后迭代器,特殊情况是当容器为空的时候begin和end是同一个迭代器,都是尾后迭代器,一般的话都用auto,比较方便。
27.迭代器支持的运算:和指针十分类似,比如
*iter ;//返回迭代器iter所指向元素的引用
iter->mem; //等价于(*item).mem
++item;//指向容器的下一个元素
一般使用时要检查容器是否为空,只需要判断begin和end是否相同即可,迭代器的类型一般有iterator或者const_iterator两种,后者和底层const类似,不能对其指向对象进行修改
28.begin和end的返回类型由对象是否是常量决定,如果是就返回const的,否则就是普通的。一般如果只读不写尽量用const的,C++11新标准提供了两个新函数,cbegin和cend,就可以返回const的。
29.要注意的是像vector这样能动态增加空间的容器,对其增加元素的时候会使得迭代器失效,因此,在用迭代器遍历或者用范围for循环遍历的时候不要给vector新加元素
30.数组是不能拷贝和赋值的
31.数组和指针的一些复杂的声明:
一般从内向外,从右向左看
比如
int (*Parray)[10]=&arr;
从括号看它是一个指针,从右看它是指向一个大小为10的int数组;
32.数组下标其实是size_t类型的,它是一种机器相关的无符号类型,它被设计的足够大可以能表示内存中任意对象的大小,其在cstddef头文件里定义的。
33.C++11中为数组定义了和容器类似的begin和end,用法是这样而不是成员函数
begin(ia);
34.可以用string和字符数组相加或者用字符数组赋给string对象,不过反过来不可以,可以用string里的c_str()成员函数,返回类型是const char *
35.不能用vector初始化数组不过可以用数组初始化vector,只需要指明要拷贝区域的首元素和尾元素地址即可
vector<int> ivec(begin(int_arr),end(int_arr));