嵌软八股大全1 - C & C++ 手撕真题
1、OJ在线编程常见输入输出练习
1.1、A+B(7)
题目:已知满足 1 <= n <= 100
,输入若干行形如 1 2 3...
的由空格隔开的 n
个数据(n 不固定),要求输出每一行数据求和后的结果
示例输入
1 2 3
4 5
0 0 0 0 0
示例输出
6
9
0
注意:
- 可以利用
getchar() == '\n'
判断是否一行结束
解答:
#include <stdio.h>
int main() {
int n,m=0;
while(scanf("%d", &n) != EOF) {
m += n;
if(getchar() == '\n'){
printf("%d\n", m);
m = 0;
}
}
return 0;
}
1.2、字符串排序(1)
题目:已知输入为两行,第一行为数字 n
,第二行是形如 a b c..
的由空格隔开的 n
个字符串,要求输出一行排序后的字符串,空格隔开,无结尾空格
示例输入
5
c d a bb e
示例输出
a bb c d e
注意:
- 每个元素都是一个字符串
- 使用 C 库函数
qsort
快速排序
解答:
#include <stdio.h>
int compare(const void *a,const void*b)
{
return strcmp((const char *)a, (const char *)b);
}
int main() {
int n,i;
scanf("%d", &n);
char arr[n][100];
for(i=0;i<n;i++){
scanf("%s", &arr[i]);
}
qsort(arr, n, sizeof(arr[0]), compare);
for(i=0;i<n;i++){
if(i == (n-1)) printf("%s", &arr[i]);
else printf("%s ", &arr[i]);
}
return 0;
}
1.3、字符串排序(3)
题目:已知满足 n < 100
,输入形如 xxx,xxx,xxx...
的由逗号隔开的 n 个字符串,输出一行排序后的字符串,用 ,
隔开,无结尾空格
示例输入
a,c,bb
f,dddd
nowcoder
示例输出
a,bb,c
dddd,f
nowcoder
注意:
- 现在每一行都是一个不能分割的字符串
- 使用
char *fgets(char *str, int n, FILE *stream)
获取每一行输入 - 使用
size_t strcspn(const char *str1, const char *str2)
快速找到字符串 str1 中匹配字符串 str2 的位置 - 使用
char *strtok(char *str, const char *delim)
分解字符串 str 为一组字符串,delim 为分隔符
解答:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_LINE_LENGTH 100
// 比较函数,用于qsort排序
int compare(const void *a, const void *b) {
return strcmp(*(const char **)a, *(const char **)b);
}
// 主函数
int main() {
char line[MAX_LINE_LENGTH];
while (fgets(line, sizeof(line), stdin)) {
// 去掉换行符
line[strcspn(line, "\n")] = 0;
// 拆分字符串
char *tokens[MAX_LINE_LENGTH];
int n = 0;
char *token = strtok(line, ",");
while (token != NULL) {
tokens[n++] = token;
token = strtok(NULL, ",");
}
// 排序
qsort(tokens, n, sizeof(char *), compare);
// 输出结果
for (int i = 0; i < n; i++) {
printf("%s", tokens[i]);
if (i < n - 1) {
printf(",");
}
}
printf("\n");
}
return 0;
}
1.4、“看不见的错误”
题目:
已知整数 a,b 满足 0 < 𝑎, 𝑏 < 2×10^10
,按照形如 1 1
的格式输入多组测试用例,两个整数间用空格隔开,要求输出两个整数的和
示例输入:
1 1
示例输出:
2
注意:
- 此题潜在的风险在于输入的两个数
a,b
最大值为 2×10^10,所以编程时要注意输入的值的类型,如果为int
,数太大则会溢出
解答:
#include <stdio.h>
int main() {
long m,n;
while(scanf("%ld %ld", &m, &n) != EOF){
if(getchar() == '\n'){
printf("%ld\n", m+n);
}
}
return 0;
}
1.5、总结
总结如下
- ACM 模式下使用
scanf() / cin()
作为试题输入 - 使用
printf() / cout()
作为试题输出 - 使用
getchar() == '\n'
来判断一行的输出是否结束 - 使用
qsort
库函数快速排序
常用标准库函数
#include <stdio.h>
char *fgets(char *str, int n, FILE *stream)
常用字符串库函数
#include <string.h>
size_t strcspn(const char *str1, const char *str2)
char *strtok(char *str, const char *delim)
2、笔试真题
2.1、求斐波那契第 n 项的值?
// 递归
int fibonacci_recursive(int n) {
if (n <= 0) {
return 0;
} else if (n == 1) {
return 1;
} else {
return fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2);
}
}
// 迭代
int fibonacci_iterative(int n) {
if (n <= 0) {
return 0;
} else if (n == 1) {
return 1;
}
int prev1 = 1, prev2 = 0;
int result = 0;
for (int i = 2; i <= n; ++i) {
result = prev1 + prev2;
prev2 = prev1;
prev1 = result;
}
return result;
}
变形:已知一个数列的前3个数为3,4,5,以后每个数为前3个数的和,编程序求此数列的第N项。
int fibonacci_recursive(int n) {
if (n <= 0) {
return 3;
} else if (n == 1) {
return 4;
} else if (n == 1) {
return 5;
} else {
return fibonacci_recursive(n - 1)
+ fibonacci_recursive(n - 2)
+ fibonacci_recursive(n - 3);
}
}
2.2、排列组合?
有 1、2、3、4 四个数字,用 C 语言编程计算能组合出多少个不重复的三位数?
#include <stdio.h>
int main() {
int count = 0;
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 4; j++) {
if (j == i) continue;
for (int k = 1; k <= 4; k++) {
if (k == i || k == j) continue;
printf("%d%d%d\n", i, j, k);
count++;
}
}
}
printf("All Situations: %d\n", count);
return 0;
}
2.3、矩阵相乘?
// 需要满足 colsA == rowsB 才可以进行矩阵相乘
void multiplyMatrices(int rowsA, int colsA, int matrixA[rowsA][colsA],
int rowsB, int colsB, int matrixB[rowsB][colsB],
int result[rowsA][colsB]) {
// 无法相乘
if(colsA != rowsB)
return;
// 初始化结果矩阵
for (int i = 0; i < rowsA; i++) {
for (int j = 0; j < colsB; j++) {
result[i][j] = 0;
}
}
// 进行矩阵乘法运算
for (int i = 0; i < rowsA; i++) {
for (int j = 0; j < colsB; j++) {
for (int k = 0; k < colsA; k++) {
result[i][j] += matrixA[i][k] * matrixB[k][j];
}
}
}
}
2.4、手撕 memcpy()
?
// 自定义 memcpy 函数
void my_memcpy(void *dest, const void *src, size_t n)
{
char *d = (char *)dest;
const char *s = (char *)src;
// 循环复制每个字节
while (n--) {
*d++ = *s++;
}
}
2.5、手撕 memcpy_s()
// 函数原型
// errno_t memcpy_s(void *dest, size_t destSize, const void *src, size_t count);
#include <stdio.h>
#include <errno.h>
errno_t memcpy_s(void* dest, size_t dest_size, const void* src, size_t count) {
// 检查空指针
if (dest == nullptr || src == nullptr) {
return EINVAL; // 参数无效
}
// 检查目标缓冲区大小是否足够
if (count > dest_size) {
// 若目标缓冲区不够大,则不执行复制,返回错误码
return ERANGE; // 超出范围
}
// 执行内存复制
unsigned char* d = (unsigned char*)dest;
const unsigned char* s = (const unsigned char*)src;
for (size_t i = 0; i < count; i++) {
d[i] = s[i];
}
return 0; // 成功
}
2.6、手撕 strcpy()
?
// 原型:char* strcpy(char* _Dest, const char* _Source);
// 字符串赋值函数
char* my_strcpy(char* dest, const char* src)
{
char *temp = dest;
// 将 src 的每个字符复制到 dest,直到遇到空字符
while((*temp++ = *src++) != '\0'){}
return temp;
}
2.7、手撕 strcat()
?
// 原型:char* strcat(char* _Dest, const char* _Source);
// 字符串拼接函数
char* my_strcat(char* dest, const char* src)
{
char *temp = dest;
// 移动到 dest 的末尾
while (*dest) {
dest++;
}
// 追加 src 到 dest 的末尾
while ((*dest++ = *src++) != '\0'){}
return temp;
}
2.8、手撕 strlen()
?
// 原型:size_t __cdecl strlen(const char *_Str);
// 计算字符串长度函数
size_t my_strlen(const char* str)
{
size_t length = 0;
// 遍历字符串直到遇到空字符
while (*str++) {
length++;
}
// 返回字符串的长度
return length;
}
2.9、大端与小端相互转化?
// val = 0x12345678;
int swap_endian(int val) {
// 0x00000012 | 0x00003400 | 0x00560000 | 0x78000000 = 0x78563412
return ((val >> 24) & 0x000000FF) |
((val >> 8) & 0x0000FF00) |
((val << 8) & 0x00FF0000) |
((val << 24) & 0xFF000000);
}
2.10、实现一个 mutex 互斥锁?
关键使用 TestAndSet
函数,该函数可以原子的测试并修改给定内存位置的值
int TestAndSet(int *ptr, int new)
{
int old = *ptr;
*ptr = new;
return old;
}
自己实现一个简单的锁
//锁结构体数据
typedef struct __lock_t { int flag; } lock_t;
//初始化锁
void init(lock_t *mutex)
{
// 0: lock is available
// 1: lock is held
mutex->flag = 0;
}
//上锁
void lock(lock_t *mutex)
{
while (TestAndSet(&mutex->flag, 1) == 1) {;}
}
//解锁
void unlock(lock_t *mutex)
{
mutex->flag = 0;
}
2.11、实现字符串反转?
“abcdefg“ -> ”gfedcba”
辅助数组方式
void reverseString(char *str) {
int n = strlen(str);
char temp[n + 1];
for (int i = 0; i < n; i++) {
temp[i] = str[n - 1 - i];
}
temp[n] = '\0';
strcpy(str, temp);
}
双指针交换方式
void reverseString(char *str) {
int n = strlen(str);
char temp;
int left = 0;
int right = n - 1;
while (left < right) {
temp = str[left];
str[left] = str[right];
str[right] = temp;
left++;
right--;
}
}
2.12、求素数?
使用 C/C++ 实现求 100 以内的素/质数
素数:除了 1 和它自身之外,不能被其他自然数整除的数
#include <stdio.h>
#define MAX 100
// 埃拉托斯特尼筛法
void sieve_of_eratosthenes(bool prime[]) {
// 初始化所有都为 true
for (int i = 0; i <= MAX; i++) {
prime[i] = true;
}
// 0
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
欢迎来到我的专栏,在这里,我将整理并分享2024年各大企业的真实笔试/面试真题,同时还整理了嵌入式软件相关的八股知识。专栏内容涵盖C/C++基础、嵌软常见通信协议、ARM、FreeRTOS、Linux OS相关问题汇总,希望能帮助求职者了解考试趋势和嵌入式常见考点。无论你是准备面试,还是希望提升自己的专业知识,这里都能为你提供宝贵的参考和学习资源。