软考学习笔记

因为二进制运算很麻烦,表示的位数很多,所以使用八进制和十六进制来缩短表示。
每3个二进制位代表一个八进制位
每4个二进制位代表一个十六进制位

源码,把一个数转化为二进制位,最高位是符号位,但是源码不能直接运算,所以提出了反码,补码,移码
反码,正数的反码不变,负数的符号位不变,其他位取反
补码,在反码基础上加一
移码,在补码基础上将最高位取反

寄存器,cache,内存,外存

内存按地址读取,cache按内容读写

cache提高速度的原因是有局部性原理

控制器靠指令指挥机器工作

——————————-

进程状态:
运行:获得了所有条件和CPU资源
就绪:获得了所有条件,只差cpu
等待:缺少条件,且没获得cpu资源

页号和页内地址
页号是逻辑地址,页内地址是数据大小或叫偏移量
页和块的大小是相同的,只不过块存储时不是连续的,是允许分散的

第几个字是从1开始
第几个位是从0开始

分层,缓存,映射,表,模块,分解,完备性

计算机原理
操作系统,数据库,网络通信,数据结构与算法,多媒体,设计模式,面向对象,数据流图

求候选键
找入度为零的键,看能不能遍历整个键
如果没有入度为零的的键,则从既有入度也有出度的键找找看,看有没有可以遍历整个网络的键
入度为零的键没有其他键能找到他

当一个关系中的所有分量都是不可分的数据项时,该关系是规范化的

非主属性:在某关系模式的一组属性中,如果一个属性有可能被选中作为主键(包括多主键的其中一个),它就是主属性,否则就是非主属性。

第一范式,原子属性。
第二范式,消除依赖关系。比如通过身份证号可以索引到姓名,那么身份证号和姓名就不应该同时出现。即如果x可以索引到y,那么x和y就不应该同时出现。
第三范式,消除传递依赖。即在第二范式的基础上,如果x可以索引到y,y可以索引到z,那么x和z也不应该同时出现

判断无损分解方法,表格法

事务,如银行转账,有收钱和加钱两个操作,这两个操作必须全部执行。事务就指要么全做,要么全不做

脏数据,临时数据

触发器,脚本

转储就是备份

—————————
网络通信
两个特殊的IP地址,假地址,代表服务器出故障了:
169.254.x.x(WIn)和0.0.0.0(Linux)

计算机网络分类:
总线型,星型,环形结构

IP地址:
网络地址+主机地址
全0代表网络地址,

子网掩码,用于划分子网:
1代表网络号
0代表主机号

127网段,回播地址

对称加密,加密和解密的密码一样

非对称加密技术
私钥只有自己有,公钥谁都可以有
甲可以用乙的公钥加密,然后乙就可以用乙的私钥解密了,通常使用对称加密来加密原文,使用非对称技术加密对称密钥的密钥

用私钥加密叫数字签名,对信息摘要加密,而不是对信息原文加密,因为原文信息量大

数字证书,类似身份证,绑定了持有者的信息和公钥

整除,也叫向下取整

数据传递分为:按值和按址

代码类型:编译型和解释型。主要区别在于,前者源程序编译后即可在该平台运行,后者是在运行期间才编译。所以前者运行速度快,后者跨平台性好。

编译型语言

使用专门的编译器,针对特定的平台,将高级语言源代码一次性的编译成可被该平台硬件执行的机器码,并包装成该平台所能识别的可执行性程序的格式。

特点

在编译型语言写的程序执行之前,需要一个专门的编译过程,把源代码编译成机器语言的文件,如exe格式的文件,以后要再运行时,直接使用编译结果即可,如直接运行exe文件。因为只需编译一次,以后运行时不需要编译,所以编译型语言执行效率高。

总结

1.一次性的编译成平台相关的机器语言文件,运行时脱离开发环境,运行效率高;

2.与特定平台相关,一般无法移植到其他平台;

3.现有的C、C++、Objective等都属于编译型语言。

作者:KID不务正业的程序员
链接:https://www.jianshu.com/p/54e2aeca013b
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

解释型语言

使用专门的解释器对源程序逐行解释成特定平台的机器码并立即执行。是代码在执行时才被解释器一行行动态翻译和执行,而不是在执行之前就完成翻译。

特点

解释型语言不需要事先编译,其直接将源代码解释成机器码并立即执行,所以只要某一平台提供了相应的解释器即可运行该程序。

总结

1.解释型语言每次运行都需要将源代码解释称机器码并执行,效率较低;

2.只要平台提供相应的解释器,就可以运行源代码,所以可以方便源程序移植;

3.Python等属于解释型语言。

作者:KID不务正业的程序员
链接:https://www.jianshu.com/p/54e2aeca013b
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

高内聚,低耦合,模块化设计,灵活性

测试,尽早测试,修改后进行回归测试

动态测试:黑盒测试,白盒测试,灰盒测试

静态测试:桌前检查,代码走查,代码审查

适配器模式,数据转换

值传递,指针传递,引用传递
值传递是拷贝一份数据到函数内,不影响原数据,指针传递是拷贝一份地址到函数内,引用传递是传递原数据到函数内

封装,继承,多态
多态有重载,重写,模版
Virtual关键字用于提醒编译器和用户,子类继承父类后需要重写该函数

C语言和c++中struct的区别
C语言中struct只能存储数据类型,没有访问控制权限,c++中struct可以存储数据类型和方法,默认访问权限public

C++中struct和class的区别
Struct默认访问权限是public,class默认访问权限是private,除此之外并无区别

封装:封装可以隐藏细节,使得代码模块化,形成高内聚低耦合,继承可以扩展已存在的类
多态的作用:隐藏细节,解决紧耦合问题,作为接口使用,通过接口指向不同的子类,使代码模块化,动态决策

面向对象三大特征封装,继承,多态
封装,使用class,private来实现;
继承,是为了复用
多态,是为了抽象,作为接口使用

内存的分配方式:
静态存储区,存储全局变量和静态局部变量
栈,存储局部变量
堆,存储new的变量

如何判断操作系统是16位还是32位?
定义一个指针p,sizeof(p),如果是4也是32位,如果是2,则是16位
不用sizeof判断,可以定义一个int a=0,然后对a取反,如果值大于65535,也是16位以上操作系统,如32位

为什么使用堆?
主要是动态申请内存,因为有些数据一开始不知道内存有多大,只有使用时候才知道

Malloc/free和new/delete
两者都是动态申请内存,但malloc不会调用构造函数和析构函数
因此提出new/delete主要是为了符合面向对象编程需求,语言构造和析构函数,
其次malloc是c语言的库函数,new是关键字是运算符
关键字就是预留字,不可以被作为变量名

为什么数组名作为参数传递可以改变其内容,而int不会?
数组名传递的是地址,因此可以修改内容,而int传递的是拷贝内容,因此不可以修改原数据内容

析构函数和虚函数
父类的析构函数要定义为虚函数,这样在销毁父类的时候也会销毁子类的析构函数
构造函数和析构函数
构造函数用于初始化类内数据,以后函数用于当函数的生命周期结束后释放类内数据,析构函数定义为虚函数是为了在销毁父类的时候也能把子类销毁掉,防止内存泄漏

转义字符
转义字符后边只能加3个八进制数,以及其他字符

引用和指针的区别?
指针传递的是地址,引用传递的是原数据。
引用必须被初始化,没有空引用,指针可以不被初始化。
引用初始化后不能被改变,指针初始化后可以改变指向的内容

重复调用fclose会怎样?
会导致文件描述符结构指针指向的内存被重复释放。可能这块内存释放后刚好被分配出去,写上了内容,这样再次调用fclose就会造成不可知的结果

重载,重写
重载是在同一个类中,函数名相同,参数类型不同或者参数个数不同,返回值无所谓。
重写是继承中,子类重新实现父类虚函数的方法

C++是不是类型安全的?
不是,两个不同类型的指针可以强制转换

Main函数之前会进行全局函数的构造函数

内联函数,类似于宏,在编译期编译器将内联函数内部的代码副本放在被调用的地方。我猜与函数的区别是没有函数跳转的开销,减少了函数跳转的开销

Const
修饰变量,将变量的权限变为只读
修饰指针,可以注释指针本身,也可以修饰指针所指向的内容
const int * pOne; //指向整形常量 的指针,它指向的值不能修改
int * const pTwo; //指向整形的常量指针 ,它不能在指向别的变量,但指向(变量)的值可以修改。
const int *const pThree; //指向整形常量 的常量指针 。它既不能再指向别的常量,指向的值也不能修改。
修饰函数的形参,表明传进函数的变量不能被修改。
修饰函数,表明这是一个常函数,其内部的变量不能被修改
修饰函数的返回值,表明改函数的返回值不不能作为左值

Debug模式和Release模式
Debug模式会保留调试信息,Release模式不会保留调试信息

Virtual关键字如果只在父类中有写,子类中没写,是否子类也能实现多态?
可以的,virtual是隐式继承的

如何打印当前文件名和行号?
使用预定义的宏 FILE

__FUNC__用于打印当前函数名

sizeof(void)=1

static作用,
修饰局部变量,用于只初始化一次局部变量
修饰函数和全局变量,用于限制函数和全局变量的作用域在本文件内

函数重载靠函数签名确定实际函数

模版和容器,常用容器有
vector,list,map,set

深拷贝和浅拷贝
主要是指针,深拷贝拷贝指针和内容,浅拷贝只拷贝指针

i++和++i
i++不可以当左值,++i可以当左值

不是所有的运算符都能被重载

sizeof用于判断一个变量或类型的大小,以字节为单位.sizeof用于指针时,因为指针指的是地址,所以sizeof返回的是计算机内部总线地址总数的宽度,在32位计算机中,一个指针的返回值必定是4

写一个能做左值的函数
能做左值的函数当返回值是引用的时候即可

指针和引用,指针传递的是地址,引用传递的是变量本身,操作指针如果指针越界会造成不可知的后果

不使用运算符计算a和b中的最大值
((a+b)+abs(a-b))/2

所有类型的指针变量在内存中占用的大小是相同的,即机器能寻址的字长

函数签名只包含函数名,参数类型和参数个数。返回值不作为函数签名部分

虚函数和纯虚函数,
虚函数是为了便于派生类重新定义基类的方法
纯虚函数的类叫抽象类,不能声明该类的对象,抽象类只是给派生类提供接口

多态
多态可以使用重载和重写来实现
重写通过子类重写父类方法来实现

虚函数和纯虚函数
定义一个函数为虚函数,不代表函数为不能被实现的函数,定义他为虚函数是为了允许用基类指针来调用子类的这个函数。
定义一个纯虚函数才代表函数没有被实现。
可参考菜鸟教程

编译时和运行时
编译时是编译器把源码编译为机器码
运行时是代码被装载在内存中进行运算

C++默认产生哪些函数?
默认构造函数,拷贝构造函数,赋值运算符,析构函数

拷贝行为,
使用等号赋值时,值传递传参时,返回值时,使用一个对象初始化另一个对象时

C++类中成员被声明static后有什么用?
成员变量被声明为static后,将被该类的所有实例共享这个变量

模板类和类模版
所谓类模版,实际上是建立一个通用类,其成员数据,成员函数的返回值类型和形参类型不具体指定,用一个虚拟的类型来代表。使用类模版定义对象时,系统会用实参的类型取代类模版中的虚拟类型从而实现不同的类的功能

哪些函数不能被声明为虚函数?
普通函数,即非成员函数。构造函数,内联成员函数,静态成员函数,友元函数

如果不声明一个析构函数,默认是非虚析构函数

结构体和共用体
结构体可以同时存储多种变量类型,而共同体同一个时间只能存储和使用多个变量类型的一种
共用体的作用是同一个数据项可以使用多种格式,可以节省空间。

Linux
查看磁盘使用空间,df -h
查看当前目录使用空间,du -ah .

如何查看cpu内存和系统版本
查看CPU cat /proc/cpuinfo 或动态查看cpu 使用top
查看内存 cat /proc/meminfo 或使用free -m
查看系统版本 uname -a

查看网络信息 netstat -anp
查看8080端口是否被占用 netstat -anp | grep 8080
其中grep用于查找文本里符合条件的字符串

查看进程信息 top
让进程按内存使用率排序,进去top后,按shift M即可,按shift p则按cpu使用率排序

查看网络ip,ipconfig

文件
访问方式:r-可读,w-可写,x-可执行
访问用户: u-所有者,g-所属组,o-其他用户
rwx rwx r-w 表示文件的所有者可读可写可执行,文件的所属组可读可写可执行,其他用户可读可执行,也可以表达为二进制数字111 111 101也可以表达为八进制数字775

umask -S可以查看或修改文件的默认创建权限
chmod
给指定用户添加指定权限chmod g+w test2.txt,代表给test2.txt的所属组添加可写权限,
chmod o-r test2.txt代表给test2.txt的其他用户去除可读权限
chmod【augo】 a代表所有用户,u代表所有者,g代表所属组,o代表其他用户
Chmod777代表所有用户具有所有权限
并非只有修改文件权限才能使用文件,也可以修改文件的所有者或所属组,通过chown和chgrp,这时候需要使用root用户,如chown cdq test2.txt

Linux系统操作权限
Su命令可以切换用户,如su root
Sudo 临时为用户提升权限
编辑sudo配置,输入命令visudo,然后输入:100跳转到100行

Grep用于过滤文本中想要的内容,如
Grep 'love' test.txt指的是在test.txt中筛选出有love的信息
-i可以不区分大小写,-n可以显示行号

Vim test.txt +1346打开文件跳转到行

Last查看最近登录信息

Find命令
Find大小写敏感
find ~ -name text.txt 在home目录下查找text.txt
find ~ -iname text.txt 在home下查找text.txt,大小写不敏感
find ~ -name text -8k查找小于8k的文件

Vector
vector添加元素push-back ,插入元素insert
删除通过erease
[]取值如果越界会发生未定行为,at取值如果越界会抛出异常
升序排序std:sort(ivector.begain(),ivector.end())
降序排序std:sort(ivector.begain(),ivector.end(),std:greater())
创建,增,删,查,改,排序

list排序,list.sort()

Uniq
用于过滤文件中多余的重复行
uniq text1.txt text2.text去除text1中的重复行后输出到text2中

Linux命令格式
命令字 【命令选项】【命令参数即操作对象】ban

sed是流编辑器,用于处理文本内容。
sed 【选项】“匹配模式ni 命令” fileni

Linux sort 命令,对文件内容进行排序
sort 默认对空格或制表符进行划分,默认对第一列进行排序
-t 选项可以指定分隔 了,如 sort tmp.txt -t “:”
-k选项可以按照第列进行排序 sort tmp.txt -t “:” -k 4
在排序时默认排序方式是字符串排序 因此想使用数字进行排序就要使用-n命令
sort tmp.txt -t “:” -k 4 -n
如果想逆序排序 可以使用 -r命令
如果目标列是带有单位的数字 就可以使用-h命令对带单位的数字排序
-u命令可以对排序后的选项进行去重处理
-o选项可以输出到指定文件中
-f选项比较时将所有字符视为大写

Stl map
创建 map<int , string> maptest;
增。 pair<int,string> v1={1,”student”}; maptest.insert(v1);
还有一种插入方式:maptest[1]=“student ”
值得一提的是map底层会对map的关键字进行排序
查找。使用maptest.find(1)来通过键值查找,此时返回该map对
删除。maptest.erase(1)
插入区间
pair <int,string>v[]={{1,”student”},{2,”teacher”}}
maptest.insert(v+1,v+2);

通过一个map去初始化另一个map
map1.insert(map2.begin(),map2.end());

vector初始化的六种方式
vector tmp;默认构造函数,vector为空,size为0,容器中没有元素。
vectortmp(copytmp);
vectortmp(1,2 ,3,4,5);
vectortmp(test.begin(),test.end()-1);
vectortmp(7);vector中有7个元素,默认初始化都是0
vectortmp(7,3);vector 中有7个3
二维数组vector<vector>tmp;
vector.resize()

Vector.resize()的用于保留空间,但并没有开辟空间。

二维数组行优先访问效率高还是列优先访问效率高?
行优先访问效率更高。
因为程序有局部性原理,且二位数组的存储方式在内存中也是一维存储方式。所以当按行优先访问的时候,如果读取了第一个元素,系统会将其附近的第二个元素也装在进内存,但如果按列访问,当访问第一列第一个元素后,想访问第二列第一个元素时,程序发现没有该元素会再次装载一遍该元素及其附近元素,造成频繁装载数据的现象。

Vector的底层实现?
STL-Vector。SGI-STL
泛型的动态类型顺序表
有三个指针start、finish和end_of_storage,分别代表Vector的起始元素,最后元素的下一个位置和空间末尾
优点,快速访问,查找速度是O(1)
因为空间位置是连续的,因此不适合插入和删除
左闭右开
插入元素方式:
将要插入的元素之前的元素搬到新空间,将要插入的元素插入到新空间,将要插入元素后边的元素插入到新空间
引起扩容的时机:插入元素,reserve,resize
简单来说,有两种扩容方式,一种是不需要扩容,另一种是需要扩容,
如果不需要扩容,则从插入位置之后的元素全都向后移动一位,然后插入需要插入的元素
如果需要扩容,则从需要插入的位置position之前的元素搬到新的空间,然后插入元素,然后将后面的元素搬到插入元素的后边

resize()和reseve()的区别?
resize()扩容是开辟空间并初始化,;resize并不会对原vector已经存在的元素进行重新初始化!!!!!https://blog.csdn.net/jinx_qixianzhi/article/details/83143748
reseve()是扩容是扩大空间但不会进行开辟空间;reserve的作用是保护起一段内存空间不会别人使用。
为了避免vector边插入边扩容,可以先reserve预留一定空间,就不会变插入边扩容了。

C++设置成protect的原因?
不想让外界访问,但想让继承其的子类可以访问
C++ public,private和protect
Public在声明对象后可以被对象索引出来,
Private在声明对象后不可以被对象索引出来,
Protect在只可以被子类对象索引出来,不可以被其他对象索引出来

STL-Map
使用之前引入头文件
Map的值类型用pair来构建
Pair<int,string>pv={1,”Hello”};
Cout<<pv.second<<endl;
Map<int , string> mp;
Pm.insert(pv);
for(const auto &e:mp)
cout<<e.first<<“:”<<e.second<<endl;
mp[1]

反向迭代器
Map<int,string>::reverse_iterator rit=mp.rbegin();

清空map
Mp.clear();

if(mp.begin()==mp.end())则数据被清空

删除数据
map.erease();
预防迭代器失效,在调用 map.erease();后去接收他的返回值,如 mp.begin()=map.erease();

当被问到vector是如何进行插入的?
面试官想听到的是:
1. 是够掌握vector的各种插入方式
2. 不同插入方式背后会发生什么
3.插入后果会导致什么

push_back();
push_backa()在插入时会产生边插入边扩容的现象,影响效率,为此可以使用reserve先预留空间,就不会进行动态调整空间了,在Win下push_back 扩容是1.5倍,在Linux下是2倍
void TestPushBck()
{
vector v;
v.reserve(100);
size_t sz=v.capacity();
for(int i=0;i<100;i++)
{
v.push_back(i);
if(sz !=v.capacity())
{
sz=v.capacity();
cout<<sz<<endl;
}
}

}

当插入用户自定义类型的时候,push_back使用的是对象的拷贝,影响效率,因此C++11提出了emplace_back来就地插入对象,不会进行对象的拷贝行为,而是直接将传入的实参插入进去。

浅拷贝会造成代码奔溃。

深拷贝,浅拷贝与写时拷贝
https://tonglin.blog.csdn.net/article/details/86384051?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1.control
浅拷贝会造成多个指针指向同一个地址,在析构函数调用时造成多次释放同一个地址,由于第一个释放后资源被系统回收,因此再次释放该地址是不允许的,还有一种情况是系统回收该处资源后又重新使用了该地址资源,那么二次释放就会导致其数据被释放,造成不可知的结果
深拷贝是当拷贝的时候重新申请一块内存,并将内容拷贝进来,这样就避免了二次释放

移动语义与右值引用
值传递会产生拷贝行为,产生一个匿名对象,并将匿名对象赋给新值,这样就产生了两次空间开辟,C++11位了避免这种情况的浪费,使用了移动语义,将新值的地址直接指向了匿名对象的地址,再将匿名对象的指针指向空

push_back在插入对象时,如果对象是一个可更改的左值,push_back会进行拷贝方式进行插入,此时如果是用户自定义类型,则需要用户提供复制构造函数,否则会产生程序崩溃,而如果插入的是一个临时对象,则push_back会使用C++11的移动语义进行插值
如果不需要考虑98和11的兼容性,推荐使用emplace()来提高插入的效率,因为该函数不需要拷贝方式来插入,而是将传入的参数直接插入。

vector insert
在任意位置插入一个元素的拷贝
在任意位置插入n个元素的拷贝
在任意位置插入一段区间,左闭右开

vector v{1,2,3,4,5};
v.insert(v.begin()+3,10,5);
Int array[]={6,7,8};
auto it =find(v.begin(),v.end(),3);
if(it != v.end())
{
v.insert(it, array,array+sizeof(array)/sizeof(array[0]));
}

Insert插入的也是数据的拷贝

构造函数
构造函数是类同名的,无返回值的特殊函数,用于给对象初始化使用,拷贝构造函数可以传入参数,并使用列表初始化方式来初始化内部数据。
class person
{
Public:
Person(string name, int age)
:i_name(name),i_age(age)
{

}

Private:
string i_name;
int i_age;
};

Insert可能造成的后果
如果插入时触发了扩容,会导致迭代器失效,因为扩容会寻找新地址,因为旧的迭代器就失效了

总结insert的插入方式:
push_back在队尾插入
Insert在任意位置插入,插入的是拷贝数据
Emplace在任意位置插入,插入的是原数据

Linux-awk
打印第二列 awk -F ':' '{print $2}' tmp.txt
打印第二行第二列 awk -F ':' 'NR2{print $2}' tmp.txt
打印第1-3行第二列 awk -F ':' 'NR
1,NR==3{print $2}' tmp.txt
打印前2列数据 awk -F ':' 'NR=2{print $2}' tmp.txt
正则表达式,匹配包涵小李的数据 awk -F ':' 'NR=2{/小李/print $2}' tmp.txt

从浏览器输入url到显示页面内容,都发生了什么?

一、客户端本地缓存查找

二、向dns询问ip的四次请求:
如查找www.baidu.com
1.向本地dns询问,即移动,联通等,
2.如果本地服务器没有查到,他会询问根服务器,根服务器会告诉他去相应的顶级域服务器查找,即com域
3.本地服务器向顶级域请求后,顶级域会告诉本地dns服务器去二级域查找,即baidu域
4.本地服务器向二级域请求后,二级域会告诉本地服务器去三级域查找,即www域,
5.本地服务器向三级域请求后,三级域会告诉本地服务器域名的ip地址,然后本地服务器再将ip地址返回给客户端

三、建立TCP链接
在拿到域名对应的IP地址后,浏览器会以一个随机端口(1024<端口<65535)向服务器的WEB程序(常用的有httpd,nginx等)80端口发起TCP的连接请求。,这个连接请求进入到内核的TCP/IP协议栈(用于识别该连接请求,解封包,一层一层的剥开),还有可能要经过Netfilter防火墙(属于内核的模块)的过滤,最终到达WEB程序,最终建立了TCP/IP的连接,对于客户端与服务器的TCP链接,必然要说的就是『三次握手』。

四、浏览器向WEB服务器发起Http请求
建立TCP连接之后,发起HTTP请求,请求一般分为三部分
请求方法URI协议/版本
请求头(Request Header)
请求正文

其他
https://www.cnblogs.com/yuanzhiguo/p/8119470.html

linux 查看log
Cat 查看完整文件,-n可显示行
Less查看部分文件,可翻页
More一页一页显示文件
Head显示文件前几行的内容,默认是前10行
Tail用于显示文件后几行的内容,默认是后10行内容

将内容输出到文件:
echo “abc” >> test.txt

STL-Map的底层实现原理
红黑树
红黑树调整
源码探秘

树,二叉树,二叉排序树(BST树),平衡树(AVL树,红黑树)
红黑树的根节点是黑色的,如果父节点是红色,则子节点必须是黑色
一头一脚黑(根结点和叶节点都是黑),黑同红不连(每个路径上的黑树数量是相同的,没有两个红树是相连的
红黑树使用红黑二色进行“着色”,目的是利用颜色值作为二叉树的平衡对称性的检查,只要插入的节点“着色”满足红黑二色的规定,最短路径与最长路径不会相差的太远,红黑树的节点分布就能大体上达至均衡。

Map的底层是使用红黑树的接口
Map不能插入相同键值,单重映射
Multimap可以插入相同键值,多重映射

TCP编程基本流程
服务器基本流程:socket、bind、listen、accept、recv/send、close
客户端基本流程:socket、connect、send/recv、close

多线程和多进程
进程是一个执行实例,一个正在运行的程序,会获得cpu的资源。
它是一个task_struct,包含
进程标识符,进程状态,进程优先级,进程计数器,上下文数据等等

多进程
如何创建一个子进程?
调用fork函数
原理:子进程会拷贝父进程的PCB,以及页等结构,创建子进程完成后,子进程具有自己的进程虚拟地址空间,具有自己的页表结构。

什么是线程?
线程是进程内部的一个控制序列,
一个进程至少都有一个执行线程,
线程在进程内部执行,本质上是在进程地址空间内运行
线程的PCB要比进程的PCB轻量化,
线程之间共享:文件描述符,信号的处理方式,当前进程工作目录,用户id和组id

多线程优点
多个进程相互独立,子进程或父进程崩溃不会相互影响
由于多进程之间资源相互独立,因此进程间交换数据需要进程间通信,
创建子进程的开销要比创建线程的开销大

线程间共享进程的资源,是cpu调度的基本单位
进程间资源相互独立,线程间共享进程的资源,
线程创建和销毁的速度快,

read()阻塞的原理
read()阻塞是将当前进程从工作进程放到等待队列中,当有数据缓存区有数据传来时,再将进程放回工作队列中

多线程出现异常后,会导致所在进程直接挂掉
多进程出现异常后,不会影响到其他进程

资源管理是以进程为单位是分配的,
但是cpu调度的时候是以线程为单位的

一个进程的组成实体分为:线程集和资源集

虚拟内存
每个进程都支持0-4G(32位操作系统)的寻址
MMU内存映射单元,如果程序运行时需要某个内存数据,就会触发MMU进行缺页处理,将对应的内容加载到物理内存中,
有了虚拟内存,编程就不需要考虑内存重叠的问题

Linux 查看当前目录
tree

TCP/IP的七层协议:
物理层,数据链路层,网络层,传输层,会话层,表示层,应用层
na
thread有共享内存,process没有共享内存

include<stdio.h>

include<stdlib.h>

include<pthread.h>

Void * myfunc(void* arms){
printf(“Hello World\n”);
return null;
}
int main()
{
pthread_t th;
pthread_creat(&th,NULL,myfunc,NULL);//最后一个参数是用来向myfunc中传参数的
pthread_join(th,NULL); //等待子进程结束
return 0;
}

使用gcc编译的时候要加上编译选项 -lpthread

当多线程访问同一个数据资源的时候,需要给该资源加锁,如mutex
锁是用来锁一段代码用的,锁需要初始化,加锁,解锁
加锁解锁不要放在循环里,否则浪费时间

统计代码运行时间
time ./example

假共享,当多核cpu操作多线程时候,如果多线程操作的是数组,就会产生假共享,影响效率

传输层,TCP/UDP
应用层,HTTP,ftp
网络层,IPV4,IPV6
网络接口层,ARP

客户端服务器模式C/S架构的优点:
可以在客户端本地缓存数据,加快访问
缺点,既要开发客户端软件,又要开发服务器软件,开发工作量大。

BS模型,浏览器服务器架构

七层模型所对应的四层模型:
网络接口层,网络层,传输层,应用层

tcp协议会打包上端口号,ip会打包上IP地址,以太网协议会打包上MAC地址,
MAC地址就是网卡的物理地址,由于ip地址是可以更换的,而MAC地址是唯一的,所以交换机需要通过MAC地址来找到对应的网卡。

数据链路层,用于将网络信息整理,并传输到物理层

socket
ip地址可以在网络中唯一标定一台主机,端口号可以在一台主机中唯一标定一个应用。

TCP/IP协议规定,网络数据流应采用大端字节序

c89中,是不存在bool类型的,所谓的bool类型是用整数类型模拟的
c99中,增加了内置类型bool
c语言中整数类型是采用补码方式进行的,即真值存储
float存储方式采用IEEE754标准进行存储的,最高位是符号位,接下来的8位是阶数位,其余是尾数位

二维数组是行优先存储的
c[2][2], c代表第一个元素的地址,c代表第一行元素的首地址,
c[i]等价于
(c+i)
因此,c和&c[0][0]等价的,代表二维数组中第一个元素。
因此c,*c和
c的值相同,但是代表的含义不同

浮点数的加法不满足结合律
因此
float a,b,c;
(a+b)+c == a+(b+c) 是不能比较的

预处理,编译,汇编,链接

error 编译时输出一条错误信息,并终止继续编译

ASSERT()断言,一般用于一些必须条件的检测,防止非法出错

数组名代表首元素的地址,每次+1走一个元素类型的大小,不要对数组名取址不知道获得的是什么

strcpy()字符串拷贝,遇到\0则停止拷贝,并将\0也拷贝过去,
memcpy()内存拷贝,把指定长度的字符拷贝到指定空间,不会遇到\0就停止

do while 和while do
至少执行一次和有可能一次都不执行

浮点型数据有精度丢失问题,因此运算后比较大小是不能相等的

const和define
const定义的是常量变量,可以被编译器检查,ma

指针传递的是地址,但他本身还是采用值传递的方式进行传递
因此以下方式是不能给指针赋值的:
void getmemory(char *p)
{
p=(char *)malloc(100);//此时p已经不是实参的地址了。
strcpy(p,”hello world”);
}
Int main()
{
char *str=NULL;
getmemory(str);
printf(“%s/n”,str);//此时str仍然是NULL
}

“01234abcd”[i]是合法的
即把字符串常量当数组名来用得到的是第一个字符的地址,
因此“01234abcd”[0]是字符0的地址,“01234abcd”[5]是字符5的地址

常用的数据结构有哪些?
线性存储,链式存储,散列表,队列

strlen()返回字符串的长度,不包括’\0’

在gcc编译器下,如果局部变量不初始化,会是随机值

在正常情况下,给变量分配内存是以字节为单位,但在结构体中可以以位域的形式分配内存;
struct A
{
char t:4;
char k:4;
unsigned short i:8;
unsigned long m;
}
sizeof(A)=8

如果一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。

位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。
struct k
{
int a:1
int :2 /该2位不能使用/
int b:3
int c:2
};

字节对齐
对于32位的Intel X86平台,采用4字节对齐,即起始地址能够被4整除。
Struct A{
int a;
char b;
short c;
}
Struct B{
char b;
int a;
short c;
}
已知32位机器上各数据类型的长度为:char为1字节、short为2字节、int为4字节、long为4字节、float为4字节、double为8字节。那么上面两个结构体大小如何呢?
结果是:sizeof(strcut A)值为8;sizeof(struct B)的值却是12。

大端对齐和小端对齐
首先了解一下,数字的大端在左,内存的大端在右
小端对齐就是数字的低位存放在内存的低位,符合逻辑,大对大,小对小
大端对齐就是数字的高位存放在内存的低位,符合存取逻辑,都是从左往右

整形存储的是真值,浮点型存储的是近似值

数据溢出,数据溢出时,填充低位,去除高位

指针的作用:
减少数据传递量,相对于自定义变量来说,指针只传递地址,消耗要小;
作为出参返回多个返回值;

在c89标准中,是没有bool类型的,在c语言99中是有bool类型的
C89中也不能在for内定义变量,而c99可以

如果两个正数相加,返回值比两个数都小,就发生了溢出,
所有的溢出都是因为数据位不足产生的

结构体和联合体的区别,
结构体是多个数据的集合,每个数据有独立的内存空间,而联合体是多个类型的值共用同一块内存。

数组的本质是数组 首地址+偏移量 如p[i]

Char *和数组的区别
Char *不能改变内容,而数组可以改变内容
char *s1 = "abc";//不能改变内容

运维工作中什么最重要?
数据,规则

==========================
面试流程:
简单自我介绍,工作经验问答,
专业技术问答,人生规划问答

linux远程登录
ssh

ISO/OSI 国际标准互联 7层结构
应用层 :给用户提供一个操作界面
表示层:数据提供的表示,加密,压缩,把数据和二进制进行翻译转换
会话层:确定是否网络传递,
传输层:数据的拆分和组装,协议选择【TCP/IP(可靠的,面向连接的传输协议)或UDP(不可靠的,面向无连接的传输协议)】,端口封装,差错校验
网络层:IP地址编址,路由选择(静态路由,动态路由)
数据链路层:MAC地址编址,MAC地址寻址,差错校验。
注:ip确定公网口,数据链路确定局域机器,
物理层:数据实际传输

TCP/IP四层协议
应用层
传输层
网络层
网络接口层

每层都有协议,协议即传输方式的约定

悬空指针和野指针
野指针,未被初始化的指针
悬空指针,被delete后未被分配的指针
Void main()
{
char *dp=(char *)malloc(A_CONST);
free(dp);//dp是悬空指针
do=NULL;//dp不再是悬空指针
}

多态包括重载和重写

list排序,list.sort();

线程间通信的方式:
全局变量,共享内存和消息传递

通过共享对象通信,
忙等待busy wait

进程间通信:
信号量,socket,共享内存,管道,共享文件
线程间通信:
全局变量+互斥锁,条件变量,信号量,读写锁

进程和线程的区别:
进程是操作系统调度的基本单元,
线程是cpu调度的基本单元

孤儿进程,父进程没有等待子进程销毁完就销毁了,这时子进程就是孤儿进程
子进程退出后,会留下一个僵尸进程的数据结构等待父进程处理,如果父进程没有调用wait处理子进程,这个子进程就是僵尸进程了

解耦,就是在对象和对象之间添加处理层,使两个对象能各自维护各自内容,不互相影响

linux远程传输
scp

linux远程登录
ssh

显示进程
ps -e显示所有进程

linux编译调试,gcc

vim保存
:wq

别名
alias

软连接
ln

输出重定向

posted @ 2020-12-26 22:34  多弗朗强哥  阅读(332)  评论(0编辑  收藏  举报