(十)嵌入式面试题收集:15道
问题 1(信息管理界面设计,C 语言实现)
以下是基于 C 语言的信息管理系统,使用结构体存储信息,支持命令行交互实现增删改查功能,以学号、姓名、班级为例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define MAX 100 // 最大记录数
#define LEN 20 // 字符串长度// 信息结构体
typedef struct {char id[LEN]; // 学号char name[LEN]; // 姓名char cls[LEN]; // 班级
} Info;Info infos[MAX]; // 存储信息数组
int count = 0; // 当前记录数// 刷新并显示所有信息
void refresh() {system("cls"); // 清屏(Windows系统,Linux用"clear")printf("=== 当前信息列表 ===\n");printf("学号\t姓名\t班级\n");for (int i = 0; i < count; i++) {printf("%s\t%s\t%s\n", infos[i].id, infos[i].name, infos[i].cls);}printf("=====================\n");
}// 添加信息
void add() {if (count >= MAX) {printf("信息已满,无法添加!\n");return;}Info newInfo;printf("请输入学号:");scanf("%s", newInfo.id);printf("请输入姓名:");scanf("%s", newInfo.name);printf("请输入班级:");scanf("%s", newInfo.cls);// 检查学号是否重复for (int i = 0; i < count; i++) {if (strcmp(infos[i].id, newInfo.id) == 0) {printf("学号已存在!\n");return;}}infos[count++] = newInfo;refresh();printf("添加成功!\n");
}// 按学号查找(返回索引,-1表示不存在)
int findById(char *id) {for (int i = 0; i < count; i++) {if (strcmp(infos[i].id, id) == 0) {return i;}}return -1;
}// 显示全部信息
void showAll() {refresh();if (count == 0) {printf("暂无信息!\n");}
}// 按条件查找
void search() {int choice;char key[LEN];printf("请选择查找条件:1-学号 2-姓名 3-班级:");scanf("%d", &choice);printf("请输入查找内容:");scanf("%s", key);refresh();printf("=== 查找结果 ===\n");int found = 0;for (int i = 0; i < count; i++) {if ((choice == 1 && strcmp(infos[i].id, key) == 0) ||(choice == 2 && strcmp(infos[i].name, key) == 0) ||(choice == 3 && strcmp(infos[i].cls, key) == 0)) {printf("%s\t%s\t%s\n", infos[i].id, infos[i].name, infos[i].cls);found = 1;}}if (!found) {printf("未找到匹配信息!\n");}
}// 修改信息
void modify() {char id[LEN];printf("请输入要修改的学号:");scanf("%s", id);int index = findById(id);if (index == -1) {refresh();printf("未找到该学号信息!\n");return;}// 显示当前信息printf("当前信息:学号=%s 姓名=%s 班级=%s\n", infos[index].id, infos[index].name, infos[index].cls);printf("是否修改?(1-是 0-否):");int confirm;scanf("%d", &confirm);if (confirm != 1) {refresh();return;}// 修改信息printf("请输入新姓名(不修改按回车):");char name[LEN];getchar(); // 清空缓冲区fgets(name, LEN, stdin);name[strcspn(name, "\n")] = '\0'; // 去除换行符if (strlen(name) > 0) {strcpy(infos[index].name, name);}printf("请输入新班级(不修改按回车):");char cls[LEN];fgets(cls, LEN, stdin);cls[strcspn(cls, "\n")] = '\0';if (strlen(cls) > 0) {strcpy(infos[index].cls, cls);}refresh();printf("修改成功!\n");
}// 删除信息
void delete() {char id[LEN];printf("请输入要删除的学号:");scanf("%s", id);int index = findById(id);if (index == -1) {refresh();printf("未找到该学号信息!\n");return;}// 移位删除for (int i = index; i < count - 1; i++) {infos[i] = infos[i + 1];}count--;refresh();printf("删除成功!\n");
}// 删除全部信息
void deleteAll() {printf("确定要删除全部信息吗?(1-是 0-否):");int confirm;scanf("%d", &confirm);if (confirm == 1) {count = 0;refresh();printf("全部信息已删除!\n");} else {refresh();}
}// 显示菜单
void menu() {printf("\n===== 信息管理系统 =====\n");printf("1. 添加信息\n");printf("2. 显示全部\n");printf("3. 查找信息\n");printf("4. 修改信息\n");printf("5. 删除信息\n");printf("6. 删除全部\n");printf("0. 退出系统\n");printf("请选择操作:");
}int main() {int choice;while (1) {refresh();menu();scanf("%d", &choice);switch (choice) {case 1: add(); break;case 2: showAll(); break;case 3: search(); break;case 4: modify(); break;case 5: delete(); break;case 6: deleteAll(); break;case 0: printf("谢谢使用,再见!\n"); return 0;default: printf("无效操作,请重新选择!\n");}printf("按任意键继续...");getchar(); // 等待输入getchar();}
}
问题 2(棋子交换问题,C 语言实现)
以下是解决 2N+1 格棋子交换问题的 C 语言代码,支持通用 N 值:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 打印当前棋盘状态
void printBoard(char *board, int size) {for (int i = 0; i < size; i++) {printf("%c ", board[i]);}printf("\n");
}// 移动棋子(src:源位置,dest:目标位置)
void move(char *board, int src, int dest) {board[dest] = board[src];board[src] = ' ';printf("移动:%d -> %d,当前状态:", src, dest);printBoard(board, 2 * (src > dest ? src : dest) + 1); // 打印当前状态
}// 解决棋子交换问题(n:每种棋子数量,总格子数=2n+1)
void solveChessSwap(int n) {int size = 2 * n + 1;char *board = (char *)malloc(size * sizeof(char));if (!board) {printf("内存分配失败!\n");return;}// 初始化棋盘:n个'A' + 空格 + n个'B'for (int i = 0; i < n; i++) {board[i] = 'A';}board[n] = ' '; // 中间是空格for (int i = n + 1; i < size; i++) {board[i] = 'B';}printf("初始状态:");printBoard(board, size);// 通用解法逻辑for (int i = 0; i < n; i++) {// B向左移动或跳跃(从n+1+i到n-i)move(board, n + 1 + i, n - i);// A向右移动或跳跃(从n-2-i到n+2+i,i=0时n-2-i可能为负,需特殊处理)if (n - 2 - i >= 0) {move(board, n - 2 - i, n + 2 + i);}}// 补充步骤(确保最终状态正确)if (n > 1) {move(board, n + 1, n - 1);if (n - 2 >= 0) {move(board, n - 2, n + 2);}}printf("最终状态:");printBoard(board, size);free(board);
}int main() {int n;printf("请输入棋子数量n(总格子数为2n+1):");scanf("%d", &n);solveChessSwap(n);return 0;
}
说明:
- 问题 1 的 C 语言实现通过命令行交互,使用结构体数组存储信息,支持所有要求的功能,操作后自动刷新界面。
- 问题 2 的 C 语言实现通过模拟棋子移动过程,支持任意 N 值的 2N+1 格情形,遵循移动规则(可移动一格或跳过对方一个棋子,A 只能右移,B 只能左移)。运行时输入 n 值(如题目中的 n=3)即可看到完整移动过程。
问题 1:关键字 const 有什么含义?
const 是 C/C++ 中的关键字,用于声明常量,表示其修饰的变量或对象的值在定义后不能被修改。主要作用包括:
- 定义常量:如
const int MAX = 100;,MAX的值不可更改。 - 修饰指针:
const int *p(或int const *p):指针指向的内容不可修改,但指针本身可以指向其他地址。int *const p:指针本身不可修改(即指向的地址固定),但指向的内容可以修改。const int *const p:指针本身和指向的内容都不可修改。
- 修饰函数参数:表示函数内部不会修改该参数的值,增强代码可读性和健壮性。
- 修饰函数返回值:表示函数返回的是常量,调用者不能修改该返回值。
问题 2:检查下面的程序有没有问题
void test1()
{char string[10];char* str1="0123456789";strcpy(string, str1);
}
存在问题。
str1指向的字符串"0123456789"长度为 10(包含末尾的\0终止符),共 11 个字符。- 而
string数组仅分配了 10 个字符的空间,strcpy会将str1的所有字符(包括\0)复制到string中,导致数组越界(缓冲区溢出),可能引发程序崩溃或未定义行为。
问题 3:已知一个数组 table,用一个宏定义,求出数据的元素个数
可以通过数组总字节数除以单个元素字节数来计算元素个数,宏定义如下:
#define ARRAY_SIZE(table) (sizeof(table) / sizeof(table[0]))
- 例如,对于
int table[5];,sizeof(table)是5 * sizeof(int),sizeof(table[0])是sizeof(int),相除结果为5,即元素个数。
问题 4:写一个 “标准” 宏 MIN,这个宏输入两个参数并返回较小的一个
需要考虑参数副作用(如参数是表达式时的重复计算问题),“标准” 宏实现如下:
#define MIN(a, b) ((a) < (b) ? (a) : (b))
- 括号的作用是确保宏在复杂表达式中能正确运算,避免优先级错误。
问题 5:do……while 和 while 有什么区别?
| 特性 | while 循环 | do……while 循环 |
|---|---|---|
| 执行顺序 | 先判断条件,条件为真时执行循环体 | 先执行循环体,再判断条件 |
| 最少执行次数 | 0 次(条件初始为假时,循环体不执行) | 1 次(无论条件是否为真,循环体至少执行一次) |
| 语法格式 | while(条件) { 循环体; } | do { 循环体; } while(条件); |
问题 6:一个 32 位的机器,该机器的 16 位无符号的数据指针是多少位?
32 位。
- 指针的位数由机器的地址总线宽度决定,与指针指向的数据类型无关。在 32 位机器中,地址总线是 32 位的,因此无论数据指针是指向 16 位、32 位还是其他类型的数据,指针本身的位数都是 32 位。
问题 7:12 位 ADC 的输入电压计算
已知 12 位 ADC 的量程为\(0 \sim 4095\)(\(2^{12}-1\)),若 ADC 参考电压为\(V_{ref}\),输入电压经电阻\(R_1\)和\(R_2\)分压后接入 ADC(分压关系为\(V_{adc} = \frac{R_2}{R_1+R_2}V_{in}\)),则输入电压\(V_{in}\)的计算公式为:
\(V_{in} = \frac{adc\_value \times V_{ref} \times (R_1 + R_2)}{4095 \times R_2}\)
其中,\(adc\_value\)为 ADC 的采样值。
问题 8:计算 0 到 1000 的整数和
C 语言实现:
// 方法1:循环累加
int sum_0_to_1000_loop() {int sum = 0;for (int i = 0; i <= 1000; i++) {sum += i;}return sum;
}// 方法2:等差数列求和公式(更高效)
int sum_0_to_1000_formula() {// 公式:S = n*(a1 + an)/2,其中n=1001(项数),a1=0,an=1000return 1000 * 1001 / 2; // 结果为500500
}
问题 9:滑动滤波算法实现
滑动滤波通过维护固定长度的缓冲区,每次更新数据后计算平均值,适用于平滑高频噪声。
C 语言实现(窗口长度为 5):
#define FILTER_WINDOW 5 // 滑动窗口大小
static int adc_buffer[FILTER_WINDOW] = {0}; // 存储历史采样值
static int buffer_index = 0; // 当前缓冲区索引
static int total_sum = 0; // 缓冲区总和// 输入新的ADC采样值,返回滤波后的值
int sliding_filter(int new_adc) {// 减去缓冲区中最旧的值total_sum -= adc_buffer[buffer_index];// 存入新值并累加adc_buffer[buffer_index] = new_adc;total_sum += new_adc;// 更新索引(循环覆盖)buffer_index = (buffer_index + 1) % FILTER_WINDOW;// 返回平均值(滤波结果)return total_sum / FILTER_WINDOW;
}
说明:
- 静态变量确保缓冲区状态在多次调用中保持。
- 每次更新仅需加减操作,时间复杂度为\(O(1)\),效率高。
问题 1:用 C 语言实现一个函数,判断一个整数是否为素数
答案 1:
#include <stdbool.h>
#include <math.h>// 判断n是否为素数(素数:大于1的自然数,除了1和自身外无其他因数)
bool is_prime(int n) {if (n <= 1) {return false; // 1和负数不是素数}if (n == 2) {return true; // 2是素数}if (n % 2 == 0) {return false; // 偶数不是素数(除2外)}// 检查到sqrt(n)即可,因为因数成对出现for (int i = 3; i <= sqrt(n); i += 2) {if (n % i == 0) {return false;}}return true;
}
问题 2:编写 C 语言代码,将一个字符串反转(如 "hello" 反转后为 "olleh")
答案 2:
#include <string.h>void reverse_string(char *str) {if (str == NULL) {return; // 空指针处理}int len = strlen(str);int left = 0;int right = len - 1;// 左右指针交换字符,直到相遇while (left < right) {char temp = str[left];str[left] = str[right];str[right] = temp;left++;right--;}
}
问题 3:用 C 语言实现冒泡排序算法,对整数数组进行升序排序
答案 3:
// 冒泡排序(升序):每次比较相邻元素,将大的元素"浮"到末尾
void bubble_sort(int arr[], int n) {if (n <= 1) {return; // 数组长度<=1无需排序}for (int i = 0; i < n - 1; i++) {int flag = 0; // 标记本轮是否有交换,优化无交换时提前退出for (int j = 0; j < n - 1 - i; j++) {if (arr[j] > arr[j + 1]) {// 交换相邻元素int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;flag = 1;}}if (flag == 0) {break; // 无交换,数组已有序}}
}
问题 4:编写 C 语言函数,计算两个整数的最大公约数(GCD)
答案 4:
// 方法1:辗转相除法(欧几里得算法)
int gcd(int a, int b) {// 保证a >= b,若a < b则交换if (a < b) {int temp = a;a = b;b = temp;}// 当余数为0时,除数即为最大公约数while (b != 0) {int remainder = a % b;a = b;b = remainder;}return a;
}// 方法2:递归实现辗转相除法
int gcd_recursive(int a, int b) {if (b == 0) {return a;} else {return gcd_recursive(b, a % b);}
}
问题 5:用 C 语言实现一个函数,将十进制整数转换为二进制字符串(如 10 转换为 "1010")
答案 5:
#include <string.h>// 将十进制整数n转换为二进制字符串,存储到buf中(需保证buf足够大)
void decimal_to_binary(int n, char *buf) {if (buf == NULL) {return;}if (n == 0) {strcpy(buf, "0");return;}int is_negative = 0;// 处理负数(简单表示为符号+绝对值的二进制,非补码)if (n < 0) {is_negative = 1;n = -n;}int index = 0;// 提取二进制位(从低位到高位)while (n > 0) {buf[index++] = (n % 2) ? '1' : '0';n /= 2;}// 添加负号(如果是负数)if (is_negative) {buf[index++] = '-';}buf[index] = '\0'; // 字符串结束符// 反转字符串(因为上面是从低位开始存储的)reverse_string(buf); // 复用问题2的反转函数
}