- 下面的第5行代码可以写成第6行注释的代码
#include<iostream> int main() {int v1{}, v2{};(std::cin >> v1) >> v2;//std::cin>>v1>>v2;(std::cout << v1) << " " << v2 << std::endl;return 0; }
- char类型在有些机器上是有符号的,在有些机器上是无符号的,需要使用char类型,最好明确是signed char还是unsigned char.
- 当赋给无符号类型一个超出其表示范围的值是,得到的结果是初始值对无符号类型表示数值总数取模后的余数,但是赋给有符号类型一个超出其表示范围的值,结果是未定义未知的,程序可能继续工作,可能崩溃,也可能产生垃圾数据。如果一个表达式中包含有符号和无符号类型,则有符号类型会转换成无符号类型进行计算,切勿混用带符号和无符号类型进行计算。
#include<iostream> #include <climits> int main() {unsigned u = 10, v = 42;int i = -42;long long l = i + 10, num = UINT32_MAX + 1LL, g = i * 10;std::cout << u - v << " " << u + i << " " << u * i << std::endl;std::cout << (l + num) % num << " " << (g + num) % num << std::endl;return 0; }
4294967264 4294967264 4294966876 4294967264 4294966876
- 使用泛化的转义序列,其形式是\x后紧跟着1ge或者多个16进制数字,或者\后紧跟着1个或者多个八进制数组其中数字部分表示的是字符对应的数值,如果\后面跟着的八进制数组超过3个,则只有前面三个数字与\构成转义序列,如果\x跟着的十六进制数超过4个,则只有前面4个数组与\构成转义序列。
#include<iostream> #include <climits> int main() {int num = ' ';std::cout << std::hex;std::cout << num << std::endl;std::cout << '\x20' << '\12' << "234" << std::endl;return 0; }
20234
- void可以存放任意对象的地址,包括另一个指针所指向的地址,但是void的作用比较有限,只能拿它和别的指针比较,作为函数输入输出,或者给另外一个void指针赋值,但是不能直接操作void类型的指针所指向的对象。除了void*是个例外,其他大部分情况下指针的类型和指向的对象类型要严格匹配,不发生隐式类型转换。
#include<iostream> #include <climits> int main() {double num = 3.14, * pd = #void* pv = #pv = pd;std::cout << *pd << " " << *(double*)(pv) << std::endl; }
- 引用本身不是一个对象,所以不能定义一个指向引用的指针,但是指针是对象,所以可以存在对指针的引用。
#include<iostream> #include <climits> int main() {int i = 42;int* p;int*& r = p;r = &i;*r = 1;std::cout << i << " " << *p << " " << *r << std::endl; }
- const修饰的对象仅在定义文件内有效,非定义文件不存在该对象,如果想在其他文件一并使用,则对const变量不管是声明还是定义都加上extern关键字,这样只需要定义一次就够了,常变量引用初始化的时候可以使用任意表达式作为初始值。如果const引用的不是一个const的对象,则该对象可以通过另一个非const引用改变值,也可以通过自身改变值,但是不能通过const引用改变值
//file.cc文件定义并初始化一个常变量,该常变量能够被其他文件使用 extern const int bufSize=fuc(); //file.h头文件 extern const int bufSize;//和file.cc文件定义的bufSize是同一个 double dval=3.45; int a=43,b=34; //允许任意表达式作为初始值 const int &ri=a+b; //允许由双精度浮点数生成一个临时的整形变量 const int &rp=dval; //允许常变量引用初始化值是常量 const int& int_ptr = 10;
#include<iostream> #include <climits> int main() {int i = 42;int& r1 = i;const int& r2 = i;std::cout << r1 << " " << r2 << " " << i << std::endl;r1 = 1;std::cout << r1 << " " << r2 << " " << i << std::endl;i = 2;std::cout << r1 << " " << r2 << " " << i << std::endl; }
42 42 42 1 1 1 2 2 2
- constexpr可以类型必须用常量表达式初始化,一个constexpr指针的初始值必须是nullptr或者0,或者储存于某个固定地址的对象(比如函数体外)
#include<iostream> #include <climits> //x必须定义在函数体外才能被consrexpr修饰 int x = 10; int main() {const int a = 10;constexpr int b = 20;constexpr int c = a + b;//p1是指向整形常量的指针,const int* p1 = nullptr;//p2是指向整形的常量指针constexpr int* p2 = 0;//p3是指向整形常量的常量指针constexpr const int* p3 = &x;//p4是指向整形的常量指针constexpr int* p4 = &x;p1 = &b;*p4 = 20;std::cout << *p1 << " " << p2 << " " << *p3 << " " << *p4 << std::endl;
}
-
CPP允许给类型起别名,包括使用typedef和using,注给指针起别名的时候使用const修饰的指针是常量指针,而不是指向常量的指针。
#include<iostream> #include <climits> int main() {typedef double wages;typedef wages base, * p;base i = 1.0;const p ptr = &i;//相当于double * const ptr = &i;*ptr = 20;std::cout << i << " " << *ptr << std::endl;double* const num = &i;*num = 30;using Son = int;Son s = 10; }
-
auto一般会忽略掉顶层的const,不能将类型变成指向数据的常量指针,但是能够变为指向常量的指针,如果希望变出来的数据能够是指向数据的常量指针,则可以在auto左边加上const
#include<iostream>#include <climits>#include<typeinfo>int main(){int i = 10;const int ci = i, & cr = ci;auto a = i;auto b = ci;auto c = cr;auto d = &i;auto e = &ci;const auto f = ci;auto& g = ci;const auto& j = 42;auto& m = ci, * p = &ci;const auto* x = &ci;std::cout << "a " << typeid(a).name() << std::endl;std::cout << "b " << typeid(b).name() << std::endl;std::cout << "c " << typeid(c).name() << std::endl;std::cout << "d " << typeid(d).name() << std::endl;std::cout << "e " << typeid(e).name() << std::endl;std::cout << "f " << typeid(f).name() << std::endl;std::cout << "g " << typeid(g).name() << std::endl;std::cout << "j " << typeid(j).name() << std::endl;std::cout << "m " << typeid(m).name() << std::endl;std::cout << "p " << typeid(p).name() << std::endl;std::cout << "x " << typeid(x).name() << std::endl;}``` ```cpp a intb intc intd int * __ptr64e int const * __ptr64f intg intj intm intp int const * __ptr64x int const * __ptr64
-
decltype注意点:
#include<iostream> #include <climits> #include<typeinfo> int main() {int i = 42, * p = &i, & r = i;decltype(r + 0) b;//表达式加法结果为int类型,b为未初始化的intdecltype(*p) c=i; //如果表达式的内容是解引用操作则为引用类型,c为int&类型 decltype(r) d = i;//r本身是一个引用类型,所以d为引用类型decltype((i)) e = i;//变量名加上括号是引用类型,所以e是引用类型decltype((i + i)) f;//表达式加上括号不是引用类型const int* const num = &i;decltype(num) ret = &i;//ret属于指向常量的常量指针int z = 100;//*ret = 10;//ret = z; }
-
如果一个表达式中已经有了std::string的size()函数,就不要使用有符号整形,因为size()有可能返回一个unsigned int类型的数据。
-
string的加号+必须保证+号的两侧至少有一个是string
#include<iostream> #include <climits> #include<typeinfo> int main() {std::string s1 = "123";std::string s2 = "123" + s1 + "sdf";std::string s3 = s1 + "123" + s2;std::string s4 = (s1 + "sdf") + "sdf"; }
-
vector初始化注意一下代码:
#include <iostream> #include <climits> #include <vector> int main() {std::vector<int> svec;std::vector<int> svec1(svec);std::vector<int> svec2 = svec;std::vector<std::string> svec3{ "wer","sdf","Sdf" };//std::vector<std::string> svec4("wer", "sdf", "Sdf");std::vector<std::string> svec4(10, "wer");//创建10个werstd::vector<int> svec5(10);//创建10个值为0的int类型std::vector<int> svec6{ 10 };//创建一个值为10的int类型std::vector<int> svec7(10, 1);//创建10个值为1的int类型std::vector<int> svec8{ 10,1 };//创建一个为10和一个为1的int类型std::cout << svec6.front() << std::endl; }
-
范围for语句for(statement : expression)体内不允许改变其遍历序列
-
迭代器中iterator可读写相关对象的元素,const_iterator只可以读取,不可以写相关元素。
#include <iostream> #include <climits> #include <vector> int main() {std::vector<int> vec{ 1,4,2,4,6,23 };std::vector<int>::iterator it1 = vec.begin() + 2;*it1 = 100;for (auto x : vec){std::cout << x << " ";}std::cout << std::endl;std::vector<int>::const_iterator it2 = vec.begin() + 2;//*it=10;std::cout << *it1 << " " << *it2 << std::endl; }
-
begin和end迭代器返回的具体类型由对象是否是常量决定,如果是常量,begin和end返回const_iterator,如果不是常量返回iterator,而cbegin和cend不管是否是常量容器都会返回const_iterator类型