cpp primer笔记-010开始

  1. 下面的第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;
    }
    
  2. char类型在有些机器上是有符号的,在有些机器上是无符号的,需要使用char类型,最好明确是signed char还是unsigned char.
  3. 当赋给无符号类型一个超出其表示范围的值是,得到的结果是初始值对无符号类型表示数值总数取模后的余数,但是赋给有符号类型一个超出其表示范围的值,结果是未定义未知的,程序可能继续工作,可能崩溃,也可能产生垃圾数据。如果一个表达式中包含有符号和无符号类型,则有符号类型会转换成无符号类型进行计算,切勿混用带符号和无符号类型进行计算。
    #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
    
  4. 使用泛化的转义序列,其形式是\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;
    }
    
    20
    
    234
    
    
  5. void可以存放任意对象的地址,包括另一个指针所指向的地址,但是void的作用比较有限,只能拿它和别的指针比较,作为函数输入输出,或者给另外一个void指针赋值,但是不能直接操作void类型的指针所指向的对象。除了void*是个例外,其他大部分情况下指针的类型和指向的对象类型要严格匹配,不发生隐式类型转换。
    #include<iostream>
    #include <climits>
    int main()
    {
    	double num = 3.14, * pd = &num;
    	void* pv = &num;
    	pv = pd;
    	std::cout << *pd << " " << *(double*)(pv) << std::endl;
    }
    
  6. 引用本身不是一个对象,所以不能定义一个指向引用的指针,但是指针是对象,所以可以存在对指针的引用。
    #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;
    }
    
  7. 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
    
  8. 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;
    

}

  1. 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;
    }	
    
  2. 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 int
    	b int
    	c int
    	d int * __ptr64
    	e int const * __ptr64
    	f int
    	g int
    	j int
    	m int
    	p int const * __ptr64
    	x int const * __ptr64	
    
  3. decltype注意点:

    #include<iostream>
    #include <climits>
    #include<typeinfo>
    int main()
    {
    	int i = 42, * p = &i, & r = i;
    	decltype(r + 0) b;//表达式加法结果为int类型,b为未初始化的int
    	decltype(*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;
    }
    
  4. 如果一个表达式中已经有了std::string的size()函数,就不要使用有符号整形,因为size()有可能返回一个unsigned int类型的数据。

  5. 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"; 
    }
    
  6. 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个wer
    	std::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;
    }
    
  7. 范围for语句for(statement : expression)体内不允许改变其遍历序列

  8. 迭代器中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;
    }
    
  9. begin和end迭代器返回的具体类型由对象是否是常量决定,如果是常量,begin和end返回const_iterator,如果不是常量返回iterator,而cbegin和cend不管是否是常量容器都会返回const_iterator类型

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值