写在前头,这里面只是我在做这些公司笔试时抄下来的一部分题,并不全,但我会尽量把我所抄的每道题的知识点都贴上
1. Linux下支持的IO多路复用,有selec、poll和epoll,但Windows下仅支持select。
2. 新版C++,智能指针不再推荐使用auto_ptr。
3.char数组和char*的区别:
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
int main(){
char str1[] = "abc";
char str2[] = "abc";
const char str3[] = "abc";
const char str4[] = "abc";
const char *str5 = "abc";
const char *str6 = "abc" ;
char *str7 = "abc";
char *str8 = "abc";
cout<<(str1==str2)<<endl;
cout<<(str3==str4)<<endl;
cout<<(str5==str6)<<endl;
cout<<(str7==str8)<<endl;
cout<<(str5==str7)<<endl;
return 0;
}
打印结果是:
0
0
1
1
1
char * 更加类似于string类,而且重载了很多运算符如程序中的“==”,“<<”。
所以比较的是字符串的 内容 (重载的效果),而char[] 由于是没有重载——是默认效果,比较的是 地址!
a、str1==str2比较的是地址,而不是内容;
b、每个数组对象都分配了自己的存储空间,地址各不相同;
c、指针变量并不分配存储区,而是指向常量“abc”所在的静态存储区,由于是指向同一个常量,所以str5,str6,str7,str8指向的地址相同
4.私有IP地址的范围:
5. 网络字节序一般采用的是大端。
6. 指针的大小
相当于一个内存地址所占的内存大小。
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
int main(){
const char *str = "hello";
char str2[] = "he";
cout<<sizeof(str)<<endl;
cout<<sizeof(str2)<<endl;
cout<<sizeof("hello")<<endl;
return 0;
}
输出结果为
8
3
6
7. 它们的区别:
这里有一个小技巧:一般先看const左边修饰什么,要是左边没有东西,才看右边。具体可以看这个视频
8.线程问题
通过fork创建子进程,读时共享,写时复制,一开始时,父子进程共享同一块虚拟内存空间,当要写的时候,子进程复制父进程的虚拟内存空间,并把它映射到新的实际内存。
但线程就不一样,共享虚拟内存空间,但栈和代码区不共享。每个线程处理各自负责的一部分。
在很多现代操作系统中,一个进程的(虚)地址空间大小为4G,分为系统(内核)空间和用户空间两部分,系统空间为所有进程共享,而用户空间是独立的,一般Windows进程的用户空间为2G。
一个进程中的所有线程共享该进程的地址空间,但它们有各自独立的(/私有的)栈(stack),Windows线程的缺省堆栈大小为1M。堆(heap)的分配与栈有所不同,一般是一个进程有一个C运行时堆,这个堆为本进程中所有线程共享,windows进程还有所谓进程默认堆,用户也可以创建自己的堆。
用操作系统术语,线程切换的时候实际上切换的是一个可以称之为线程控制块的结构(TCB),里面保存所有将来用于恢复线程环境必须的信息,包括所有必须保存的寄存器集,线程的状态等。
堆:是大家共有的空间,分全局堆和局部堆。全局堆就是所有没有分配的空间,局部堆就是用户分配的空间。堆在操作系统对进程初始化的时候分配,运行过程中也可以向系统要额外的堆,但是记得用完了要还给操作系统,要不然就是内存泄漏。
栈:是个线程独有的,保存其运行状态和局部自动变量的。栈在线程开始的时候初始化,每个线程的栈互相独立,因此,栈是thread safe的。操作系统在切换线程的时候会自动的切换栈,就是切换 ESP/EBP 寄存器。栈空间不需要在高级语言里面显式的分配和释放。
9.STL常见的容器
顺序容器(容器并非排序的,元素的插入位置同元素的值无关): vector:动态数组,内存连续,末端增删性能最佳,无序; deque:双向队列,内存连续,无序; list:双向循环链表,内存不连续(不支持随机存取),无序;
关联容器(元素是排序的,插入任何元素,都按相应的排序规则来确定其位置): set/multiset:红黑树,有序; map/multimap:红黑树,有序
容器适配器: stack:先进后出; queue:先进先出; priority_queue:优先级队列(内部维持某种有序,然后确保优先级最高的元素总是位于头部,最高优先级元素总是第一个出列)
10.%hu代表以 unsigned short格式输出整数
11.正则表达式
在线测试工具
?(问号) 加在一个字符后面,表示前面的这个字符出现0次或者1次,也就是可有可无的意思。
*(星号) 可以匹配0个或者多个字符,也就是上面的’b’要出现0次或者多次。
+(加号) 会匹配至少出现一次以上的字符。
{}(花括号) 可以指定字符出现次数的范围。上面是指定匹配’b’出现六次的。
上面的意思是我们希望’b’的出现次数在2到6之间。
如果希望’b’出现两次以上,我们可以之间省略这里的6。
这上面介绍的都是匹配一个字符的,如果我们想匹配多个字符的,可以采用用()(括号),把我们要匹配的字符括起来。如:
或运算符(|)
字符类:
例如我们想要匹配有abc组合起来的单词,我们可以用[](方括号)。
方括号里的内容代表要求匹配的字符只能取自于它们。
我们还可以在方括号里指定字符的范围。
a-z:表示所有的小写英文字符。
a-zA-z:表示所有的英文字符,包括大小写。
a-zA-z0-9:表示所有的英文字符和数字。
^(尖号运算符)
如果我们在方括号里的前面加一个 ^ ,就代表要求匹配除了尖号后面列出的那些以外的字符。如:
[ ^0-9 ] 表示所有的非数字字符(包括换行符)。
元字符:
12.
char a[][5]={"abc","ijh","defg","opq"};
char* p = &a[1][1]; //&a[1][1]表示第二行的第二个元素的地址
printf("%d %s %s",a[2]-a[0],&p[1],&p[5]); //a[2]表示的是第三行的首地址,a[0]表示的是第一行的首地址,所以a[2]-a[0]为10(10个char)
//&p[1]为"h\0",因为a[1][3]和a[1][4]为空,但也算一个字节,所以&p[5]的起始位'e'
13. C++中为什么要把源码分为头文件( *.h)和源文件( *.cpp)?
当一个源文件A要用到源文件B的函数时,只需要在自己的程序加上这个函数的声明,而且这个声明(函数类型、函数名和参数列表)要一样。当需要源文件B或者其他源文件中的多个函数时,这个时候就会很麻烦了,因为要确保源文件A要确保这些函数的函数签名的声明都正确,但这个是比较难做到的事,这个时候就需要有头文件来存放这些函数的声明。详细的可以看这篇博文
14. 数组定义为"int a[4][5]";下列哪个是不正确的()
A.* a B.* (*(a+2)+3) C.&a[2][3] D.++a
答案是D。
A . * a 之后得到的值是一个地址,这个值跟就是数组a的首地址,不过意义不一样,a相当于一个二级指针,指向一个4行5列的二维数组,而 *a是一个一级指针,指向一个有5个元素的数组首地址。
B. 这是二维数组的另外一种元素索引方式,不过多解释。
C. 取 第2行第3列元素首地址。
D. 语法有错误。指针可以++操作,而数组名也可以转化为指向第一个元素的指针,但是为什么数组名不能++操作呢?因为定义了一个数组,那么这个数组的地址就是固定的了。int a[4][5],那么a的地址是固定的,相当于 int **const类型,改变了a的指向就会出错。
15. 主要考察运算符的优先级和&&的使用规则
int a=1,b=2,c=3,m=4,n=5,k=6;
(a=m>k)&&(b=n>k);
cout<<a<<" "<<b;
输出:
0 2
运算符优先级:
&&和||的使用规则:
&&左边为false,右边不执行;
||左边为true,右边不执行;
16. Linux哪个信号不能被捕获?(快手)
两种不能被忽略和被捕获的信号:SIGKILL和SIGSTOP。
17. (快手)
#define VERSION(x,y) #x"."#y
#define MINS(x) x
#define MAXS(x) x
int main(){
printf("%s\n",VERSION(MAXS(1),MINS(0)));
}
输出结果:
如果x是一个宏参量,那么#x可以把参数名转化为相应的字符串。该过程称为字符串化。
具体可以参考这篇文章
18. (快手)
int *p1 = new int[10]; // 10个未初始化int
int *p2 = new int[10] (); // 10个值初始化为0的int
详情看这个
19. class的大小(快手)
看这个
20. poll之所以对fd数量没有限制是因为使用了链表(快手)。
select一般限制的大小为1024,epoll也没有限制。
21. 友元函数不是成员函数,不能被继承,也不具备传递性(A是B的友元,B是C的友元,但A不是C的友元),没有this指针,但可以直接被调用。具体可以看这个