news 2026/5/11 11:14:50

嵌入式面试中常见的一些编程题目

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
嵌入式面试中常见的一些编程题目

嵌入式面试中常见的一些编程题目

注:本文只是代码实现,并没有深入讲解实现原理,大家可以看一下主要会考什么,然后再具体针对性了解原理,也更有利于理解。

眼看26届秋招接近尾声,自己虽然很菜,但也在激烈的竞争中拿到了几个 offer,已经非常满意了,希望未来持续学习进步。

本文主要总结了嵌入式秋招中问的比较多的编程题目,总的来说,大部分不会涉及到复杂的算法题(我本身非科班,也没怎么刷题,秋招期间遇到手撕复杂算法的公司也是成功挂掉了),比较重要的是一些已有函数的实现,主要考察对数据在内存中分布的掌握,对C语言在嵌入式场景中理解的深度,比如 memcpy() 函数,遇到 dest 和 src 空间重合的问题是怎么处理的。其次就是各大排序,链表,字符串,数组的操作,二叉树的概念,遍历等等。

一、链表

链表的一些基础操作

链表定义

struct Node {

int data;

struct Node* next;

}

创建节点

struct Node* createNode(int value) {

struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));

if(newNode == NULL)

printf("malloc failed!");

newNode->data = value;

newNode->next = NULL;

return newNode;

}

头插法插入节点

struct Node* insertAtHead(struct Node* head, int value) {

struct Node* newNode = createNode(value);

newNode->next = head;

return newNode; // 新的头结点

}

尾插法插入节点

struct Node* insertAtTail(struct Node* head, int value) {

struct Node* newNode = createNode(value);

if(head == NULL)

return newNode;

struct Node* temp = head;

while(temp->next != NULL) {

temp = temp->text;

}

temp->next = newNode;

return head;

}

遍历链表

void printList(struct Node* head) {

struct Node* temp = head;

while (temp != NULL) {

printf("%d -> ", temp->data);

temp = temp->next;

}

printf("NULL\n");

}

1. 实现链表的逆置

struct ListNode* reverseList(struct ListNode* head) {

if (head == NULL || head->next == NULL) return NULL;

struct LiseNode* former;

struct ListNode* latter;

struct ListNode* mid = head;

while (mid != NULL) {

latter = mid->next;

mid->next = former;

former = mid;

mid = latter;

}

}

2. 判断单链表中是否存在环

struct ListNode* detectCycle(struct ListNode* head) {

struct ListNode* fast = head;

struct ListNode* slow = head;

while(fast != NULL && fast->next != NULL) {

slow = slow->next;

fast = fast->next->next;

if(slow == fast) {

fast = head;

while(fast != slow) {

fast = fast->next;

slow = slow->next;

}

return slow;

}

}

return NULL;

}

3. 单链表相交,如何求交点

struct ListNode* getIntersectionNode(struct ListNode* headA, struct ListNode* headB) {

struct ListNode* p = headA;

struct ListNode* q = headB;

while(q != p) {

if (p == NULL)

p = headB;

else

p = p->next;

if (q == NULL)

q = headA;

else

q = q->next

}

return q;

}

4. 求有环链表第一个入环点

struct ListNode* detectCycle(struct ListNode* head) {

struct ListNode* fast = head;

struct ListNode* slow = head;

while(fast != NULL && fast->next != NULL) {

slow = slow->next;

fast = fast->next->next;

if(slow == fast) {

fast = head;

while(fast != slow) {

fast = fast->next;

slow = slow->next;

}

return slow;

}

}

return NULL;

}

5. 写出链表的删除一个节点的程序

void deleteNode(Node** headRef, int key) {

Node* temp = *headRef;

Node* prev = NULL;

if (temp == NULL) return;

if (temp->data == key) {

*headRef = temp->next; // 头指针后移

free(temp); // 释放原头节点

return;

}

while (temp != NULL && temp->data != key) {

prev = temp;

temp = temp->next;

}

if (temp == NULL) return;

prev->next = temp->next;

free(temp);

}

6. 用递归算法实现两个有序链表的合并

struct ListNode* Merge(struct ListNode* pHead1, struct ListNode* pHead2 ) {

// write code here

if (pHead1 == NULL) return pHead2;

if (pHead2 == NULL) return pHead1;

if (pHead1->val > pHead2->val) {

pHead2->next = Merge(pHead1, pHead2->next);

return pHead2;

} else {

pHead1->next = Merge(pHead1->next, pHead2);

return pHead1;

}

}

二、二叉树

满二叉树:除了最后一层,所有的节点都是满的,并且所有节点都有两个子节点

完全二叉树:最后一层可以是单节点,所有节点连续几种在左边。

二叉搜索数:BST,左子树中的所有节点值都小于该节点值。右子树中的所有节点值都大于该节点值。

平衡二叉树:AVL,左右子节点的高度不超过1的BST。

// 定义二叉树节点结构

typedef struct Node {

int data; // 存储节点的数据

struct Node* left; // 指向左子节点

struct Node* right; // 指向右子节点

} Node;

// 创建新节点

Node* createNode(int data) {

Node* newNode = (Node*)malloc(sizeof(Node));

if (newNode == NULL) {

printf("内存分配失败!\n");

exit(1);

}

newNode->data = data;

newNode->left = NULL;

newNode->right = NULL;

return newNode;

}

// 销毁二叉树

void destroyTree(Node* root) {

if (root == NULL) return;

destroyTree(root->left); // 递归释放左子树

destroyTree(root->right); // 递归释放右子树

free(root); // 释放当前节点

}

// 二叉树深度

int maxDepth(struct TreeNode* root){

if (root == NULL) return 0;

int lenLeft = maxDepth(root->left);

int lenRight = maxDepth(root->right);

return lenLeft > lenRight ? lenLeft + 1 : lenRight + 1;

}

1. 遍历

// 中序遍历:创建一个数组,数组作为传入参数保存遍历的结果

/**

* returnNum: 保存遍历出的元素

* returnSize: 保存二叉树的大小

*/

void inTra(struct TreeNode* root, int *returnNum, int* returnSize)

{

if(root==NULL) return;

inTra(root->left, returnNum, returnSize);

returnNum[(*returnSize)++] = root->val;

inTra(root->right, returnNum, returnSize);

}

int* inorderTraversal(struct TreeNode* root, int* returnSize) {

int *returnNum = (int *)malloc(sizeof(int)*101);

*returnSize = 0;

if(root==NULL) return NULL;

inTra(root,returnNum,returnSize);

return returnNum;

}

不需要保存的遍历:

// 前序遍历:根 -> 左 -> 右

void preorderTraversal(Node* root) {

if (root == NULL) return;

printf("%d ", root->data); // 访问根节点

preorderTraversal(root->left); // 遍历左子树

preorderTraversal(root->right); // 遍历右子树

}

// 中序遍历:左 -> 根 -> 右

void inorderTraversal(Node* root) {

if (root == NULL) return;

inorderTraversal(root->left); // 遍历左子树

printf("%d ", root->data); // 访问根节点

inorderTraversal(root->right); // 遍历右子树

}

// 后序遍历:左 -> 右 -> 根

void postorderTraversal(Node* root) {

if (root == NULL) return;

postorderTraversal(root->left); // 遍历左子树

postorderTraversal(root->right); // 遍历右子树

printf("%d ", root->data); // 访问根节点

}

2. 深度

int maxDepth(struct TreeNode* root) {

// 递归结束条件

if (root == NULL) return 0;

int l_depth = maxDepth(root->left);

int r_depth = maxDepth(root->right);

return (l_depth > r_depth ? l_depth : r_depth) + 1;

}

3. 是否平衡二叉树

bool isAVL(struct TreeNode* root)

{

struct TreeNode* left = root->left;

struct TreeNode* right = root->right;

int l_dep = maxDepth(left);

int r_dep = maxDepth(right);

if (l_dep == r_dep) return true;

else if (l_dep > r_dep) return ((l_dep-r_dep) < 1 ? true : false);

else return ((r_dep-l_dep) < 1 ? true : false);

}

三、排序查找算法及其改进

我想对于每一个经历过秋招的小伙伴们来说,十大排序基本都被问过(快速排序、归并排序、堆排序、冒泡排序、插入排序、选择排序、希尔排序、桶排序、基数排序)。

排序名称 最好时间复杂度 平均时间复杂度 最坏时间复杂度 空间复杂度

快排

归并

插入

冒泡

堆排

选择

1. 快速排序

void quickSort(vector<int>& arr, int left, int right) {

if (left >= right) return;

int pivot = arr[right];

int l = left - 1;

int r = left;

for (; r < right; ++r) {

if (arr[r] < pivot) {

l++;

swap(arr[l], arr[r]);

}

}

int povitIndex = l + 1;

swap(arr[povitIndex], arr[right]);

quickSort(arr, left, povitIndex - 1);

quickSort(arr, povitIndex + 1, right);

}

2. 冒泡排序

// 双重循环,每次循环次数减1.长度为5的数组,第一次循环对比4次

void bubble_sort(int *arr, int n) {

int flag;

for (int i = 0; i < n-1; i++) {

flag = 0;

for (int j = 0; j < n-1-i; j++) {

if (arr[j] > arr[j+1]) {

swap(&arr[j], &arr[j+1]);

flag = 1;

}

}

if (flag == 0) return;

}

}

3. 归并排序

/*

* 归并排序的思想:

* 1. merge函数,传入一个以m为界限的左右分别排序好的数组,然后把这个数组合并

* 1.1 首先malloc两个数组L,R然后填充,然后使用? :填充arr[k++]

* 2. mergeSort函数递归执行,停止条件l>=r;

*/

void merge(vector<int>& arr, int left, int mid, int right) {

int n1 = mid - left + 1;

int n2 = right - mid;

vector<int> L(arr.begin() + left, arr.begin() + left + n1); // 或 mid + 1

vector<int> R(arr.begin() + mid + 1, arr.begin() + mid + 1 + n2); // 或 right + 1

int i = 0, j = 0;

int k = left;

while (i < n1 && j < n2) arr[k++] = L[i] < R[j] ? L[i++] : R[j++];

while (i < n1) arr[k++] = L[i++];

while (j < n2) arr[k++] = R[j++];

}

void mergeSort(vector<int>& arr, int left, int right) {

if (left >= right) return;

int mid = left + (right - left)/2;

mergeSort(arr, left, mid);

mergeSort(arr, mid+1, right);

merge(arr, left, mid, right);

}

4. 堆排序

堆的数组表示:

对于数组中一个位置为i的节点(下标从0开始),

父节点:(i-1)/2

左子节点2i+1

右子节点2i+2

最后一个非叶子节点的下标是n/2 - 1。n是数组长度。

最大堆:每个父节点大于子节点。

最小堆:每个子节点大于父节点。

构建最大堆,排序

/**

* @brief 堆化函数

*

* 这是堆排序的核心。它将以 i 为根的子树调整为大顶堆。

* 假设 i 的左右子树已经是大顶堆。

*

* @param arr 待排序的数组

* @param n 数组的大小,也是堆中元素的总数

* @param i 当前需要堆化的子树的根节点索引

*/

void heapify(std::vector<int>& arr, int n, int i) {

int largest = i;

int left = 2 * i + 1;

int right = 2 * i + 2;

if (left < n && arr[left] > arr[largest]) largest = left;

if (right < n && arr[right] > arr[largest]) largest = right;

if (largest != i) {

std::swap(arr[i], arr[largest]);

heapify(arr, n, largest);

}

}

void maxHeap(std::vector<int>& arr) {

int n = arr.size();

for (int i = n / 2 - 1; i >= 0; i--) heapify(arr, n, i);

}

void heapSort(std::vector<int>& arr) {

int n = arr.size();

maxHeap(arr);

for (int i = n - 1; i > 0; i--) {

std::swap(arr[0], arr[i]);

heapify(arr, i, 0);

}

}

使用priority_heap容器适配器实现的堆排列

void heapSortUsingPriorityQueue(std::vector<int>& arr) {

if (arr.empty()) {

return;

}

// 1. 创建一个最大堆(默认行为)

// 将数组中的所有元素放入优先队列

std::priority_queue<int> max_heap;

for (int val : arr) {

max_heap.push(val);

}

// 2. 依次取出最大元素,并存回原数组

// 此时元素是按从大到小的顺序被取出的

int index = 0;

while (!max_heap.empty()) {

arr[index] = max_heap.top(); // 获取最大值

max_heap.pop(); // 从堆中移除

index++;

}

// 3. 因为得到的是降序序列,需要反转数组才能得到升序结果

std::reverse(arr.begin(), arr.end());

}

5. 插入排序

// 从第二个数开始往前插入数,前面部分是排序好的,假如有n=5个数据,第一次插入a[1],第4次插入a[4]。

// 所以外循环n-1次,从index=1开始。从j = i - 1依次向左比较,直到比较到最低位或者小于key的数。

// 两个关键点,i是需要插入的索引key=arr[i],i左边也就是j=i-1是排序好的节点,然后向左比对,当arr[j]<key时,arr[j+1]=key。

void insertSort(vector<int>& arr) {

for (int i = 0; i < arr.size(); ++i){

// i=2插入到前面排序好的数组,跟前面的一一比较

int key = arr[i];

int j = i-1;

while (j >= 0 && arr[j] > key) {

arr[j + 1] = arr[j];

j--;

}

arr[j + 1] = key;

}

}

6. 选择排序

// 选择排序函数(升序)

// 遍历数组,第一遍找出最小的放到第一个位置,第二遍从[1]开始,找出最小的,以此类推

void selectionSort(std::vector<int>& arr) {

int n = arr.size();

for (int i = 0; i < n - 1; ++i) {

int minIndex = i;

for (int j = i + 1; j < n; ++j) {

if (arr[j] < arr[minIndex]) minIndex = j;

}

if (minIndex != i) swap(arr[i], arr[minIndex]);

}

}

四、数组

二分查找法

int searchInsert(vector<int>& nums, int target) {

int left = 0;

int right = nums.size() - 1;

while (left <= right) {

int mid = left + (right - left)/2;

if (nums[mid] == target) return mid;

else if (nums[mid] < target) left = mid + 1;

else right = mid - 1;

}

return left;

}

五、字符串

1. 字符串复制

void mucpy(char *s1, char *s2) {

while(*s1++ = *s2++);

}

2. 字符串翻转

//C++

std::reverse(s.begin(), s.end());

void swap(char* str, int start, int end) {

char temp = 0;

while (start <= end) {

temp = str[start];

str[start] = str[end];

str[end] = temp;

end--;

start++;

}

}

void reverseStr(char* str, int n) {

int start = 0;

int end = n - 1;

swap(str, start, end);

}

3. 单词翻转

// 字符串反转

// 1. 使用算法实现 #include <algorithm>

std::string s = "hello";

std::reverse(s.begin(), s.end());

// 2. 手动实现

while (left < right) {

std::swap(s[left++], s[right--]);

}

// 单词反转

std::string reverseWords(std::string s) {

// 1. 分裂单词,存入字符串数组

std::stringstream ss; ss.str(s);

std::vector<std::string> words;

std::string word;

while (ss >> word) {

words.push_back(word);

}

// 2. 反转数组

std::reverse(words.begin(), words.end());

// 2. 合并单词

std::string result;

for (int i = 0; i < words.size(); ++i) {

if (i != 0) result += " ";

result += words[i];

}

return result;

}

#include <stdio.h>

#include <string.h>

// 反转字符串的某一部分 [start, end]

void reverse(char* s, int start, int end) {

while (start < end) {

char temp = s[start];

s[start] = s[end];

s[end] = temp;

start++;

end--;

}

}

// 反转字符串中的单词顺序

void reverseWords(char* s) {

int len = strlen(s);

if (len <= 1) return;

// 1. 反转整个字符串

reverse(s, 0, len - 1);

// 2. 逐个反转每个单词

int wordStart = 0;

for (int i = 0; i <= len; i++) {

if (s[i] == ' ' || s[i] == '\0') {

reverse(s, wordStart, i - 1);

wordStart = i + 1;

}

}

}

int main() {

char str[] = "Hello world";

printf("Original: \"%s\"\n", str);

reverseWords(str);

printf("Reversed: \"%s\"\n", str);

return 0;

}

六、图

图的几个概念:

节点(顶点,vertex),边(edge),有向图/无向图(单向边,双向边),带权图(边带有数值(权重),比如两个城市之间的举例,两个任务之间的时间成本)

图在算法中的经典应用:最短路径问题,搜索问题(BFS,DFS)。

想象你在一个迷宫里,要从起点走到终点,迷宫有很多岔路口,每个岔路口又有多个分支。你可以用两种策略来探索迷宫:深度优先搜索(DFS):一条路走到黑,选一条路一直走下去,直到走不通了,再返回上一个岔路口,换另一条路继续,使用栈或者递归。广度优先搜索(BFS):层层推进,先走一步看看所有可能,再走第二步……像水波一样一圈一圈扩散,用队列实现,适合找最短路径。

假设一个无向图

0 -- 1 -- 3

| |

2 -- 4

用邻接表表示为:

0 -> 1, 2

1 -> 0, 3, 4

2 -> 0, 4

3 -> 1

4 -> 1, 2

#include <iostream>

#include <vector>

#include <queue>

#include <stack>

using namespace std;

// 图的邻接表表示

vector<vector<int>> graph = {

{1, 2}, // 0

{0, 3, 4}, // 1

{0, 4}, // 2

{1}, // 3

{1, 2} // 4

};

vector<bool> visited(5, false); // 记录节点是否被访问过

// 深度优先搜索(DFS)- 递归实现

void dfs(int node) {

visited[node] = true;

cout << node << " ";

for (int neighbor : graph[node]) {

if (!visited[neighbor]) {

dfs(neighbor);

}

}

}

// 深度优先搜索(DFS)- 非递归(栈)实现

void dfs_stack(int start) {

fill(visited.begin(), visited.end(), false); // 重置访问状态

stack<int> s;

s.push(start);

visited[start] = true;

while (!s.empty()) {

int node = s.top();

s.pop();

cout << node << " ";

for (int neighbor : graph[node]) {

if (!visited[neighbor]) {

visited[neighbor] = true;

s.push(neighbor);

}

}

}

}

// 广度优先搜索(BFS)- 队列实现

void bfs(int start) {

fill(visited.begin(), visited.end(), false); // 重置访问状态

queue<int> q;

q.push(start);

visited[start] = true;

while (!q.empty()) {

int node = q.front();

q.pop();

cout << node << " ";

for (int neighbor : graph[node]) {

if (!visited[neighbor]) {

visited[neighbor] = true;

q.push(neighbor);

}

}

}

}

int main() {

cout << "DFS (递归): ";

dfs(0);

cout << endl;

cout << "DFS (栈): ";

dfs_stack(0);

cout << endl;

cout << "BFS (队列): ";

bfs(0);

cout << endl;

return 0;

}

七、嵌入式常考的函数实现

1. memcpy

void* my_memcpy(const void* dest, const void* src, int n) {

char* d = (char*)dest;

char* s = (char*)src;

// 判断重叠,s在前从后往前拷贝,s在后从前往后拷贝

if (s < d && s + n < d) {

for (int i = n - 1; i >= 0; ++i) {

d[i] = s[i];

}

} else {

for (int i = 0; i < n; ++i) {

d[i] = s[i];

}

}

return dest;

}

2. strcpy

char *my_strcpy(char *dest, char *src) {

if (dest == NULL || src == NULL) return NULL;

char *ret = dest;

while ((*dest++ = *src++) != '\0');

return ret;

}

3. strncpy

#include <stddef.h>

char *my_strncpy(char *dest, char *src, size_t n) {

if (dest == NULL || src == NULL) return NULL;

char *ret = dest;

while (n && (*dest++ = *src++) != '\0') n--;

// n有剩余

if (n != 0) {

while (n--) *dest++ = '\0';

}

return dest;

}

4. strlen

size_t my_strlen(const char *str) {

if (str == NULL) return 0;

size_t len = 0;

while (*str++ != '\0') len++;

return len;

}

5. strcmp

int my_strcmp(const char *s1, const char *s2) {

if (s1 == NULL || s2 == NULL) return -1;

while (*s1 && (*s1 == *s2)) {

s1++;

s2++;

}

return *(unsigned char *)s1 - *(unsigned char *)s2;

}

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/10 11:19:23

iOS功能开关架构设计:5步构建企业级远程配置系统

iOS功能开关架构设计&#xff1a;5步构建企业级远程配置系统 【免费下载链接】awesome-ios-architecture :japanese_castle: Better ways to structure iOS apps 项目地址: https://gitcode.com/gh_mirrors/aw/awesome-ios-architecture 在当今快速迭代的移动应用开发环…

作者头像 李华
网站建设 2026/5/9 0:49:59

终端AI编程助手:5分钟掌握正则搜索高效定位代码

终端AI编程助手&#xff1a;5分钟掌握正则搜索高效定位代码 【免费下载链接】opencode 一个专为终端打造的开源AI编程助手&#xff0c;模型灵活可选&#xff0c;可远程驱动。 项目地址: https://gitcode.com/GitHub_Trending/openc/opencode 在庞大的代码库中快速找到特…

作者头像 李华
网站建设 2026/5/9 0:56:22

Apple Color Emoji 在 Linux 系统中的终极配置指南

Apple Color Emoji 在 Linux 系统中的终极配置指南 【免费下载链接】apple-emoji-linux Apple Color Emoji for Linux 项目地址: https://gitcode.com/gh_mirrors/ap/apple-emoji-linux 想让你的 Linux 系统也能享受苹果设备上那般精美绝伦的彩色表情符号吗&#xff1f;…

作者头像 李华
网站建设 2026/5/10 10:57:54

MPV播放器窗口定位:从“乱跳“到“精准落地“的完整指南

开篇&#xff1a;你的MPV窗口还在"随机游走"吗&#xff1f; 【免费下载链接】mpv &#x1f3a5; Command line video player 项目地址: https://gitcode.com/GitHub_Trending/mp/mpv 每次打开视频&#xff0c;MPV窗口就像个调皮的孩子&#xff0c;总爱出现在意…

作者头像 李华
网站建设 2026/5/6 16:45:16

【URP】Unity[后处理]运动模糊MotionBlur

Motion Blur 概念与作用Motion Blur&#xff08;运动模糊&#xff09;是一种模拟真实相机在拍摄快速移动物体或自身移动时产生的模糊效果的后处理技术。它通过模糊图像中运动物体的轨迹&#xff0c;增强动态场景的真实感和速度感。在游戏开发中&#xff0c;Motion Blur 主要有以…

作者头像 李华
网站建设 2026/5/6 23:30:14

Qwen3-VL-235B-Instruct技术揭秘:多模态智能的三大核心突破

在人工智能向多模态融合发展的关键节点&#xff0c;阿里云最新发布的Qwen3-VL-235B-Instruct模型以三项革命性技术突破&#xff0c;重新定义了视觉-语言交互的能力边界。这款具备2350亿参数的巨型模型&#xff0c;不仅实现了从二维感知到三维认知的跨越&#xff0c;更在时序理解…

作者头像 李华