卡码笔记
首页
计算机基础
C++
Java
面经
笔记广场 (opens new window)
代码随想录 (opens new window)
首页
计算机基础
C++
Java
面经
笔记广场 (opens new window)
代码随想录 (opens new window)
  • Java面经

  • C++面经

    • 字节一面面经
    • 字节二面面经
    • 字节后端一面面经
    • 百度测试开发一面面经
    • 亚信安全C++一面面经
    • 宇视嵌软线下技术面
    • 小鹏汽车嵌入式面经
    • 小鹏汽车嵌入式测开技术面一面面经
    • 小鹏汽车嵌入式测开技术面二面面经
    • 希奥端软件开发一面面经
    • 希奥端软件开发二面面经
    • 广联达c++技术面

# 面试总结

大老远跑到杭州线下面的,面的很难,并且很细,他只问了跟报的那个岗位相关的项目,技术栈只涉及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
结束函数
1
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;
}
1
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;
}
1
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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Last Updated: 3/10/2026, 6:08:48 PM

← 亚信安全C++一面面经 小鹏汽车嵌入式面经 →

评论

验证登录状态...

侧边栏
夜间
卡码简历
代码随想录
卡码投递表🔥
2026群
添加客服微信 PS:通过微信后,请发送姓名-学校-年级-2026实习/校招
支持卡码笔记
鼓励/支持/赞赏Carl
1. 如果感觉本站对你很有帮助,也可以请Carl喝杯奶茶,金额大小不重要,心意已经收下
2. 希望大家都能梦想成真,有好的前程,加油💪