LearnCpp

Learn_CPP www.learncpp.com
{
std::
cout
cin

<<endl的效率不高 -> 做了两件事情 1.移动光标到下一行。2. flush

}

Chapter4
{
4.6 定义系统变量位数
{
int -> 4byte
std::int8_t 1byte signed -> -128 ~ -127
std::uint8_t 1byte signed -> 0~255
int16_t 2byte

std::int32_t 4byte

	std::int64_t  8byte
	
	用于 xintx_t -> typedef long int int64_t
	将所有类型进行区分,可以用于重定义。
	如  在16bit 芯片中将int定义为16位的类型->typedef long int int16_t
	
	
		int_fast#_t    #= 8,16,32,64  ->  至少#位的数据类型
		int_least#_t   				  ->  最多#位的数据类型
		
		最大#位   ,最小#位
		
		size_t  -> 当前系统中int 类型的位数
}
	
4.7 科学计数法
{
	4.2030e4

}
4.8 浮点数据类型
{
	123456789
	123456792 
	在做bool运算时  bool a = 123456789.0f == 123456792.0f;
	得到的结果为a = true. 原因是浮点数据类型仅精确到7位有效数字

	float  sig : 1  指数: 8bit  尾数: 23bit   单精度浮点型,和int一样占有4字节
	double sig : 1  指数: 11bit 尾数:52bit   双精度浮点型。占有八个字节。
}

4.9
{
	cout<<std::boolalpha;    -》 print bool 以 true 和flase 的方式显示  。否则会输出01
	
	cin>>b  (bool b{})   只能输入0 1   输入其它默认为0

}

4.11
{
	在C ++中,固定宽度整数int8_t通常与带符号的char相同,因此通常将其打印为char而不是整数。
	
	打印char 对应数字 ->  
	char b{97};
	int a(b);
	cout<< a <<endl;
	
	
	静态转换  ->  static_cast<new_type>(expression)
	
	例子 :  <<  static_cast<int>(b)  <<   -> 静态转换。
	
	
	example cin>>b  单次只能赋单个值,但是其余 值都会保存在键入缓存队列中。
	
	直到调用完成。
	
	int main()
	{
		char b{};
		cin >> b;

		cout << b << "\t has code \t" <<static_cast<int>(b) << endl;
		cin >> b;
		cout << b << "\t has code \t" << static_cast<int>(b) << endl;
		cin >> b;
		cout << b << "\t has code \t" << static_cast<int>(b) << endl;
		cin >> b;
		cout << b << "\t has code \t" << static_cast<int>(b) << endl;
	}
	结果
	{
	输入  abcd
	
	输出 :abcd
			a        has code       97
			b        has code       98
			c        has code       99
			d        has code       100
	
	}
	
	
	\a   发出警报 -> 蜂鸣声
	
	\b   向后移动光标一格
	
	\f   将光标移动到下一个逻辑界面  ?
	
	\n \r \t
	
	\v  竖向跳格,不常用。
	
	对单个字符'\r'  使用单引号而不是双引号,可以提高编译效率
	
	\x()  以16进制显示   \x69    这里的69位16进制数
	
	\o()    以8进制显示
	
	
	char8_t  char16_t  char32_t 
	
	
	
	
}

4.12   Literals 常量
{
	C++ 包含两种常量    文本常量 和 符号常量
	
	return  5;   ->  这里的5 就是常量
	true,false
	
	添加类型后缀(suffix)  比如   5u   -> 表示无符号的类型5
	
	u || U   ->   unsigned int 
	l || L   ->   long
	ul || UL  ->  unsigned long
	ll || LL  ->  long long 
	ull || uLL -> unsigned long long
	f || F   ->   float
	l or L   ->   long double
	
	
	在c++ 中没有后缀将其视为双精度文字
}

4.13 const 指定常量
{
	const 指定的参数必须赋初值
	
	const double pi{3.14159};
	
	两种常量->  运行时常量和编译常量
	
	运行时常量 ->  程序运行前无法确认初值
	{
		int age{};
		cin >> age;
		const int constAge{age};
	}
	编译常量  -> 程序编译时已经确定初值
	{
		const int age{18};
	}
	常量通常作为函数参数传入
	void DoSomething(const int a)
	{}

	C++ 11 ->  引入 constexpr 来指定编译时常量(必须赋确定值)
		exp:  constexpr double {9.8};
		
		
	#define AnExampleValue 30  
	可以定义常量,但是尽量不要这么做。因为其作用域是全局的。
	外部调用时可能出现命名重叠导致的编译错误。
	
	定义全局常量的理想方法->
	{
		1.创建一个头文件来放这些常量
		2.在这个头文件内部声明一个命名空间
		#ifndef CONSTANTS_H
		#define CONSTANTS_H
		namespace constants
		{
			constexpr double pi{3.14159};
			...
		}
		#endif
		
		c++ 17 中 建议加入inline -> 提升性能
		
		inline constexpr double pi{3.14159};
		

		3.将所有常量放入命名空间中  确保c++编译版本。 如constexpr
		4.引入头文件在需要的地方
		
	}
	

}

5  运算操作符
{
	5.3
	{
		乘幂pow()操作不包含在标准库中   必须包含 #include <cmath>
		因为幂操作容易导致溢出
		
		pow(3,4);
	}
	...
}

o. 位操作
{
	#include <bitset>   需要包含位操作库
	std::bitset<8> mybitset{};
	
	mybitset.size()   -> 8
	
	
	mybitset.test(n(0到7))    允许我们查询单个位
	mybitset.set(n)           置位单个位  
	mybitset.flip(n)           将该位反转
	mybitset.reset(n) 		  将单个位
	
	注意置位时顺序位低位到高位
	   
	位操作运算符  
		<<   左移运算符
		>>	 右移运算符
		~    反转
		&    
		|
		^ 
		
	c++ 20 以前不要移位有符号整型
	
	cout (输入输出流)中的 << 重载移位<<的符号
	
	
	位掩码-> 0100  & 1000(mask)  只运算需要的位。
	
	
	位运算转为十进制

}

6. 对象
{
	6.1 block (结构体语句)   ------>   {}
		{
			{}可以嵌套在函数内。 使用独立作用域
			
			如 int main()
			{
				{
					int a{5};
				}
				
				cout<<a;  -> 非法。找不到a
			
			}
		}
	6.2 命名作用域  namespace
	{
		namespace Mynamespace
		{
		...
		
		}
		
		
		使用作用域的方法: 
			::->  . Mynamespace:: ...
		
		
		可以自己扩展命名空间,即库,但标准库std被禁止扩展。
		
		命名域可嵌套  
		namespace a
		{
			namespace b
			{
				
			}
		}
		
		namespace a::b
		{
			
		
		}
		
		
		可以定义作用域的别名来简化调用
		
		int main()
		{
			namespace ab = a::b;
			...
		
		}
		
		
		6.3 局部变量
		{
			
		
		}
		
		6.4 全局变量
		{
		
		}
		
		6.6 内联
		{
			内部全局变量   只在当前文件有效   static
				static int a{};
				
				const int b{};   //const默认为内联
				constexpr int c{3};  //constexpr 默认为内联

			非常量全局变量指定为内部变量的方法是加 static 
				这样这个变量就只对当前文件有效。
				常量(const,constexpr)默认为内部变量
				
			内部函数 函数名称前加 static
			static int add(int ,int){}
		}
		
		6.7 外部函数
		{
			a.cpp  
				void Hello(){cout<<"Hello";}
			
			main.cpp
				#include "a.h"   //包含a的头文件
				void Hello();   ->首先声明该函数。
				
				int main()
				{
					Hello();
					return 0;
				}
				
			这种前向声明的方法。
			
			!使用external 来声明外部变量
			
			a.cpp
				int a{3};   -> 非常量变量默认为可链接外部变量
				external const int b{4}; -> 常量变量需要加external来声明为外部变量
			main.cpp
				external int a;
				external const int b;   使用external变量的前向声明,声明完之后才能在本文件使用
				
			!定义未初始化的非常量全局变量,不要使用external关键字,否则会认为正在对其进行前向声明
			
			!函数声明不需要external声明
			
			全局变量初始化在执行功能之前。
			
				静态初始化和动态初始化,动态初始化?
				
				变量初始化不能依赖于其他变量,
					否则会出现变量值与预期不一定的现象。原因是静态初始化和动态初始化的问题。
					
			尽可能避免动态初始化。
			
		
		}
		
		6.8 内联变量
		{
			多个文件调用,防止更改一次造成大量文件重新编译。
			使用头文件,链接文件,和使用文件组成
			注意只能使用const 因为 constexpr 无法进行前向声明。
			
			constants.h
				#ifndef CONSTANTS_H
				#define CONSTANTS_H
					namespace constants
					{
						external const double pi;
						external const double gravity;
					}
				#endif
			constants.cpp
				#include "constants.h"
				namespace constants
				{
					external const double pi{3.1415926};
					external const double gravity{9.8};
				}
			
			main.cpp  //使用
				#include "constants.h"
				
				int main()
				{
					cout<< 2.0*r*constants::pi<< endl;
				}
				
			这里多使用一个constants.cpp文件来链接。可以避免修改头文件constant参数而导致的大量文件重编译的情况。
			
			
			但是这种方法已经过时。 在C++ 17以上的版本使用
			
			使用inline 来定义内联变量  这样在同样实现了12的优点,避免了缺点
			constants.h
				#ifndef CONSTANTS_H
				#define CONSTANTS_H
					namespace constants
					{
						inline constexpr double pi{3.1415926};
						inline constexpr double gravity{9.8};
					}
				#endif
			
			main.cpp  //使用
				#include "constants.h"
				
				int main()
				{
					cout<< 2.0*r*constants::pi<< endl;
				}
			
		
		}
		
		6.10 static local  静态局部变量
		{	
			在当前文件执行过程中声明的这个变量不会被摧毁且只会声明一次。
			之后的操作也将一直保留,但只能被当前这个函数修改。
			
		
		}
		
		6.11 summary 
		{
		Local variable	int x;	Block	Automatic	None	
		Static local variable	static int s_x;	Block	Static	None	
		Dynamic variable	int *x { new int{} };	Block	Dynamic	None	
		Function parameter	void foo(int x)	Block	Automatic	None	
		External non-constant global variable	int g_x;	File	Static	External	Initialized or uninitialized
		Internal non-constant global variable	static int g_x;	File	Static	Internal	Initialized or uninitialized
		Internal constant global variable	constexpr int g_x { 1 };	File	Static	Internal	Must be initialized
		External constant global variable	extern constexpr int g_x { 1 };	File	Static	External	Must be initialized
		Inline constant global variable	inline constexpr int g_x { 1 };	File	Static	External	Must be initialized
		Internal constant global variable	const int g_x { 1 };	File	Static	Internal	Must be initialized
		External constant global variable	extern const int g_x { 1 };	File	Static	External	Must be initialized at definition
		Inline constant global variable	inline const int g_x { 1 };	File	Static	External	Must be initialized
		
		}
		
		6.12 using
		{
			{
				using ...
				
				...
			}
			
			{
				using ...
				
				...
			
			}
		}
		6.13 typedef
		{
			typedef double myDouble_t
			
			
			typedef *poniter APoint
			
			建议_t来表明这是一个反向的后缀。
			
			也可以使用using来代替typedef   比如using myDouble_t = Double
		}
		6.14  auto
		{
			自动识别类型
			
			auto d{5.0};
			auto i{1+2};
			
			
			auto sum{add(a,b)};
			
			
			auto add(int x, int y) -> int
			{
			  return (x + y);
			}
			
			
			c++20可以尝试的新写法?
			void addAnd(auto a,auto b)
			{
				cout<< a+b;
			}
		}
		
		6.15 隐式转换
		{
			double -> float 会造成低精度小数位发生误差。
			
			int a = 3.5   ->  a ==3
			
			由于 一般不希望精度丢失,所以使用{} 进行初始化,
				在这种初始化方式下不允许产生精度丢失。
				
				int a{3.5f} 会报错
			
			隐式转换允许升类型,不会造成精度丢失比如 int->float
			
			The priority of operands is as follows:

			long double (highest)
			double
			float
			unsigned long long
			long long
			unsigned long
			long
			unsigned int
			int (lowest)	
		}
		6.16 显式转换  cast  static_cast
		{
			5种转换方法: C-style,  static_cast, consts casts ,dynamics cast,reinterpret cast
			

			C-style
			{	
				auto a{(int)(3 + 4.2)};   
				auto b{(float)3};
			}
			
			static_cast  C++提供
			{
				char c{'a'};
				cout << c << '' << static_cast<int>(c) << '\n';
				
				比C强制转换弱,提供编译检查。 不能转换const等。 
				溢出不会警告,表明可以承担溢出的后果。	
			}
			
		6.17 匿名命名空间  和内联命名空间
		{
			所有未命名的命名空间被认为是父命名空间的一部分。
			但匿名命名空间中的信息只能在当前文件中被找到。
			

			namespace 
			{
				void doSomething()  //只能在当前文件被找到。
				{
					cout<< "v1\n";
				}
			
			}		
			int main()
			{
				doSomething();    //无需声明命名空间
				return 0;
			}
			
			
			使用内联命名空间 -> !默认命名空间。
			{
				inline namespace v1
				{
					void doSomething(){}
				}
				namespace v2
				{
					void doSomething(){}
				}
				
				int main()
				{
					v1:doSomething();  ->执行v1的
					v2:doSomething();  ->执行v2的 
					
					doSomething();   ->执行v1的				
				}
			
			
			通过这个可以实现修改某个函数并在新方法内通过调用v2::来执行v2的函数
				而前面仍然使用v1的函数,实现开闭。
			}
		}
			
			
			
			
		
		
		
		}
		
		
		
		
	
	
	
	}





}

7.控制流 与错误处理
{

	7.1   控制流语句
	{
		状况    if,switch
		
		跳转    Goto
		
		函数调用   Function()
		
		循环    for,while,do while, !ranged-for 
		
		停止   sys::exit()  sys::abort()
		
		意外    try,throw,catch
	}
	
	7.6 Goto语句
	{
		int main()
		{
			double x{};
		tryInput:   //这是goto的标志位
			cin>>x; 
			
			if(x < 0) goto tryInput;
			
		cout << "out !!!" <<x<<endl;
		return 0;			
		}
	}
	
	7.9 For
	{
		for(int i{0};i<length;i++)
		{
		...
		}
	}
	
	7.17 std<<cerr ->  控制报错  assert
	{
	  std::cerr << "Error : Could not divide by zero"
	  
	  
	  assert(gravity >0) 断言。 若断言出错则报错
	  
	  NDEBUG 可以控制断言是否开启。
	  
	}
	
	7.x Range for
	{
		vector<int> vecInt;
	
		for (auto i : Vector)
		{
			cout<< i;
		}
	
	
	}

}

8. Compound Types ——> 复合类型
{
	8.1 std::string
	{
		#需要包含string 库   
		#include <string>
		
		std::string myName{"Donald"};
		
		string 初始化若没有赋值,之后cin只能得到一个单词
		https://www.learncpp.com/cpp-tutorial/an-introduction-to-stdstring/
		
		string str{};
		
		此时不能用std::cin,改为使用
			std::getline(std::cin,age),但使用时需要删除换行符,否则换行符会被认为改行已经结束。
			
		int main()
		{
			int choice{};
			std::cin >> choice;
			std::cin.ignore(32767,'\n');  忽略最多32767个字符直到删除'\n'
			
			std::cout << "enter name" ;
			std::string name{};
			std::getline(std::cin,name);
			
			std::cout << name << choice << std::endl;
			return 0;
		}
		
		std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
				->忽略最大流输入的所有 直到删除\n。
				
		string append 
		
		    a + b 
		
		string 长度
			a.length()  -> 得到的是char 的长度。
	
	}
	8.2 Using a language reference  {}
	
	8.3 Enumerated 枚举类型
	{
		enum Color
		{
			color_black,
			color_red,
			color_green,
			color_white,
			...		
		};    ->枚举类需要加;结尾
		
		使用->
			Color paint{color_black};
			
		枚举类型会默认赋值0,1,2,3,4,5,6,。。
	}
	
	8.4 Enum class 枚举类
	{
		由于枚举类型会赋初值,有可能出现不同枚举出现相同值而被系统认为相同的情况。
		此时使用枚举类。
		
		
		enum class Color
		{
			red,
			blue
		};
		enum class Fruit
		{
			banana,
			apple
		};
		
		Color color {color::red};
		Fruit fruit{Fruit::banana};
		
		color == fruit -> 报错。 系统无法比较不同枚举类
		
		可以通过static_cast<int>(color)来强制将这个枚举类转换为整型。
		
	
	
	}
	8.5 结构体 Structs
	{
		struct Employee
		{
			int id{0};
			int age{0};
			double wage{0};
		};
		
		
		//使用 
		Employee joe{};
		//Employee donald{};
		
		joe.id = 14;
		joe.age = 32;
		joe.wage = 24.15;
		
		Employee donald{1,24,500000.0};
		
		
		Employee Donald{donald};  //为新的结构体复制一份原来的值。
		
		
		函数也可以返回结构体。
		
		Employee GetEmployed()
		{
			return {0,0,10000};
		}
		
		结构体可以嵌套结构体。
		
		结构体的大小
		sizeof(Employee)->  
			得到的大小为当前结构体的最大数据类型的大小,
			比如这里会得到16 (double的大小)
	}
	
	8.6 !随机数生成器
	{
		生成随机数依赖于伪随机数生成器(PRNG)
		
		包含一个起始数字(种子)。->经过运算 -> 生成随机数 -> 新种子。
		
		种子一般只播种一次。
		
		内置伪随机数生成器 -> 需要包含#include <cstdlib> 
		需要调用的函数 std::rand()  std::srand()
		
		
		int main()
		{
			std::srand(5253)  //播种5323  
				想要实现高随机可以尝试将当前世界时间(基本不可重复)作为种子播种进去。
			std::rand();   ->得到一个随机值,第一次调用不使用以便获得更好的随机效果。
			
			for(int count{1};count <= 100; count++)
			{
				std::cout<< std::rand()<< endl;
			}			
		}
		
		
		使用系统注册时间播种->
		std::srand(static_cast<unsigned int>(std::time(nullptr)));  //nullptr 指向空的指针 == 0
		
	
		<random>库中包含许多随机数生成器
		{
			#include <random>
			#include <ctime>
			
			int main()
			{
			//初始化种子
			std::mt19937 mersense{static_cast<std::mt19937::result_type>(std::time(nullptr))}
			
			//创建die随机数生成器
			std::uniform_int_distribution die{1,6};
			
			for(int count{1};count <= 48; ++count)
			{
				std::cout << die(mersenne) << '\t';
				
				
			
			}
			
			}
		
		}
	}
	9 Arrays 数组
	{
		9.1 Arrays
		{
		
		int testScore[30] {};
		
		int testScore[5]{1,3,57,2,3};
		
		int testScore[5]{1,3,5};  //声明5个但只初始化3个,其他的会默认为0
		
		}
		
		
		9.2 Arrays
		{
			Arrays的长度  sizeof(Arr)/sizeof(Arr[0]);
			
			std::size(Arr);   // 需要 #include <iterator> // for std::size
			->这个得到的是子元素个数
			
			C++不会对数据Arr大小进行检查,若超过Index 将随机修改内存值!!
		}
		
		9.3 Arrays Loop
		{
			for(int i{0};i < std::size(scores); i++)
			{
				...
			}
			
			
			for (auto i : Arr)  //int,float....
			{
			
			
			}
		}
		
		
		9.4 Sorting an array using selection sort 
		{
			工作原理  ->  std::swap(a,b)
			
			https://www.learncpp.com/cpp-tutorial/sorting-an-array-using-selection-sort/
			1.选择排序
			
			使用<std::algorithm>命名空间  来调用std::sort()函数
			
			
			std::sort(std::begin(Arr),std::end(Arr));
		}
		
		9.5 Multidimensional Array 多维数组
		{
			int Arr[3][4];   -> 3行4列数组
			
			int Arr[3][5]
			{
				{1,2},		->  1,2,0,0,0
				{3,4,5},	->  3,4,5,0,0
				{6,7,8,9}   ->  6,7,8,9,0   
			};
		}
		
		9.6 C-style string
		{}
		
		9.7 String_View
		{
			https://www.learncpp.com/cpp-tutorial/an-introduction-to-stdstring_view/
		
			c++ 17  -> string_view
			String_View  提供一个可观测string(指向该地址,不另外声明空间),不允许修改。
			
			陷阱-> string_view 末尾没有'\0' ! 使用时注意边界。
			
			string_view 指向的字符串不能在string_view被销毁前被回收。
		
			std::string_view text{"hello"} 。
		
		}
		
		9.8 Pointer
		{
			int x{5};   // 
			std::cout << x << "\n" ;    ->5   		
			std::cout << &x << "\n" ;   ->0027FEA0  存放该值的内存地址
		
			间接操作符 *
			
			std::cout << *(&x) << "\n"  -> 5    取地址存放的值
			
			声明一个指针    	int *Ptr{};
			声明指针指向地址 	int *Ptr{&x};
			
			C++也不允许将文字内存地址转换为指针比如int *Ptr{0027FEA0} 非法
			
			
			&x 返回的是一个包含操作数地址的指针  比如一个指向x的地址的Pointer
			typeid(&x).name()  ->   int *  
			
			
			int* ptr{&x}    声明指针指向地址,指针值代表地址,*指针*Ptr代表取地址
			
			cout<< ptr   ->   0027FEA0
			cout<< *ptr  ->   5

		}
		
		9.9 null Pointer 空指针
		{
			声明空指针 
			float *ptr{0};
			int *ptr1{NULL};  //使用Null 需要引用 #include <cstddef>
			
			
			int main()
				{
					int* ptr{ 0 };
					//int* ptr;     现在未初始化的指针使用会报错

					if (ptr)
						cout << "1" << endl;
					else
						cout << "2" << endl;
				}
				
				
			C++ 11 空指针->   nullptr 
			int *ptr{nullptr};
			
			nullptr 可以隐式转换为任何指针类型,包括函数类型。
			比如可以先声明nullptr给需要函数指针的函数,或者预置初始值。
			
			
			!声明函数指针
			{
				void useFun(int x, int (*ptr)(int funParameter))   //重点在声明这里
				//注意函数名本身就是指针   所以 可以直接声明int Fun(int funParameter)
				//也可以int x, int (*Fun)(int funParameter)  
				//在这里(*Fun) == Fun
				{
					cout << (*ptr)(x) << endl;   //这里使用了函数指针。调用时直接用函数名
				}

				int Fun(int x)
				{
					return (x + 3);
				}
				int main()
				{
					useFun(5, Fun);  //函数名就是指针
				}
			
			}
			
			
			nullptr_t  类型,也在#include <cstddef>
			
			只能存放nullptr  无法转换。
		}
		9.10 Pointer And Array
		{
			https://www.learncpp.com/cpp-tutorial/pointers-and-arrays/
			
		}
		9.11 Pointer arithmetic and array indexing 
		{   指针算术与索引
			
			int value{7};
			int* ptr{&value};
			
			cout << ptr <<endl;    ->value 内存地址
			cout << ptr +1 <<endl; ->value 内存地址加4位
			cout << ptr +2 <<endl; ->value 内存地址加8位
			
			+多少位取决于 ptr的类型大小
			
			
			对可迭代元素Arr,
			使用std::begin() std::end()
			可获得Arr的首尾地址。

		}
		9.12 C-style Pointer
		{
			const char* name{"donald"};  赋值字符串数组?
			
			char name1[]{"donald"};
			
			
			这里声明的指针的地址不可变。
		
		}
		9.13 Dynamic memory allocation with new and delete
		动态分配内存  allocation  new delete
		{
			https://www.learncpp.com/cpp-tutorial/dynamic-memory-allocation-with-new-and-delete/
			
			动态分配内存可以使用 
			new int 关键字 
			
			new int;  -> 返回一个声明了一个int的地址。使用指针接收
			
			//动态分配内存
			int *ptr{new int};
			//动态分配内存并初始化
			int *ptr{new int(5)};
			int *ptr{new int{5}};
			
			
			!使用完以后记得删除
			delete ptr;  
			ptr = nullptr;  指针指向0    //C++ 11 nullptr   以前 0
			
			
			delete实际上并不删除,
				但其告诉操作系统当前内存可以被覆盖了
			此时ptr 成为悬挂指针,比较危险(可能不知道改了哪里的参数)
			所以delete后 需要将ptr 指向空。
			
			
			使用new (std::nothrow) int;  在分配内存失败时会指向空
			这样可以防止程序报错。
			
			int *ptr = new (std::nothrow) int;
			
			
			!内存泄漏  (存在操作系统无法使用而本身程序也不再指向的内存地址)
			{
				int value = 5;
				int *ptr{ new int{} }; // allocate memory
				ptr = &value; // old address lost, memory leak results
			
				!这里ptr造成了内存泄漏,声明的int没有delete。
			
			}
		}
		9.14 Dynamically allocating arrays
			动态分配数组
		{
			new []
			delete []
			
			{
				int *Arr{new int[]{}};
				
				delete[] array;
			}
			
			动态分配一个较大的内存空间
			int length{10000000};
			int *array{new int[static_cast<std::size_t>(length)]{}};
			
			删除数组必须使用delete[]  否则会造成内存泄漏
			
			
			
			动态分配并初始化		
			int *Arr{new int[5]{1,2,3,4,5}};
			int *Arr{new int[5]{0}};
			
			auto *Arr{new int[5]{1,2,3,4,5}};
			
		
		}
		
		9.15 Pointer and Const  常量
		{
			https://www.learncpp.com/cpp-tutorial/pointers-and-const/
			很花哨的知识点。。用这么花真的好吗
		
			非const 指针无法指向const 常量
			const int x{5};
			int *ptr{&x};  -> 编译错误
			
			
			因此要指向常量就要建立常量指针。 const int* 
			const int x{5};
			const int* ptr{&x}
			
			
			但常量指针可以指向非常量
			int x{5};
			const int* ptr{&x};  ->合法
			
			int* const ptr{&x};   //ptr将始终指向value
			*ptr = 6;  //允许,x为非常量,这里只限制地址。
			
			
			//初始化后不允许任何修改,包括值和地址(只包括指针对其操作)
			const int* const ptr{&x}; 	
		}
		9.16 引用变量 类似于创建别名 &
		{
			int x{ 5 };
			int& y{ x };  //  y  引用x   &x,&y输出一样的内存地址
		
		
			注意const 值不能声明引用,因为引用会改真值
			
			引用一般作为函数参数传入(如果需要更改的话)
			
			注意如果参数包含常量,不能传入,否则会编译报错
			
			void swap(int& a,int&b)
			{
				...
			}
			
			
		
		}
		9.17 常量引用
		{
			
		}
		9.18 成员选择与引用
		{
			使用.
			struct Student
			{
				int age{};
				double weight{};
			};
			
			Person person;
			
			person.age = 5 ;
			
			创建指向结构的指针,获取对象使用->
			Person* ptr{&person};
			
			ptr->age = 15;  //和 (*ptr).age 作用一样	
		}
		
		9.19 foreach循环   C++ 11
		{
			for(auto i : Arr)
			{
				
			}
			
			需要更改其值  声明引用
			for(auto& i : Arr)
			{
			
			}
			
			foreach不能遍历指针数组const int array[]与动态数组
		
			
			c++20
			{
				可以添加索引了
				
				for(int index{0};auto i : Arr)  //index 为当前索引
				{
				
				}
			
			}
		}
		9.20 Void指针
		{
			#http://c.biancheng.net/view/429.html
			void* void_ptr;
			
			void 类型指针可以指向任何对象。
			但这个指针不知道具体是什么类型,所以使用需要进行强制转换。
			
			int* int_ptr{static_cast<int*>(void_ptr)};
		}
		
		9.21 指向指针和多维数组指针
		{
			可选
			指向指针的指针
			
			int **ptrptr = &ptr;
			
			动态分配数组指针
			int **Arr = new int*[10];
			
			二维 ->
			
			int (*Arr)[5] = new int*[10][5];
			或者
			auto Arr1 = new int[10][5];
		
		}
		9.22 std::array   std::标准库中
		{
			#include <array>
			
			std::array<int,3> Arr;
		
			C++ 17(提供省略写法) -> std::array Arr;
			
			访问允许使用下标运算符[],但其不进行边界检查。
			使用Arr.at(5) 会进行边界检查
			
			Arr.size()
			
			函数使用时传入const std::array<int,5> &myArray
			->防止其复制一遍
			
			for (int i{ 0 };i < Arr.size(); i++)
			//这里有错误,因为有符号不匹配。
			//i的类型不对。
			应该改为
			for (std::array<int,5>::size_type i{ 0 };i < Arr.size(); i++)
			或者使用auto自己找
			for (auto {Arr.size() - 1};i >= 0; i--)
			-> 但这样会存在死循环。(比如数组为0)
			可以再改进加入限制条件等
	
			或者使用foreach 索引
			for(auto i : Arr)
			{...}

		}
		
		函数参数传递 ->
			值传递   Fun(A a) ->适合通用类型,会复制,如果有构造和析构会耗费性能
			引用传递 Fun(A& a) -> 会改变值,不会复制提高性能
			const 引用传递  Fun(const A& a) 不会复制提高性能,不能改值
		
		9.23 std::vector 动态数组
		{
			#include<vector>
			
			std::vector<int> Arr{1,3,42};
			
			Arr.size();
			
			Arr.resize(5);   将Arr大小放大为5
		}
		
		9.24 iterator 迭代器
		{
			
		
		}
		9.25 standard library algorithm 标准算法库
		{
			#include <algorithm>
		
			1.	std::find
			{
			auto Found{std::find(Arr.begin(),Arr.end(),search)}
				——>得到的Found是一个迭代器,其指向我们找到的元素
				->没有则指向最后一个元素Arr.end()  ->内存地址
			}
			
			2. std::find_if(Arr.begin(), Arr.end(), FindFun)
			{
				我们提供条件的bool函数FindFun,
				——>得到的Found是一个迭代器,其指向我们找到的元素
				->没有则指向最后一个元素Arr.end()  ->内存地址
			
			}
			
			3. std::count 计数
			{
				count(Arr.begin(), Arr.end(),Num)
			}
			
			4. std::count_if
			{
				count_if(Arr.begin(), Arr.end(),CountFun) //CountFun : bool
			}
			5. std::sort 
			{
				sort(Arr.begin(), Arr.end());  ->升序
				
				sort(Arr.begin(), Arr.end()).std::reverse();  ->降序
				
				sort(Arr.begin(), Arr.end(),SortFun); //SortFun : bool true-> change			
			}
			6. std::foreach
			{
				foreach(Arr.begin(), Arr.end());
			
			}
			7. 可以保证顺序执行的算法
			{
				std::for_each()
				std::copy()
				std::copy_backward()
				std::move()
				std::move_backward()
			}
			
			C++ 20 添加了 ranges 取代 std::begin 和 std::end 
			
		}
		
	}
	
	10.Function
	10.1
	{
		函数参数与参数
		
		形参 parameter
		实参 argument
	
	}
	
	10.2
	{}
	10.3 引用传递
	{
		void Fun(A &a);
		
		void Fun (const A& a);
		
		可以在函数参数命名时带Out 如 int& cosOut 来说明这个函数会改变这个值
	}
	
	10.4 地址传递
	{
		函数可以更改指针从而使其指向新的值或者nullptr
		
		void Fun(int *ptr)
		{
			*ptr = 3;   //更改值
			ptr = nullptr;  //更改指向地址 
		}
		
		传递数组时必须把数组的长度作为参数传入,因为
		数组名会变换为指针传入
		Void Fun(int *Arr,int length)
		{
			if(!Arr) return; //空指针检验
			
		}
		
		
		传递常量地址
		void Fun(const int* Arr,int length)
		{}
		
		
		传递指针时其实是把地址作值传递
		void Fun(int *ptr)
		{
			*ptr = 3;   //更改地址所指向的值->  会在全局修改 
			ptr = nullptr;  //更改指向地址 -> ptr时形参地址,所以改的地址只在本函数有效
		}
		
		例子
		int five{ 5 };
		int* ptr{ &five };
		
		
		std::cout << ptr << endl;   //-> 003FFD1C
		Fun(ptr);
		std::cout << ptr << endl;   //-> 003FFD1C
		
		创建可以在函数内部修改指针地址的函数 -> 传递引用指针
		Void Fun(int *& ptr)
		{
			ptr = nullptr;   //会全局更改
		}
		
		
		fun (int x)   -> 值传递
		fun (int &x)  -> 引用传递
		fun (int *x)  ->地址传递
		
		
	
	}
	
	10.5{}
	
	10.6 inline function   内联函数
	{
		对于小巧函数(内部实现简单功能) -> 大量函数调用增加了性能开销,
		使用inline函数  可以使编译器在编译该函数时就地展开,编译的代码会更大。
		
		inline int Fun(a,b)
		{
			return a>b? a:b;
		}
		
		
		inline 仅仅是建议,编译器考虑函数不适合内联并不会对其进行内联操作
	
	
	
	}
	10.7 函数重载
	{
	
	}
	10.8 默认参数
	{
		void Fun(int a = 3)
		{}
	}
	10.9 函数指针
	{
		int Fun1()
		{}
		
		int Fun2()
		{}
		
		
		int main()
		{
			int *(funPtr){&Fun1};  函数指针指向Fun1 
			funPtr = &Fun2;        函数指针改为指向Fun2
			
			return 0;
			
			
		
		}
		
		
	
	}
	
	
	
	















}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值