由于前一天孩子打了疫苗然后晚上发烧了,睡觉的时候差不多凌晨四五点了,一晚上睡了两三个小时,在这之前呢,上午十一点面了一家,下午两点半又面试了一家,下午四点半又面试了一家,面试这家的时候是第四家,脑袋属于迷糊状态。
总共2次技术面试,第一面和第二面恰巧是同一个面试官,问了很多的问题,也聊了很多,虽然自己感觉面试的一塌糊涂,最后面试官给过了,面试官人很不错,2面直接给了offer,很感谢这位面试官。可是因为其他原因,我选择了拒绝,这里不能说是哪家公司,希望这位面试官步步高升。
把面试回答不好的地方做以下总结。及时的查漏补缺。
另外一点总结就是:面试的时候,别管前一个问题回答的如何,下一个题目一定要认真仔细的回答清楚,面试是一个很好的学习机会。
- #include
- #include
-
- int main(void)
- {
- char *p = new char[100];
-
- p += 2;
-
- delete []p;
-
- printf("it is demo\n");
-
- }
运行结果:

gdb调试:

结论:
printf不能打印。p是一个无效的指针,会出现核心转储
原因(题目考察的核心点):
只有 malloc返回的地址才能free()
new和delete本质也是调用的malloc和free。
改正:
- #include
- #include
- int main(void)
- {
- char *p = new char[100];
-
- //p += 2;
-
- delete []p;
-
- printf("it is demo\n");
-
- }

- #include
- #include
-
-
- struct MyClass{
- int a;
- };
-
- int main(void)
- {
-
-
- char *p = new char[100];
- delete p;
- printf("it is test demo1\n");
-
- MyClass* q = new MyClass [100];
- delete q;
- printf("It is a test demo2!\n");
-
- }
其实这个问题很简单:
(1)printf可以正常打印
(2)会出现内存泄漏
- #include
- #include
-
- int main(void)
- {
-
- char* ptr = "0123456789";
- while(*ptr)
- {
- printf("%c\n", *ptr++);
- }
-
- return 0;
- }
结论:这段代码可以正常打印如下结果:

gdb调试程序也是正常退出
-
- #include
- #include
-
-
-
- int main(void)
- {
-
- char* ptr = "0123456789";
- while(*ptr++)
- {
- printf("%c\n", *ptr);
- }
-
- return 0;
- }
结论:

为什么会多一个换行呢?
原因:最后的'\0'也会被计算到里面,所以最后多了一个换行
考察的主要问题是:*和++运算符的优先级,*的优先级高于++的优先级,那这个问题就很好理解了
- #include
- #include
-
- using namespace std;
-
- int main(void)
- {
-
- unsigned char aaa[100] = {0};
-
- int bbb[200] = {0};
-
- cout << sizeof(aaa) << "," << sizeof(bbb) << endl;
-
- int var,count,incr;
- (count=0, incr=10, count++) ? var = (incr-=2, count+2) : var = (incr--, count++);
-
- cout << incr << "," << var << endl;
-
- return 0;
- }
分析:
(1)前半段呢,都没问题

(2)后半段呢,是个三目描述符,首先我第一次见到这种三目,当时有点木,真的,后来仔细分析了如下:
1)(count=0, incr=10, count++):主要是判断这个表达式是不是为真。这两个数字在三目判断的时候分别为:incr=10, count=0,所以逻辑判断为假。
2)逻辑判断为假,执行 var = (incr--, count++), 这个的意思是:执行括号里面的操作,
执行结果为:

- #include
- #include
-
- using namespace std;
-
-
- int func(int x) {
- int count = 0;
- while(x)
- {
- count++;
- x = x&(x-1);
- }
- return count;
- }
-
- int main(void)
- {
- cout << " func(255) = " << func(255) << endl ;
- return 0;
- }
唉,其实这个是一个按位运算
- Starting program: /home/mrlee/test/c++/a.out
-
- Breakpoint 1, main () at main.cpp:20
- 20 cout << " func(255) = " << func(255) << endl ;
- (gdb) s
- func (x=255) at main.cpp:9
- 9 int count = 0;
- (gdb) n
- 10 while(x)
- (gdb) wathc x
- Undefined command: "wathc". Try "help".
- (gdb) watch x
- Hardware watchpoint 2: x
- (gdb) watch count
- Hardware watchpoint 3: count
- (gdb) n
- 12 count++;
- (gdb) c
- Continuing.
-
- Hardware watchpoint 3: count
-
- Old value = 0
- New value = 1
- func (x=255) at main.cpp:13
- 13 x = x&(x-1);
- (gdb) c
- Continuing.
-
- Hardware watchpoint 2: x
-
- Old value = 255
- New value = 254
- func (x=254) at main.cpp:10
- 10 while(x)
- (gdb) c
- Continuing.
-
- Hardware watchpoint 3: count
-
- Old value = 1
- New value = 2
- func (x=254) at main.cpp:13
- 13 x = x&(x-1);
- (gdb) c
- Continuing.
-
- Hardware watchpoint 2: x
-
- Old value = 254
- New value = 252
- func (x=252) at main.cpp:10
- 10 while(x)
- (gdb) c
- Continuing.
-
- Hardware watchpoint 3: count
-
- Old value = 2
- New value = 3
- func (x=252) at main.cpp:13
- 13 x = x&(x-1);
- (gdb) c
- Continuing.
-
- Hardware watchpoint 2: x
-
- Old value = 252
- New value = 248
- func (x=248) at main.cpp:10
- 10 while(x)
- (gdb) c
- Continuing.
-
- Hardware watchpoint 3: count
-
- Old value = 3
- New value = 4
- func (x=248) at main.cpp:13
- 13 x = x&(x-1);
- (gdb) c
- Continuing.
-
- Hardware watchpoint 2: x
-
- Old value = 248
- New value = 240
- func (x=240) at main.cpp:10
- 10 while(x)
- (gdb) c
- Continuing.
-
- Hardware watchpoint 3: count
-
- Old value = 4
- New value = 5
- func (x=240) at main.cpp:13
- 13 x = x&(x-1);
- (gdb) c
- Continuing.
-
- Hardware watchpoint 2: x
-
- Old value = 240
- New value = 224
- func (x=224) at main.cpp:10
- 10 while(x)
- (gdb) c
- Continuing.
-
- Hardware watchpoint 3: count
-
- Old value = 5
- New value = 6
- func (x=224) at main.cpp:13
- 13 x = x&(x-1);
- (gdb) c
- Continuing.
-
- Hardware watchpoint 2: x
-
- Old value = 224
- New value = 192
- func (x=192) at main.cpp:10
- 10 while(x)
- (gdb) c
- Continuing.
-
- Hardware watchpoint 3: count
-
- Old value = 6
- New value = 7
- func (x=192) at main.cpp:13
- 13 x = x&(x-1);
- (gdb) c
- Continuing.
-
- Hardware watchpoint 2: x
-
- Old value = 192
- New value = 128
- func (x=128) at main.cpp:10
- 10 while(x)
- (gdb) c
- Continuing.
-
- Hardware watchpoint 3: count
-
- Old value = 7
- New value = 8
- func (x=128) at main.cpp:13
- 13 x = x&(x-1);
- (gdb) c
- Continuing.
-
- Hardware watchpoint 2: x
-
- Old value = 128
- New value = 0
- func (x=0) at main.cpp:10
- 10 while(x)
- (gdb) c
- Continuing.
-
- Watchpoint 2 deleted because the program has left the block in
- which its expression is valid.
-
- Watchpoint 3 deleted because the program has left the block in
- which its expression is valid.
- 0x00000000004008d1 in main () at main.cpp:20
- 20 cout << " func(255) = " << func(255) << endl ;
- (gdb) p func(255)
- $1 = 8
- (gdb)
返回8
个人觉得最好是手画一画,其实这个就是255最大是8个位全为1,没减1,向前一位。
- 1111 1111
- & count=1
- 1111 1110
- x = 254
-
- 1111 1110
- & count=2
- 1111 1101
- x = 252
-
- 1111 1100
- & count=3
- 1111 1011
- x = 248
-
- 1111 1000
- & count =4
- 1111 0111
- x=240
-
- 1111 0000
- & count=5
- 1110 1111
- x=224
-
- 1110 0000
- & count=6
- 1101 1111
- x =192
-
- 1100 0000
- & count=7
- 1011 1111
- x=128
-
- 1000 0000
- & count=8
- 1111 1111
- x=0;
- map<int, string> mapStudent;
- map<int, string>::iterator iter;
- mapStudent.insert(map<int, string>::value_type (1, "student_one"));
- mapStudent.insert(map<int, string>::value_type (1, "student_two"));
- for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)
- cout<
first<<' '<second< -
- mapStudent[1] = "student_three";
- mapStudent[1] = "student_four";
- for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)
- cout<
first<<' '<second< -
- for(int i = 1; i < 3; i++)
- cout<< mapStudent[i] <
-
- cout<< mapStudent.size() << endl;
问题8:下面代码是否有问题?输出是?
- vector
demo{0,1,2,3,4,5,6,7,8,9,10 }; - vector
::iterator it = demo.begin(); - for(it = demo.begin(); it != demo.end(); it++)
- {
- if(!(*it%2))
- demo.erase(it);
- }
- for(it = demo.begin(); it != demo.end(); it++)
- cout << *it << endl;
问题9:下面代码有没有问题?
- struct ComplexNumber
- {
- int Real_Quantity;
- int Imaginary_Quantity;
- };
- multiset
dataset;
正在学习STL相关的,后期一定补齐这几个问题(7, 8, 9)
问题10.网络序列化问题?
网络传输中,牵扯到数据序列化,反序列化。其实,通信双方约定好序列化方式(大端/小端)即可。例如发送方按照大端序列化,接收端在接收到数据后,接收端判断自己的大小端模式,如果自己的CPU是大端模式,则不需要做大小端转换,直接进行数据解析即可。如果是小端,则解析完后还需要将数据转为小端模式。
当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为对象。
把对象转换为字节序列的过程称为对象的序列化。
把字节序列恢复为对象的过程称为对象的反序列化。
说的再直接点,序列化的目的就是为了跨进程传递格式化数据
大端:数据高字节内容保存在内存的低地址中,数据的低字节内容保存在内存的高地址中。
小端:数据高字节内容保存在内存的高地址中,数据的低字节内容保存在内存的低地址中。
比如json或者xml等,其实在发送的时候需要序列化,接收的时候需要反序列化。
问题11.http中的post和put的区别?
1.put和post的区别
PUT和POST都有更改指定URI的语义.但PUT被定义为idempotent的方法,POST则不是.idempotent的方法:如果一个方法重复执行多次,产生的效果是一样的,那就是idempotent的。也就是说:
PUT请求:如果两个请求相同,后一个请求会把第一个请求覆盖掉。(所以PUT用来改资源)
Post请求:后一个请求不会把第一个请求覆盖掉。(所以Post用来增资源)
2、get和post
- GET参数通过URL传递,POST放在Request body中。
- GET请求会被浏览器主动cache,而POST不会,除非手动设置。
- GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
- Get 请求中有非 ASCII 字符,会在请求之前进行转码,POST不用,因为POST在Request body中,通过 MIME,也就可以传输非 ASCII 字符。
- 一般我们在浏览器输入一个网址访问网站都是GET请求
- HTTP的底层是TCP/IP。HTTP只是个行为准则,而TCP才是GET和POST怎么实现的基本。GET/POST都是TCP链接。GET和POST能做的事情是一样一样的。但是请求的数据量太大对浏览器和服务器都是很大负担。所以业界有了不成文规定,(大多数)浏览器通常都会限制url长度在2K个字节,而(大多数)服务器最多处理64K大小的url。
- GET产生一个TCP数据包;POST产生两个TCP数据包。对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。
- 在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。而在网络环境差的情况下,两次包的TCP在验证数据包完整性上,有非常大的优点。但并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。
问题12:Http如何做长链接?
首先http中,没有长连接这样的类型。
http要实现长连接,是建立在tcp协议的基础上的。
一个http连接,等到不再需要该连接的时候,主动调用该连接的close()方法,才会关闭该连接。
HTTP短连接:
客户端和服务端进行一次HTTP请求/响应之后,就关闭连接。下一次的HTTP请求/响应操作需要重新建立。
在首部字段中设置Connection:close,则在一次请求/响应之后,就会关闭连接。
HTTP长连接:
客户端和服务端建立一次连接之后,可以在这条连接上进行多次请求/响应操作。
持久连接可以设置过期时间,也可以不设置。
在首部字段中设置Connection:keep-alive 和 Keep-Alive:timeout = 60,
表明连接建立之后,空闲时间超过60秒,连接失效。
如果在空闲第58秒使用此连接,则仍然有效,
并且使用完之后,重新计数空闲时间,空闲60秒无再使用,连接失效。
设置HTTP长连接,无过期时间,在首部字段中只设置Connection:keep-alive,表明连接永久有效。
在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的 TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接。
Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。
实现长连接要客户端和服务端都支持长连接。
HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。
13.个人觉得HTTP链接时间设置思想
(1)进程中有两个线程,线程1专门做数据的收和发,线程2做定时任务(红黑树)。
(2)线程1:在接收到数据后,解析出header中的Connecttion对应的value,如果,value=keep-alive,表示长链接,不做任何处理。如果value=timeout=?此类的值,首先判断红黑树是否存在对应的链接fd,如果不存在增加节点,如果存在,修改。把对应的?解析出来,然后使用当前时间+超时时间为key值加入红黑树。每次在收到数据的时候,把对应时间重置为当前时间+延迟时间。
(3)线程2,做TCP client+定时红黑树。 在对应的时间到时见后,把对应的fd发送给线程1,由线程1决定此fd是做close动作还是重置动作(可以也是用http协议,做put请求,防止重复close)。
(4)线程1,如果收到线程2的put请求后,判断是重置还是close,如果是close,则首先把红黑树的此节点删除,然后,调用close fd。
线程1主要负责:
- 对红黑树进行插入、删除、修改动作
- 对客户端请求(http)协议的解析和响应、以及断开等操作
线程2主要负责:
- 对红黑树进行查询、到时发送给线程1。
总结性能件:
- 线程1,放到主进程里面,主要做检测(epoll)
- 线程2,单独启动的特殊线程。
- 在加一个线程池,专门处理事件
问题14:如何通过进程PID获取进程的工作目录等信息?
其实这个题目的核心点,进程启动后,此进程的详细信息在哪里查看?
进程启动后,会在/proc/目录下,生成一个与此PID对应的文件夹,这个文件夹里面包含了此进程的的详细信息
1.获取进程的PID
ps -aux|grep "进程名称"

2.获取进程的工作目录
- mrlee@mrlee-virtual-machine:~/test/c++$ ll /proc/7489
- 总用量 0
- dr-xr-xr-x 9 mrlee mrlee 0 7月 21 16:39 ./
- dr-xr-xr-x 262 root root 0 7月 21 11:58 ../
- dr-xr-xr-x 2 mrlee mrlee 0 7月 21 16:41 attr/
- -rw-r--r-- 1 mrlee mrlee 0 7月 21 16:41 autogroup
- -r-------- 1 mrlee mrlee 0 7月 21 16:41 auxv
- -r--r--r-- 1 mrlee mrlee 0 7月 21 16:41 cgroup
- --w------- 1 mrlee mrlee 0 7月 21 16:41 clear_refs
- -r--r--r-- 1 mrlee mrlee 0 7月 21 16:39 cmdline
- -rw-r--r-- 1 mrlee mrlee 0 7月 21 16:41 comm
- -rw-r--r-- 1 mrlee mrlee 0 7月 21 16:41 coredump_filter
- -r--r--r-- 1 mrlee mrlee 0 7月 21 16:41 cpuset
- lrwxrwxrwx 1 mrlee mrlee 0 7月 21 16:41 cwd -> /home/mrlee/test/c++/
- -r-------- 1 mrlee mrlee 0 7月 21 16:41 environ
- lrwxrwxrwx 1 mrlee mrlee 0 7月 21 16:41 exe -> /home/mrlee/test/c++/a.out*
- dr-x------ 2 mrlee mrlee 0 7月 21 16:39 fd/
- dr-x------ 2 mrlee mrlee 0 7月 21 16:41 fdinfo/
- -rw-r--r-- 1 mrlee mrlee 0 7月 21 16:41 gid_map
- -r-------- 1 mrlee mrlee 0 7月 21 16:40 io
- -r--r--r-- 1 mrlee mrlee 0 7月 21 16:41 limits
- -rw-r--r-- 1 mrlee mrlee 0 7月 21 16:41 loginuid
- dr-x------ 2 mrlee mrlee 0 7月 21 16:41 map_files/
- -r--r--r-- 1 mrlee mrlee 0 7月 21 16:41 maps
- -rw------- 1 mrlee mrlee 0 7月 21 16:41 mem
- -r--r--r-- 1 mrlee mrlee 0 7月 21 16:41 mountinfo
- -r--r--r-- 1 mrlee mrlee 0 7月 21 16:41 mounts
- -r-------- 1 mrlee mrlee 0 7月 21 16:41 mountstats
- dr-xr-xr-x 5 mrlee mrlee 0 7月 21 16:41 net/
- dr-x--x--x 2 mrlee mrlee 0 7月 21 16:41 ns/
- -r--r--r-- 1 mrlee mrlee 0 7月 21 16:41 numa_maps
- -rw-r--r-- 1 mrlee mrlee 0 7月 21 16:41 oom_adj
- -r--r--r-- 1 mrlee mrlee 0 7月 21 16:41 oom_score
- -rw-r--r-- 1 mrlee mrlee 0 7月 21 16:41 oom_score_adj
- -r-------- 1 mrlee mrlee 0 7月 21 16:41 pagemap
- -r-------- 1 mrlee mrlee 0 7月 21 16:41 patch_state
- -r-------- 1 mrlee mrlee 0 7月 21 16:41 personality
- -rw-r--r-- 1 mrlee mrlee 0 7月 21 16:41 projid_map
- lrwxrwxrwx 1 mrlee mrlee 0 7月 21 16:41 root -> //
- -rw-r--r-- 1 mrlee mrlee 0 7月 21 16:41 sched
- -r--r--r-- 1 mrlee mrlee 0 7月 21 16:41 schedstat
- -r--r--r-- 1 mrlee mrlee 0 7月 21 16:41 sessionid
- -rw-r--r-- 1 mrlee mrlee 0 7月 21 16:41 setgroups
- -r--r--r-- 1 mrlee mrlee 0 7月 21 16:41 smaps
- -r--r--r-- 1 mrlee mrlee 0 7月 21 16:41 smaps_rollup
- -r-------- 1 mrlee mrlee 0 7月 21 16:41 stack
- -r--r--r-- 1 mrlee mrlee 0 7月 21 16:39 stat
- -r--r--r-- 1 mrlee mrlee 0 7月 21 16:41 statm
- -r--r--r-- 1 mrlee mrlee 0 7月 21 16:39 status
- -r-------- 1 mrlee mrlee 0 7月 21 16:41 syscall
- dr-xr-xr-x 3 mrlee mrlee 0 7月 21 16:41 task/
- -r--r--r-- 1 mrlee mrlee 0 7月 21 16:41 timers
- -rw-rw-rw- 1 mrlee mrlee 0 7月 21 16:41 timerslack_ns
- -rw-r--r-- 1 mrlee mrlee 0 7月 21 16:41 uid_map
- -r--r--r-- 1 mrlee mrlee 0 7月 21 16:41 wchan
- mrlee@mrlee-virtual-machine:~/test/c++$

解释:
cwd符号链接的是进程运行目录
exe符号链接的就是程序的结对路径
cmdline:就是程序运行时输入的命令行命令
environ记录程序运行时的环境变量
fd目录下是进程打开或者使用的文件的符号链接
-
相关阅读:
训练专门化的大型语言模型(LLM)现在更简单了
K8S-高可用集群
2023全新云渲染测评!效果图渲染哪个平台性价比更高?
概念题总结
数据结构应用大全
element UI table横向树结合checkbox进行多选,实现各个节点的[全选,半选,不选]状态附带模拟数据
rust闭包
Go语言网络编程(socket编程)UDP
Python入门基础知识新手必备(赶紧收藏)
2020年上半年软件设计师真题
-
原文地址:https://blog.csdn.net/weixin_43155199/article/details/125910583
-
最新文章
-
沪漂五周年了:我越来越迷茫了
Agentic Skill Routing 实战:别再把所有 Skill 塞进 AI Agent 上下文
MySQL-Seconds_behind_master的精度误差
[MAF预定义ChatClient中间件-03]CachingChatClient——利用缓存省钱省时间
AI的至暗历史:从万众期待到被政府撤资,AI的两次死亡徘徊
Agent OS :五种驯服不确定性的范式
PortSwigger SQL注入LAB11
数据库即时编译JIT
[Begin]AI Learn Data Day 0
深度学习进阶(二十七)现代 LLM 的核心架构设计其二:SwiGLU