那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥

一、C++基础语法

类型转换

切勿混用无符号类型和有符号类型
表达式中两者都有时,有符号类型会转化为无符号类型,当该值为负时会出现非预期结果;

unsigned a = 1; int b = -1; cout<<a*b;//输出 4294967295
//详解: b的源码:100...1 负数转补码按位取反加1后为:1111...0  无符号类型把该值读出为4294967295 (结果视所在机器位数而定)

无符号类型用于循环时注意其永远不会小于0的特性

转义序列和指定类型

那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥_第1张图片
在这里插入图片描述
注意:“\1234” 前3个构成转义序列八进制对应的asill值

那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥_第2张图片
注:表示长整型时用L而不是小写 l 它和 1 容易弄混;

后缀的存在是为了明确指示字面值的数据类型,从而避免编译器的隐式类型转换或产生二义性。然而,并非所有数据类型都需要后缀,因为它们的类型可以根据字面值的形式自动推断出来。此外,使用错误的后缀可能导致编译错误或运行时错误,因此需要小心使用。C++弄啥呢?这玩意儿真的是服了,哎

那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥_第3张图片

(a) 字符  宽字符型字符(wchar_t类型)  字符串  宽字符型字符串
(b) 整数  无符号数  长整数  无符号长整数  八进制数  十六进制数
(c) 浮点型   单精度浮点型   long double类型的扩展精度浮点型 
(d) 整数  无符号整数 浮点数  科学计数法表示的浮点数

变量初始化 不等于 赋值 (初始化是创建变量并赋予一个初始值,赋值是擦除当前值用新值代替)
变量声明 规定了变量类型和名字,定义 除此之外还申请了存储空间,可能还会赋初始值。(建议初始化每一个内置类型的变量)

extern int i; //声明 i 
int j;//声明并定义 j
extern int k = 3; //赋初始值抵消了extern的作用变成了定义,且如果是在函数内部初始化extern标记的变量会报错

变量必须且只能在一个文件中定义一次,其他文件中使用到该变量的必须进行声明,却绝对不能重复定义!(变量能且只能被定义一次,但是可以被多次声明)

标识符的命名规范
由字母、数字、下划线组成,且必须以字母或下划线开头。
不能作标识符规范

  • 一些作为C++语言的使用的关键字,如if、int、false等
  • 一些作为C++标准库的保留字,不能连续两个下画线,不能下画线连大写字母开头,
  • 定义在函数体外的标识符不能以下划线开头

推荐的标识符规范

  • 见名知义,能体现实际含义好懂
  • 变量名小写字母,如 index
  • 类名大写字母开头,如Index
  • 标识符多字母组成采用下划线分割或大写字母开头分割,如student_loan_up或studentLoanUp

作用域
全局作用域和块作用域
作用域嵌套,外层作用域声明某名字,其嵌套的作用域也就是内作用域都能访问该名字,同时允许内层作用域重新定义外层作用域已有的名字。

引用和指针的主要区别

  1. 引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。
  2. 不能有 NULL 引用,引用必须与合法的存储单元关联(指针则可以是 NULL)。
  3. 一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。

https://www.runoob.com/w3cnote/cpp-difference-between-pointers-and-references.html

使用未经初始化的指针容易引发错误,因此不知道指向具体对象时初始化为nullptr ,如:int *p = nullptr;
因此要判断一个指针是否指向合法地址,判断是不是nullptr即可,或者如果没有初始化指针的话可以try…catch是否出错。

void* 是一种特殊的指针类型,可以存放任意对象的地址。

int* p和 int *p的问题,其实基本类型是int的p是指向int的指针;所以建议采用第二种写法,int *p1, *p2;

指向指针的指针,为了访问原始对象,需要解引用两次;
指向指针的引用,引用本身不是对象因此不能定义指向引用的指针,但是指针是对象,所以存在对指针的引用;

int i = 33;
int *p;//int 类型的指针p
int *&r = p;//从右往左看,r 是 对指针p的引用
r = &i;//r是指向p的引用,给r赋值&i 就是让p指向i
*r = 0;//解引用 r 得到 i,也就是p指向的对象,改i的值为0

面对复杂的指针或引用声明语句时,从右向左阅读有助于弄清真实含义;

定义一个const变量在多个文件中声明并使用它的方法是,不管是定义还是声明都加extern关键字;

extern const int bufsize = fcn();//1.cc定义并初始化一个常量,并让该常量能被其他文件访问

** 底层const和顶层const? **

常量表达式:值不会改变并且编译过程就能得到计算结果的表达式
比如 const staff_size = get_size(); 就是不是,因为其到运行时才能获取到,const int limit = 20;才是常量表达式

C++11 :如果你认定变量是一个常量表达式,那就把它声明成 constexpr 类型;

auto类型推导
1、使用引用作初始值时,以引用对象的类型作为auto的类型;
int i = 0, &r = i;
auto a = r; //a 类型为 int
2、auto会忽略顶层const、保留底层const;
auto &h = 42; //非常量引用需要绑定一个可修改的对象;
const auto &j = 42;

Everything should be made as simple as possible, but not simpler

类是对象的抽象和统称,对象是类的实例;

浅拷贝:只拷贝指针地址,C++默认拷贝
构造函数与赋值运算符重载都是浅拷贝;
节省空间,但容易引发多次释放;
深拷贝:重新分配堆内存,拷贝指针指向
内容。
浪费空间,但不会导致多次释放;

写时复制

二、C++指针

未初始化和非法的指针,用指针间接访问一定要非常小心确保已初始化并恰当的赋值!
1、如果开始不知道或者不用的时候指向何处可以初始化为null
2、在对一个指针间接引用前,确定指针的值是否为null;

int *a;//未初始化化
*a = 12//非法访问

运气好定位到非法地址,程序出错终止,运气差定位到一个可以访问的地址并修改了它,错误难以捕捉,引发的错误可能完全想不到!

左值和右值
那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥_第4张图片
=号左边为左值,=号右边为右值。左值取的是如上图cp+1处的内存空间,右值取的是内存空间的值;

char ch = 'a';
char *cp = &ch;

关于++++,----等运算符:
编译器程序分解成符号的方法是:一个字符一个字符的读入,
如果该字符可能组成一个符号,那么读入下一个字符,一直到读入的字符
不再能组成一个有意义的符号。这个处理过程称为“贪心法”。
例如:int a=1,b=2;c;
c=a+++b;/∥相当于a+++b
d=a++++b;/∥相当于af+++b,error

那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥_第5张图片
代码和数据在C++程序中的存储;

那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥_第6张图片
那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥_第7张图片

RAlI(Resource Acquisition Is Initialization) :
C++所特有的资源管理方式。有少量其他语言,如Rust也采纳了RAlI,但主流的编程语言中,C++是唯一一个依赖RAII来做资源管理的。RAlI依托栈和析构函数,来对所有的资源——包括堆内存在内进行管理。
对RAll的使用,使得C++不需要类似于Java那样的垃圾收集方法,也能有效地对内存进行管理。RAll的存在,也是垃圾收集虽然理论上可以在C++使用,但从来没有真正流行过的主要原因。
RAll有些比较成熟的智能指针代表:如std:auto_ptr和boost:shared_ptr

那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥_第8张图片

内存泄漏(Memory Leak)问题
什么是内存泄漏问题:
指程序中己动态分配的堆内存由于某种原因程序未释放或无法释,
造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。
内存泄漏发生原因和排查方式:
1.内存泄漏主要发生在堆内存分配方式中,即“配置了内存后,所有指
向该内存的指针都遗失了”。若缺乏语言这样的垃圾回收机制,这样的内存
片就无法归还系统。
2.因为内存泄漏属于程序运行中的问题,无法通过编译识别,所以
只能在程序运行过程中来判别和诊断。

C++中推出了四种常用的智能指针:
unique_ptr、shared_ptr、weak_ptr;
auto_ptr:C++11中已经废弃(deprecated)的在C++17中被正式删除;

那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥_第9张图片

那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥_第10张图片
使用问题
那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥_第11张图片
所有权问题
那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥_第12张图片
循环引用:引用记数带来循环引用问题,导致堆内存无法正常回收,造成内存泄漏问题

那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥_第13张图片

C++引用
那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥_第14张图片

函数中对于基本类型来说,pass by value更高效,对与自定义类型来说,pass by reference to const更高效;

杜绝“野”指针
指向“垃圾”内存的指针。if等判断对它们不起作用,因为没有置NULL;
一般有三种情况:
1.指针变量没有初始化;
2.已经释放不用的指针没有置NULL,如delete和free之后的指针;
3.指针操作超越了变量的作用范围;

指针使用的注意事项:
没有初始化的,不用的或者超出范围的指针请把值置为NULL。(很难啊,指针在多个地方使用,很难确定什么时候不用了,解决方案:智能指针)

空指针是指向null的指针用于内存初始化指针变量,内存编号0~255是系统占用内存不可访问;
野指针是指向非法的内存空间的指针,两者访问应该都会报错,但是在Dev下运行如下代码:编译无误还能运行,只不过会无输出,运行一段时间后窗口自动关闭,这是为什么?

#include 

using namespace std;

int main(){
	int a = 10;
	int *p = NULL;
	cout << *p <<endl;
	
	int *q = (int *)0x1110;
	cout << *q <<endl;
	return 0;
}

虽然语法无误可以通过编译器,但是由于解引用空指针和野指针导致的内存访问违例,操作系统为了保护系统终止了该程序的执行。

那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥_第15张图片
机器真正的存法:正数直接存,负数保留符号位按位取反+1;
大端序是网络中普遍用的符合人类阅读习惯,小端序大多数个人PC用的,符合机器;

那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥_第16张图片

那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥_第17张图片
这个非常重要一定要注意!!!
那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥_第18张图片
Redis中设计的sdshdr结构体有个len变量存字符串长度,不用遍历去算;有个free管理剩余容量,如果容量不够会自动扩容并修改len大小;

指针和引用

那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥_第19张图片

指针的数组(array of pointers),这个数组里一个个的都是指针 。 T *t[ ]
数组的指针(a pointer to an array),这一个指针指向一个数组。T (*t) [ ]

那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥_第20张图片
第三个例子先看第一个const修饰的左边char表示指针的值不可改,再看第二个const修饰的*,表示指针的指向不能改;

const修饰指针有三种情况

  1. const修饰指针 — 常量指针(指针指向可改,指向的值不可改)
  2. const修饰常量 — 指针常量(指针指向不可改,指针的值可以改)
  3. const即修饰指针,又修饰常量(都不能改)

看const右侧紧跟着的是指针还是常量, 是指针就是常量指针,是常量就是指针常量

const常用来防止误操作

三、C++STL库

stl库的六大组件
那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥_第21张图片
六大组件的关系
那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥_第22张图片
容器用于存放数据;STL的容器分为两大类:
序列式容器(Sequence Containers):
其中的元素都是可排序的(ordered),STL提供了vector,list,deque等序列式容器,而stack,queue,priority_queue则是容器适配器;
关联式容器(Associative Containers):
每个数据元素都是由一个键(key)和值(Value)组成,当元素被插入到容器时,按其键以某种特定规则放入适当位置;常见的STL关联容器如:set,multiset,map,multimap;

#include 

using namespace std;

struct Display{
	void operator()(int i){
		cout << i << " ";
	}
};

int main(){
	int arr[4] = { 1, 2, 3, 4};
	vector<int> vec(arr, arr+4);//动态数组 
	list<int> lis(arr, arr+4);//链表 
	deque<int> deq(arr, arr+4);//双端队列
	queue<int> que(deq);//队列 
	stack<int> sta(deq);//栈 
	priority_queue<int> prique(arr, arr+4);//优先队列 
	
	for_each(vec.begin(), vec.end(), Display());
	for_each(deq.begin(), deq.end(), [](int i){
		cout<< i << " ";
	});
	
	while(!que.empty()){
		cout << que.front() << " ";
		que.pop();
	}
	while(!sta.empty()){
		cout << sta.top() << " ";
		sta.pop();
	}

	cout<<endl;
	map<string, int> studentlevel;
	studentlevel["level1"] = 1;
	studentlevel["..."] = 3;
	studentlevel["level6"] = 6;
	studentlevel.insert(pair<string, int>("level4", 4));
	for_each(studentlevel.begin(), studentlevel.end(), [](pair<string, int> i){
		cout<<i.first<<":"<<i.second<<endl; 
	});
	
	map<string, int>::iterator iter = studentlevel.find("level6");
	if(iter != studentlevel.end()){
		cout<<"level6 超能力者人数:"<<iter->second<<endl; 
	}
	
	return 0;
}

**非常需要注意:**谨防迭代器失效的问题,比如 iter = studentlevel.earse(‘‘cc’’); 使key为cc的值删除,返回下一个位置的迭代器;
(*it).empty(); 简化后it->empty();

凡是使用了迭代器的循环体,都不要向迭代器所属容器添加元素;
比如push_back可能导致vector对象的迭代器失效;
比如范围for循环向vector添加元素

仿函数(functor)

  • 仿函数一般不会单独使用,主要是为了搭配STL算法使用。
  • 函数指针不能满足STL对抽象性的要求,不能满足软件积木的要求,无法和STL其他组件搭配;
  • 本质就是类重载了一个operator(),创建一个行为类似函数的对象

从函数指针–>泛型->仿函数->仿函数模板;懒

算法(algorithm)
STL中算法大致分为四类:包含于,,
1.非可变序列算法:指不直接修改其所操作的容器内容的算法;
2.可变序列算法:指可以修改它们所操作的容器内容的算法;
3.排序算法:
包括对序列进行排序和合并的算法、搜索算法以
及有序序列上的集合操作;
4.数值算法:
对容器内容进行数值计算;
最常见的算法包括:
查找,排序和通用算法,排列组合算法,数值算法,集合算法等算法

transform();容器计算函数;count统计函数;binary_search();二分查找;

int main(){
	int arr[] = {1, 1, 1, 2, 2, 3, 4, 5, 5, 6};//父序列 
	vector<int> zi(arr+2, arr+6); //子序列 
	int len = sizeof(arr)/sizeof(arr[0]);
	cout << count(arr, arr+len, 1) << endl; 
	cout << count_if(arr, arr+len, bind2nd(less<int>(), 4)) << endl; 
	cout << binary_search(arr, arr + len, 6)<<endl;
	cout<< *search(arr, arr+len, zi.begin(), zi.end()) << endl;
	return 0;
}

手写全排列的实现

输入一个不存在重复字符的全字符串,打印出字符串中字符的全排列
比如 123
输出
123
132
213
231
312
321

stl中的全排列函数next_permutation()以及prev_permutation();

#include 

using namespace std;

void swap(char*a, char *b){
	char tmp = *a;
	*a = *b;
	*b = tmp;
}

void permutation(char *ptr, char* postion){
	if(*postion == '\0'){
		cout << ptr <<endl;
	}
	for (char* pChar = postion; *pChar != '\0'; pChar++){
		swap(*pChar, *postion);
		permutation(ptr, postion + 1);
		swap(*postion, *pChar);
	}
}

int main(){
	char test[] = "321";
	permutation(test, test);
	return 0;
}

手写GC

boost库

Boost库是为C++语言标准库提供扩展的一些C++程序库的总称,由Boost
社区组织开发、维护,Boost库可以与C++标准库完美共同工作,并且为其
imooc
提供扩展功能;
Boost可为大致为20多个分类:
字符串和文本处理库,容器库,算法库,函数对象和高阶编程库,综合类库
等等;
官网:https://www.boost.org/
镜像:https://dl.bintray.com/boostorg/release/

目前多数boost库的功能多数标准库都有了???黑人问号脸

其他库

基于C++14/17的Http应用框架Drogon: https://github.com/drogonframework/drogon/blob/master/README.zh-CN.md(《权力的游戏》中的一条龙的名字(汉译作卓耿))
grpc翻译的中文文档:https://doc.oschina.net/grpc?t=58008 (跨平台 的RPC框架),解释:https://juejin.cn/post/7047885453336248327
腾讯开源的rpc框架phxrpc:https://gitee.com/mirrors/PhxRPC#https://gitee.com/link?target=https%3A%2F%2Fgithub.com%2FTencent%2Fphxrpc%2Fwiki
https://github.com/Tencent/phxrpc

四、C++设计模式

根据前人的经验对一些普遍存在的问题提供的通用的解决方案在软件中有常见的23种面向对象可复用的设计模式。
设计模式也是有代价和适用场景的不是万能的,这23种实际上适合那种扩展性比较强将来会在大量场景中不断重复的使用并且做一些变化的场景中使用;

单例模式
那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥_第23张图片

Observer模式

那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥_第24张图片
实现思路:
将问题的职责解耦和,将Observable和observer抽象开,分清抽象和实体;

class Observer
public:
	Observer();
	virtual ~Observer();/当被观察对象发生变化时,通知被观察者调用这个方法
	virtual void Update(void* pArg) = 0;
}


class User1:public Observer
virtual void Update(void* pArg)
cout <<"User1 Got News:" << endl;
1class User2 :public Observer
virtual void Update(void* pArg)
cout <<"User2 Got News:" << endl;
1

void,NULL和nullptr是啥?
void*是一个通用指针类型,可以指向任意类型的数据。它不直接关联到特定的数据类型,因此无法进行解引用操作,需要进行显式的类型转换才能使用。例如:

void* ptr = nullptr; // ptr是一个空指针
int* intPtr = static_cast(ptr); // 将void指针转换为int指针
在较旧的C++版本中,NULL被定义为整数0。这意味着它可以用作指针的空值。然而,使用整数0可能会导致一些歧义,因为0也可以是其他整数类型的值。在现代C++中,推荐使用nullptr代替NULL。例如:

int* ptr = nullptr; // ptr是一个空指针
nullptr是C++11引入的关键字,用于表示空指针。与NULL相比,nullptr具有更好的类型安全性。它可以隐式转换为任意指针类型,并且不能与其他整数类型发生混淆。例如:

int* ptr = nullptr; // ptr是一个空指针

指针是一个变量,用于存储内存地址,可以通过解引用操作符*来访问指向的数据。空指针表示指针不指向任何有效的内存地址。在C++中,使用这些概念可以方便地处理指针为空的情况,避免出现未定义行为或错误。

那个学C++不没有点大病?一点点癫狂的语法混乱版note和有一点点长的无语的标题,让人怀疑精神状态尼奥_第25张图片
23种面向对象设计模式从分类上大致有创建型,结构型和行为型模式;
设计模式不是万能的,它建立在系统变化点上,哪里有变化哪里就可以用;
设计模式为了解耦和,为了扩展,它通常是演变过来的,需要演变才能准确
定位;
设计模式是一种软件设计的方法,不是标准,目前前大部分的框架中都已经包
含了大量设计模式的思想;

你可能感兴趣的:(c++,java,开发语言,算法,面试,c语言)