大道五十,天衍四十九,人遁其一!
# 写在前面
作为一个四非二本末流师范院校的工科专业的学生,给大厂投简历的都不如树叶落水,一丝波纹都没有.
大厂 HR 们一看院校就直接 pass 了,除非走内推,像我着这种大厂基本就没什么希望.
从 9 月 15 号开始投,直到现在还是 0 offer, 这还是我第一次面试 (╯_╰).
就感叹一下,下面的经历,诸位就当看个笑话就好.
# 面试经历
# hr 面
hr 给我打电话的时候,我正在做 智能涂鸦 的性格测试,做完之后发现有一个未接电话没当回事。当时以为是快递电话,因为前几天中通丢件了,说是要给我下午 5 点会打电话,当时差不多 5 点 (是真的巧). 然后我直接打回去了,显示的是杭州,我楞了一下 (因为一直都没有接到过面试).
电话通了之后 对面的小姐姐说:"您是?", 我愣了一下说了句:"是你们给我,打电话的". 然后对面就明白了,然后,然后就开始了猝不及防的 hr 面,以至于我最后连他们是哪个公司都不知道的情况下结束了 hr 面 (´。_。`).
最后我还是厚着脸皮问了是哪个公司つ﹏⊂.
值得庆幸的是 hr 也是个新手,大家都是第一次。所以也还好,真就是什么样的人遇上什么样的 hr (狗头)
不过总体来说 丙甲的 hr 还是很棒的,非常非常温柔和客气,非常 nice.
总体是问了 为什么走选择嵌入式,对嵌入式的看法,能不能接受杭州的环境,什么时候能实习以及安排了一下 技术面的时间
# 技术面
技术面总体感觉没有问什么特别细的东西,就大致问了问各个项目,可能也是我投的是实习的缘故.
这次技术面在项目上有几个地方把我问住了
第一个是 TCP/IP 协议有没有自定义协议,我愣了一下没反应过来说了个没有。我当时以为是说,有没有自己形成 类似于 http、COAP 之类的协议.
第二个是 KMP 算法,时间太久真的没想明白,就记得从下次不是一个个往后跳,连 next
数组都忘了
第三个是 状态机的问题,问我在垃圾桶识别的时候用什么控制,我当时以为问的是 轮询,前后台 和 RTOS, 结果我没有
第四个是 数字滤波算法,我一直以为 iir 能用电路实现,显然不能,不过 iir 可以用 FPGA 实现的,问了我为什么要用 iir, 我答了手头能实现和体现出来的效果就是这样的。感觉除了 认为 iir 可以硬件实现之外都么有什么问题
第五个是 PID 算法,问了一下 PID 和 位置式 PID 的区别,我当时第一反应是就是两个是一样的,后面他说还是有些不同的在积分环节上。我才回过神来,位置式 PID 是直接使用 PD 环的,不使用 积分环节,积分环节会导致
然后就问了一下 C 语言 的问题:
第一个是 static
加在全局变量前面的作用。我当时楞了一下,然后反应过来了是限制作用域,因为全局变量本身就是静态存储,加不加 static 并没有什么区别,但是在链接的时候,如果没有 static
那么这个在链接的时候就会和其他文件里的同名变量冲突
第二个是 #define
和 const
的区别。这个还是比较简单的,最简单的一个就是 const
定义的常量在编译过程中实现的,在内存中存在空间的, #define
定义的常量在预编译过程中完成替换,在内存中没有空间。还有一些细节上的东西我当时没打上来
第三个是 memmove
和 memcpy
的区别。这个真的是把我问懵了,因为用的少愣是想了很久了,这里主要是内存重叠的问题,主在 copy 过程中会出现 源地址 会和 起始地址重叠
整体来说,还是第一次面试的原因,过于紧张,基础知识不够牢固,对 c 库函数的不熟悉
# 知识点总结
# TCP/IP
# 网络模型
# ISO 七层网络模型:
名称 | 作用 | 典型服务 |
---|---|---|
应用层 | 所有能和用户交互产生网络流量的程序 | FTP、SMTP、HTTP |
表示层 | 用于处理两个系统中 | ASCII、JPEG |
会话层 | 向表示层 / 用户层进程提供建立连接并在连接上有序的传输数据.(也被称为同步) | ADSP、ASP |
传输层 | 负责主机之间的通信,端到端的通信,传输单位:报文段 / 数据报 | TCP、UDP |
网络层 | 把分组从源端传输到目的端,分组交换网络的不同主机所提供的通信服务。单位是数据报 | IP、IPx、ICMP、ARP、OSPF |
数据链路层 | 把网络层数据组装成帧,单位为数据帧 | SDLC、HDLC、PPP、STP |
物理层 | 在物理介质上实现网络传输 单位 bit | RJ45、802.3 |
# 五层网络模型
应用层、传输层、网络层、数据链路层、物理层
# TCP/IP 网络模型
# KMP 算法
KMP 算法最大特点在于,利用以匹配完成的信息进行转跳
转跳方式依赖于 next
数组, next
实现的方法是通过 计算最大真前缀长度实现的.
具体可以参考这篇博客传送门
# IIR 应用
人体心电信号中常带有工频干扰 (50HZ)、基线漂移 (频率低于 0.5Hz) 和肌电干扰等各种噪声
# 基线漂移
基线漂移一般由于信号采集时呼吸及人体移动造成的,表现为低频率的缓慢变化噪声,其频率一般小于 0.5Hz.
基线滤波的一个主要问题是滤波后会对 ST 段产生影响,由于基线频率与 ST 段的频率很接近,如果滤波器选择不好的话,有可能会导致 ST 段发生改变.
由于 ST 段是判断心肌梗死,心肌缺血等疾病的主要参数之一,滤波导致的 ST 段改变是不能接受的
美国心脏协会 (AHA) 推荐在使用非线性相移的 IIR 滤波器时,其截止频率最高为 0.05Hz, 使用具有线性相移的 FIR 滤波器时,截止频率最高可以到 0.67Hz, 对应 40 的心率
# 零相位的基线滤波
在使用 IIR 实现线性相位的滤波器应用中,有一类特殊的滤波器 — 零相位滤波器.
该滤波器通过前向和后向两次滤波,实现零相移,保证了 ST 段不失真。相对于 FIR 的高阶次导致较多运算量来说,零相移滤波器能实现较低的运算次数。但零相移也有一个较为致命的缺点,由于存在后向滤波,所以需要全部数据采集完成后,才可以进行第二次滤波,这样导致了在实时环境中无法使用
# 肌电干扰
肌电干扰属于高频信号,一般在实际中,采用截止频率为 20Hz、30Hz 和 40Hz 的低通滤波器进行滤除
# static 用法
限制作用域,存储方式变为静态存储
- 修饰全局变量,限制作用域。在链接过程中,多文件中的重名变量不会冲突.
- 修饰局部变量,延长生命周期,存储方式变为静态存储只进行一次初始化.
- 修饰函数,限制函数作用域,局限在文件内部。在连接过程中避免和多文件中同名函数冲突
# #define
和 const
的区别
const
定义的常量在程序运行过程中只有一份拷贝 (因为它是全局的只读变量,存放在静态区), 而#define
定义的宏常量在内存中有若干个拷贝 (没有存空间)#define
宏是在预编译阶段进行替换,而const
修饰的只读变量是在编译的时候确定其值#define
宏没有类型,而const
修饰的只读变量具有特定的类型#define
不能被调试,const
可以被调试
# memmove
和 memcpy
的区别
首先 memcpy
和 memmove
都是 c 语言库函数,位于 string.h
中的函数.
其函数原型分别为
void *memcpy(void *dst, const void *src, size_t count); | |
void *memmove(void *dst, const void *src, size_t count); |
作用都是拷贝一段内存的内容,到目的地址。区别在于,在内存重叠时, memmove
可以保证数据的正确复制,而 memcpy
不可以
情况如图
对于第一种情况 memcpy
可以完美解决,但是对于后面这两种 memcpy
就无法保证复制结果.
所以 memcpy
实现方法因该如下:
void* my_memcpy(void* dst, const void* src, size_t n) | |
{ | |
char *tmp_d = (char*)dst; | |
char *tmp_s = (char*)src; | |
while(n--) { | |
*tmp_d++ = *tmp_s++; | |
} | |
return dst; | |
} |
对 其进行分类讨论则可得到 memmove
void* my_memmove(void* dst, const void* src, size_t n) | |
{ | |
char *tmp_d = (char*)dst; | |
char *tmp_s = (char*)src; | |
if (tmp_d > tmp_s && tmp_s+n > tmp_d) | |
{ // 内存重叠 | |
tmp_d = tmp_d+n-1; | |
tmp_s = tmp_s+n-1; | |
while (n--){ // 先将回被重叠的地方存入目的地址 | |
*tmp_d-- = *tmp_s--; | |
} | |
} | |
else | |
{ | |
while(n--) { | |
*tmp_d++ = *tmp_s++; | |
} | |
} | |
return dst; | |
} |
大道五十,天衍四十九,人遁其一!