# 面试总结
大老远跑到杭州线下面的,面的很难,并且很细,他只问了跟报的那个岗位相关的项目,技术栈只涉及C++/c,简历python相关的AI项目几乎没有涉及,然后和C相关的项目问的很深,并且现场手撕代码,一道接着一道,面完心理就是哇凉哇凉的,后悔没有好好刷代码随想录。
# 宇视线下嵌入软件开发一面面经
# 1.在AI项目中安全性检测是怎么做的?里面的密码有没有做加密处理?比如掩码之类的,是如何处理的?
答:在这个AI教学系统中,安全性主要侧重于基础的数据保护。
对于用户密码,在后端使用了哈希加密,具体是werkzeug.security中的generate_password_hash函数。
它会将密码转换成一个不可逆的哈希值再存入数据库。
用户登录时,将输入的密码进行相同的哈希计算,与数据库中的哈希值进行比对,而不是直接比对明文。”
“对于界面输入的密码,我使用了PyQt5输入框的setEchoMode属性,设置为QLineEdit.Password,这样输入时就会显示为掩码(星号或圆点),防止旁人窥视。这是一种前端的基本交互安全。”
# 2.数据库是如何管理数据的?如何存储数据?
答: 项目中使用轻量级的SQLite数据库,管理数据主要是通过数据库设计和SQL操作。”
存储方面: 设计了多张表来管理不同数据。
管理方面: 使用Python的sqlite3库进行数据库连接和操作。
通过INSERT插入相关记录,用SELECT查询和展示学习看板,用UPDATE更新学习进度。
对于资源文件(如生成的PDF讲义),我存储的是它们在服务器上的文件路径,而不是将文件本身存入数据库。”
# 3.嵌入式开发中上位机是如何与主控板进行通信的?通过什么方式?
答:上位机(触摸屏/组态软件)与下位机(STM32主控板)是通过串口通信实现的,具体来说是UART协议,基于RS-485电平标准,此外自定义了简单的通信协议,包含帧头、数据长度、命令字、数据域和校验位,以保证数据的正确性。
# 4.你了解TCP/UDP通信吗?
答:TCP 是面向连接的、可靠的传输,保证数据顺序和正确性,但开销稍大,比如网页浏览、文件传输。
UDP 是无连接的、不可靠但高效的传输,适合实时性要求高、可容忍少量丢失的场景,如视频直播、语音通话。”
# 5.堆和栈了解吗?说一下它们的底层区别。
答:
栈: 由操作系统自动管理,函数调用时的局部变量、参数都在栈上分配,函数结束自动释放。
分配效率极高,但空间有限且大小编译时常确定。
“堆: 由程序员手动管理,通过malloc/free或new/delete申请和释放,空间很大,分配灵活,但容易产生内存碎片,分配速度也比栈慢
在资源受限的嵌入式系统中,需要谨慎使用堆,避免内存泄漏。”
# 6.进程线程了解吗?讲一讲它们的区别。
答: 进程是操作系统资源分配的基本单位,每个进程有独立的代码、数据空间和系统资源(如内存、文件句柄)。
进程间通信(IPC)成本高,如管道、消息队列、共享内存
线程是CPU调度和执行的基本单位,是进程内的一条执行路径。
同一进程下的多个线程共享进程的资源(如全局变量、堆空间),这使得线程间通信非常高效,但同时也带来了同步问题(如竞态条件)。”
# 7.一个线性队列要增加元素,应该怎么操作,不要只说,现场写出对应的代码。
答: 现场写核心部分的伪代码就好。
函数 enqueue(value):
如果 isFull():
输出 "队列已满,无法添加元素"
返回 false
结束如果
rear = (rear + 1) % MAX_SIZE // 循环移动队尾指针
arr[rear] = value // 在队尾位置插入新元素
count = count + 1 // 元素计数加1
返回 true
结束函数
2
3
4
5
6
7
8
9
10
11
12
完整的c++代码如下
#include <iostream>
using namespace std;
const int MAX_SIZE = 5; // 队列最大容量
class CircularQueue {
private:
int arr[MAX_SIZE];
int front; // 队头指针
int rear; // 队尾指针
int count; // 当前元素个数
public:
// 构造函数,初始化队列
CircularQueue() {
front = 0;
rear = -1;
count = 0;
}
// 判断队列是否为空
bool isEmpty() {
return count == 0;
}
// 判断队列是否已满
bool isFull() {
return count == MAX_SIZE;
}
// 入队操作 - 增加元素到队列
bool enqueue(int value) {
if (isFull()) {
cout << "队列已满,无法添加元素 " << value << endl;
return false;
}
// 循环队列:队尾指针循环到数组开头
rear = (rear + 1) % MAX_SIZE;
arr[rear] = value;
count++;
cout << "元素 " << value << " 入队成功" << endl;
return true;
}
// 出队操作
int dequeue() {
if (isEmpty()) {
cout << "队列为空,无法出队" << endl;
return -1;
}
int value = arr[front];
front = (front + 1) % MAX_SIZE;
count--;
cout << "元素 " << value << " 出队成功" << endl;
return value;
}
// 获取队头元素
int peek() {
if (isEmpty()) {
cout << "队列为空" << endl;
return -1;
}
return arr[front];
}
// 显示队列当前状态
void display() {
if (isEmpty()) {
cout << "队列为空" << endl;
return;
}
cout << "队列元素: ";
int current = front;
for (int i = 0; i < count; i++) {
cout << arr[current] << " ";
current = (current + 1) % MAX_SIZE;
}
cout << endl;
}
};
int main() {
CircularQueue queue;
// 测试入队操作
queue.enqueue(10);
queue.enqueue(20);
queue.enqueue(30);
queue.enqueue(40);
queue.enqueue(50);
queue.display(); // 显示当前队列
// 测试队列已满的情况
queue.enqueue(60); // 应该显示队列已满
// 测试出队操作
queue.dequeue();
queue.dequeue();
queue.display(); // 显示当前队列
// 继续添加元素(测试循环特性)
queue.enqueue(60);
queue.enqueue(70);
queue.display(); // 显示当前队列
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# 8.两个线程访问同一个消息任务,应该怎么做?手撕对应的代码。
答,使用POSIX线程库 pthread。
#include <pthread.h>
// 共享消息任务
int message_task = 0;
// 定义并初始化一个互斥锁
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void* thread_function(void* arg) {
for (int i = 0; i < 10000; i++) {
// 进入临界区前加锁
pthread_mutex_lock(&mutex);
// 临界区代码:对共享资源进行操作
message_task++;
// 退出临界区后解锁
pthread_mutex_unlock(&mutex);
}
return NULL;
}
int main() {
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, thread_function, NULL);
pthread_create(&tid2, NULL, thread_function, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
printf("Final value of message_task: %d\n", message_task); // 正确结果是20000
pthread_mutex_destroy(&mutex);
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 9.假如现在有三个进程,进程1,进程2,进程3,进程1正在访问一个任务。如果想让进程2进程3也处理进程1中对应的任务,应该怎么操作?写出实现的代码。
答: 属于进程间通信(IPC)问题,由于进程资源不共享,需要用IPC机制m这里共享内存是最贴切的解决方案。
进程间内存空间是隔离的,要让它们处理同一个数据,必须使用进程间通信。
共享内存是最高效的方式,它让不同的进程映射同一块物理内存,这样所有进程就能看到同一份数据。
但和线程一样,访问共享内存也需要用信号量等机制来同步,防止数据混乱。”
#include <sys/shm.h>
#include <stdio.h>
int main() {
// 1. 进程1:创建并关联共享内存
int shmid = shmget(IPC_PRIVATE, sizeof(int), 0666 | IPC_CREAT);
int *shared_task = (int*)shmat(shmid, NULL, 0);
*shared_task = 100; // 进程1初始化任务数据
// 通过某种方式(如管道、文件)将 shmid 告诉进程2和进程3
// 2. 进程2和进程3:通过得到的 shmid 关联到同一块共享内存
// int *shared_task = (int*)shmat(shmid, NULL, 0);
// 现在三个进程可以通过 *shared_task 访问同一个整数变量了
// 同样,对共享内存的访问也需要用信号量或互斥锁进行同步(这里省略)
// ... 处理任务 ...
// 3. 所有进程分离共享内存
shmdt(shared_task);
// 最后一个进程销毁共享内存
shmctl(shmid, IPC_RMID, NULL);
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
← 亚信安全C++一面面经 小鹏汽车嵌入式面经 →
评论
验证登录状态...