C语言作为嵌入式Linux开发的必备工具,作为嵌入式Linux开发的基础语言,那么在面试嵌入式工程师时C语言定是面试中的重中之重 。作为一名大三的老学长,不得不为找工作做必要准备。每天做一道C语言面试题,为面试打基础。
2021.01.19
转眼间2020年就结束了,2020年我总共投递了5家公司,目前拿到了两家公司的实习机会。发现自己在面试中有很多的足。就在前两天笔试结束后的第50天我终于等到了嵌入式面试官的面试邀请!面试官人很好就按照你说的思路来问你,中途问了很多的知识我发现我掌握的还不是特别清楚。简单整理一下面试的内容啦!
- 做一个简短的自我介绍
- 栈和堆有什么区别,谈谈栈和堆的理解
- 问了擅长什么语言,然后数据结构学的怎么样(之前我还是太天真了,以为嵌入式面试不怎么考数据结构)
- 问完我数据结构以后就是给你出相关的题目让你说思路,我的题目是用链表来实现栈这种数据结构(没有回答正确)
- 然后就问了项目中相关的嵌入式部分,对于通信有哪些了解(串口通信、IIC、SPI)。面试官问了串口通信怎么配置,然后IIC相对于串口通信有什么优点。
- 然后就是问了一点简单的Linux命令,怎么查找文件名为cvte的文件
- 问了关于网络有没有了解,然后就问了TCP和UDP的区别,还有端口号相关的知识。
- 最后是一道编程题,共享屏幕让用递归判断一个数组是否为递归数组,中间运行的比较慢,出了一些问题。然后在面试官的帮助下让程序运行的比较快!
题目描述: 用链表实现栈这种数据结构
#include "stdio.h"
#include <stdlib.h>
typedef struct linkStack{
int data;
struct lineStack *next;
}lineStack;
lineStack* push(lineStack *stack,int a)//进栈
{
lineStack* line=(lineStack *)malloc(sizeof(lineStack));
line->data=a;
line->next=stack;
stack=line;
return stack;
}
lineStack *pop(lineStack *stack)//入栈
{
if(stack)
{
lineStack *p=stack;
stack=stack->next;
printf("弹栈元素:%d",p->data);
if(stack)
{
printf("栈顶元素:%d\n",stack->data);
}
else{
printf("栈已空\n");
}
free(p);
}
else{
printf("栈内没有元素\n");
return stack;
}
}
int main()
{
lineStack *stack=NULL;
stack=push(stack,3);
stack=pop(stack);
return 0;
}
入栈采用头插法,出栈则是将头节点的第一个节点给出栈!
2021.01.20
题目描述:
自定义一个数组a[],判断这个数组是否是递增数组。如果是输出递增数组,如果不是递增数组就输出不是递增数组!
示例:
输入:
5
1 2 3 4 5
输出:
5
5 4 3 2 1
题目解析:
#include <stdio.h>
#include <string.h>
int judge_increse(int *p,int n)
{
if(n==1)
{
printf("this is a incresing array!\n");
}
else
{
if(p[n-1]>=p[n-2])
return judge_increse(p,n-1);
else
{
printf("this array is not a increasing array !\n");
return 0;
}
}
}
int main()
{
int i,a[5];
for(i=0;i<5;i++)
{
scanf("%d",&a[i]);
}
judge_increse(a,sizeof(a)/sizeof(int));
}
2020.01.21
CVTE一面3天后就接到了二面的电话,问了我二面的面试时间,我定在了这个周周六11点进行面试!结果快到11点的时候依旧没有接收到面试官的电话,心里想着面试官是不是把我给割了!然后就在11:04分面试官的电话过来了,通知了我mindlink的会议号。结果我输入会议号显示会议不存在,就非常的担心和害怕,想着怎么办?(内心当时想着的是我是不是把会议号记错了!)然后稍微等了20S左右在输入会议号就成功的进入了会议室,刚才应该是面试官还没有创建会议!
进入会议之后,看到,面试官是一个大叔型的中年男子,一开始问了一下我是什么时候开学的,在学校上课是怎么上课的,简单的聊了一下放松一下(其实还是紧张)!然后来一句简单的做个自我介绍吧!做完自我介绍后就按照我的自我介绍问了一些问题,在学校的实验室主要干啥,怎么学习的。我就说大一大二基本上就是学习一些简单的知识,然后后来老师将给我们项目让我们做项目。然后面试官就问了项目的分工安排、怎么组织的、每周有没有一到两次会议什么的,然后就是碰见问题了怎么解决的。然后就是详细的问了项目干了啥,具体的自己做了啥,有没有遇见什么难题之类的,同时通过项目问一些项目相关的知识。后面就差不多问一些个人规划的问题,最后问你还有什么问题问我嘛!大概说了一会,然后就说面了差不多一小时了要结束了,我就很贱的问了一句二面不用写代码嘛?面试官就说我看你一面写代码了,二面就不用写代码了,还反问一句你想写代码嘛!我回答说如果能不写代码当然是最好啦!然后面试官说你有时间嘛,有的话咋就写一个代码!然后又花了20分钟左右写了一个代码,结果代码有点小问题!然后感觉面试官也要吃饭了说已经面了一个多小时了就结束吧!问题下去查查,然后我就找问题,找到问题以后把遇到了什么问题、怎么解决的通过短信的方式发送给了面试官。祈祷我CVTE二面都给通过,据说CSDN许愿很灵的哦!
最后简单总结一下二面吧!总体的面试体验还是很不错的,面试官也比较专业。从你的自我介绍还有项目经历来发散的问问题,基本上就是你说到哪里面试官就会问到哪里,是我们来引导面试官来问问题!所以如果一个项目中不熟悉的地方最好还是不要说和写在简历上面。最后把二面的问题总结如下:
- 问了学校的情况(社团、实验室啥的)
- 在学校怎么学习的,在平常有没有遇到什么棘手的问题,遇到了一些棘手的问题该怎么办
- 问了项目的人员分工、进度安排、每周几次会议、项目怎么发起的
- 然后就是问项目中主要干了啥,就比如我做的项目是一个智能语音交互的项目,把流程给说了一遍,然后用到了啥
- 由于用到了多线程相关的知识还有QT,所以就问了QThread、多线程和多进程相关的问题
- 同时是在Linux中进行操作的,就问了Linux中的内核空间和用户空间的区别,怎么学习Linux的
- 通过Linux我提到Uboot相关的知识,还提到了自己的博客,面试官就打开了我的博客网站,问了一下Uboot常用的命令
- 后面就是问一些个人规划,以后打算从事技术还是管理
- 怎么了解到CVTE的,以后想进什么样的企业
- 还有什么问题问我嘛?
- 写一个链表反转,然后问了函数中定义的变量和malloc申请的变量有什么区别,存放在哪里
2020.01.22
题目描述:
找出数组中重复的数字。在一个长度为n的数组里的所有数字都在0~n-1的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字2或者3.
题目解析:
解决这个问题的一个简单方法就是先把输入的数组排序,从排序的数组中再找出重复的数字。
#include<stdio.h>
//快速排序
void quick_sort(int s[], int l, int r)
{
if (l < r)
{
int i = l, j = r, x = s[l];
while (i < j)
{
while(i < j && s[j] >= x) //从右向左找第一个小于x的数
j--;
if(i < j)
s[i++] = s[j];
while(i < j && s[i] < x) // 从左向右找第一个大于等于x的数
i++;
if(i < j)
s[j--] = s[i];
}
s[i] = x;
quick_sort(s, l, i - 1); // 递归调用
quick_sort(s, i + 1, r);
}
}
int main()
{
int n,i,a[5];
for(i=0;i<5;i++)
{
scanf("%d",&a[i]);
}
quick_sort(a,0,4);
for(i=0;i<5;i++)
{
if(a[i]==a[i+1])
printf("%d \n",a[i]);
}
return 0;
}
2020.01.24
题目描述:
[二维数组中的查找] 在一个二维数组中,每一行都按照从左到右递增的顺序排序,没一列都按照从上到下递增顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否存在该整数。例如下面的二维数组就是每行、每列都是递增排序。如果在这个数组中查找数字7,则返回true;如果查找数字5,由于数组不含有该数字,则返回false。
1 2 8 9
2 4 9 12
4 7 10 13
6 8 11 15
题目解析:
首先选取右上角的数字9。由于9大于7并且9是第四列中最小的一列,因此要排除第四列这一列,然后分析剩下的3列,如图a所示。在剩下的矩形中,位于右上角的数字是8。同样8大于7因此排除第三列,然后分析剩下的两列。
在剩余的两列数组中,数字2位于数组的右上角。2小于7,那么要查找的数字可能在2的右边也可能在2的下边。但是由于2的右侧的两列都被剔除了,那么7只可能出现在2的下边,因此把第一行剔除,然后就只用分析(c)t图中剩余的三行两列数字,在剩余的数字中,数字4位于右上角,和前面的一样,把数字4所在的行也剔除,最后剩下两列数字,如图(d)所示剩余两行两列数字。
在剩余的4个数字中,位于右上角的刚好就是我们要查找的数子7,于是查找过程就可以结束了。
通过以上的查找过程,我们可以发现如下规律:首先选取数组中右上角的数字,如果该数字等于要查找的数字,则查找过程结束;如果数字大于要查找的数字,则剔除这个数字所在的列;如果该数字小于要查找的数字,则剔除这个数字所在的行。总结以下就是:如果要查找的数字不在数组的右上角,则每一次都在数组的查找范围中剔除一行或者一列,这样每一步都可以缩小查找范围,直到找到要查找的数字,后者查找范围为空。
#include<stdio.h>
int Find(int *arr,int rows,int cloumns,int aim)
{
if(arr!=NULL&&rows>0&&cloumns>0)
{
int row=0;
int cloumn=cloumns-1;
while(row<rows&&cloumn>=0)
if(arr[row*cloumns+cloumn]==aim)
{
printf("we have checked the number\n");
return 1;
}
else if(arr[row*cloumns+cloumn]>aim){
cloumn--;
}
else
{
row++;
}
}
printf("this array doesn't have the %d number !\n",aim);
return 0;
}
int main()
{
int arr[4][3]={1,2,3,4,5,6,7,8,9,10,11,12};
int num=0;
printf("please input the number :");
scanf("%d",&num);
Find(arr,4,3,num);
return 0;
}
2021.01.28
CVTE二面一周后终于等来了CVTE的综合面试的电话,打电话过来的是一个声音甜美的小姐姐,从普通话可以明显听到带有广州那边的音调,然后就预约了面试的时间,我预定在周六早晨的9:30啦!然后就通知我加一下她的QQ号,等待我记录下她的QQ号后就添加了,结果我看了一下QQ账号的年龄居然是4岁,学校写的是一个中学,我是不是加错好友了?我是不是加错好友了?不是加错好友了?然后立马将电话回拨回去,结果没有人接然后我就觉得自己与CVTE无缘了。
还好我添加了一个我们学校的在CVTE工作的学姐,我就叫欢欢姐了吧!把我遇到的情况给欢欢姐发了过去,然后欢欢姐说帮我看一下,说没有加错好友,然后说好友验证会在面试的时候通过的,这下我终于放心啦!然后又仔细观察一下那个QQ号我就觉得我很傻,怎么可能一个四岁的小朋友会有三个太阳这么高的等级呢!然后再看了一下地区是广州的这下我就放心了!
周六早晨起床洗漱完成后就坐在电脑前等待面试,9点的时候看小姐姐没有发任何消息,然后就等了一会还没有任何消息,再9:05的时候我就给小姐姐发了一个早上好,过一会小姐姐就回了消息。然后我说我已经准备好面试啦!过一会就收到了小姐姐打过来的视频电话!嘿嘿,内心还是非常激动的。然后就类似于平常聊天一样,说了什么小姐姐也会给及时的反馈,感觉并没有网上说的CVTE的HR面会比较难!接下来就简单总结一下面试中问的问题吧!
- 觉得前面两次面试表现怎么样
- 通过面试你有没有收获到什么
- 简单说说你的未来3年、5年、10年的个人规划
- 分享一下自己最喜欢的一本书和一部电影,为什么喜欢
- 说说你和这本书或者电影里的那个角色比较像
- 你还有什么问题要问我吗
大致问题就那么多,会针对你的回答再详细的询问,整体来说中规中矩。一开始居然没有让我做自我介绍,面试时间也不到半小时。我感觉我好像凉了难道是我之前的技术面试表现的不好觉得我没戏了就简单的问问?吓得我网上搜索了一下HR面的面经瞅瞅,有网友说可能是HR看了你前面的面试表现觉得你基本上已经稳进公司了,所以就简单的问问!嘿嘿,希望我是后面那种情况!
2.2中午在CVTE的官网上查询,发现通过了CVTE的综合面试,当天下午就接到了HR的电话通知我通过了所有的面试,说了公司实习生的实习补贴情况,以及福利,相关的实习问题。尽管知道我通过了CVTE的所有面试,也知道公司的实习工资等各种情况,但是接收到HR通知的电话就是感觉有种尘埃落定的感觉。这也是我第一次通过各种笔试面试拿到手的第一个offer,感觉通过笔试、面试可以明显的发现自己的不足查漏补缺。
2021.02.04
题目描述: 如果一个链表中包含环,如何出环的入口节点?例如,在如图所示的链表中,环中的入口节点是节点3。
题目解析: 解决这个问题的第一步是确定一个链表中是否有环,在之前的系列文章中有相关的解答,可以通过快慢指针解决这个问题!第二步是找到环的入口节点我们依旧可以通过两个指针来解决这个问题。先定义两个指针P1和P2指向链表的头节点如果链表中有n个节点,那就让P1先向前移动n个节点,然后两个指针以相同的速度向前移动。当第二个指针指向环的入口节点时,第一个指针已经围着环走了一圈了,由回到了入口节点。
剩下的问题就是如何得到环中的节点数目。我们前面在判断一个链表是否有环时当两个指针相遇时,还依旧在环中的某个节点。可以从这个节点出发,一边继续向前移动一边计数,当再次回到这个节点时就可以知道环中拥有几个节点啦!
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
typedef struct Node{
int data;
struct Node *next;
}node;
node* creat()
{
node *head,*q,*p;
head=(node*)malloc(sizeof(node));
q=head;
int a;
do{
scanf("%d",&a);
p=(node*)malloc(sizeof(node));
p->data=a;
q->next=p;
q=p;
}while(getchar()!='\n');
q->next=head->next->next;
return head;
}
node *judege_cycle(node *head)
{
node *slow,*fast;
slow=head,fast=head;
if(slow->next==NULL)
{
printf("just have one node!\n");
return 0;
}
while(slow&&fast)
{
if(fast->next==NULL)
{
printf("this is not a cycle!\n");
return NULL;
}
slow=slow->next;
fast=fast->next->next;
if(slow==fast)
{
printf("this's list have a cycle!\n");
return fast;
}
}
}
int testLink(node *head)
{
node *t1 = head, *t2 = head;
while(t1->next && t2->next)
{
t1 = t1->next;
if (NULL == (t2 = t2->next->next))
return 0; //无环
if (t1 == t2)
return 1;
}
return 0;
}
node *entry_node(node *phead)
{
node *meetnode=judege_cycle(phead);
if(meetnode==NULL)
return NULL;
int m_cyclenode=1;
node *node_temp=meetnode;
while(node_temp->next!=meetnode)
{
m_cyclenode++;
node_temp=node_temp->next;
}
node_temp=phead;
for(int i=0;i<m_cyclenode;i++)
{
node_temp=node_temp->next;
}
node *entry=phead;
while(entry!=node_temp)
{
node_temp=node_temp->next;
entry=entry->next;
}
return entry;
}
void reverse(node* head)
{
node *p,*q;
p=head->next;
head->next=NULL;//创建一个新的链表
while(p)
{
q=p;
p=p->next;
q->next=head->next;
head->next=q;
}
}
void print(node* a)
{
a=a->next;
while(a!=NULL)
{
printf("%d ",a->data);
a=a->next;
}
}
int main()
{
node *a,*b;
a=creat();
//printf("this is output:\n");
//print(a);
//printf("after reverse:\n");
//reverse(a);
//print(a);
b=entry_node(a);
printf("%d\n",b->data);
return 0;
}
2021.02.07
题目描述:
计算字符串最后一个单词的长度,单词以空格隔开。
输入描述:
输入一行,代表要计算的字符串,非空,长度小于5000。
输出描述:
输出一个整数,表示输入字符串最后一个单词的长度。
示例:
输入
hello nowcoder
输出
8
题目解析:
这道题目我的方法比较简单,就是申请一个数组a[101],通过这个数组的值a[i]来记录第i+1个单词的值。那么问题就转换为确定第几个单词和怎么确定单词个数的方法了!可以通过空格来确定是第几个单词,当确定为第i个单词后,每遍历一个字母a[i]自加1,直到下一个空格结束。
#include<string.h>
int main()
{
char str1[101];
gets(str1);
int len,i,word=0;
int a[101]={0};
len=strlen(str1);
//printf("len:%d\n",len);
for(i=0;i<len;i++)
{
a[word]++;
if(str1[i]==' ')
{
word++;
}
//printf("str[%d]:%c,%d\n",i,str1[i],a[word]);
}
//printf("the world number is:%d\n",word);
printf("%d\n",a[word]);
}
在测试本程序时发现了一些问题,原因是由于平时没注重代码编写规范造成的结果!在自己的本地编译运行之后发现测试样例可以通过,但是在使用牛客的在线编译器clang时发现当只输入一个单词时的测试样例不能通过,死活想不明白为什么,通过printf在线调试发现数组a[i]由于没有初始化,所以里面放的值是未知的从而导致了输出是一个无法确定的值。通过这道题目让我明白了代码规范的重要性,数组一定要初始化,不然可能会造成无法预估的后果。
在没有找到原因的时候,发到了实验室的我们组的小群里,经过讨论,发现小学弟的解法也非常的不错,这里也给大家分享出来!就是通过strlen得到字符串的长度,然后倒序遍历,遇见第一个空格后说明这个空格后面就是这个最后一个单词的首字母!然后用字符串的长度-该字母的下边-1就得到了最后一个单词的长度。
#include<stdio.h>
#include<string.h>
int main()
{
char str[101];
gets(str);
int len,i;
len =strlen(str);
for(i=len-1;i>=0;i--){
if(str[i]==' ')
{
printf("%d\n",len-i-1);
break;
}
else if(i==0){
printf("%d\n",len);
break;
}
}
return 0;
}
在clang11以后就没有gets了,编译会出现警告!可以通过fgets来过去从键盘的输入信息。所以gets(str)
就可以换成fgets(str,sizeof(str),stdin)
。
我把这个题目发到了一个嵌入式技术交流群里供大家讨论,最终在一位技术很牛逼的老哥下又对代码进行了优化!最终优化结果如下:
#include<stdio.h>
#include<string.h>
int main()
{
char str[101];
fgets(str,sizeof(str),stdin);
int len,i,count=0;
len=strlen(str);
for(i=0;i<len-1;i++){
++count;
if(str[i]==' '){
count=0;
}
}
printf("%d\n",count);
return 0;
}
小伙伴们能看出来优化了哪里嘛!如果本题目有更好的解法欢迎评论和留言哦!
题目描述:
给定n个字符串,请对n个字符串按照字典序排列。
输入描述:
输入第一行为一个正整数n(1≤n≤1000),下面n行为n个字符串(字符串长度≤100),字符串中只含有大小写字母。
输出描述:
数据输出n行,输出结果为按照字典序排列的字符串。
示例:
输入
9
cap
to
cat
card
two
too
up
boat
boot
输出
boat
boot
cap
card
cat
to
too
two
up
题目解析:
拿到题目的时候我是没有什么思路的,用排序?用什么?怎么解决?一头雾水!当看到网友的解法以后还是一脸懵逼,为啥用strcmp就可以比较两个字符串的大小?然后就去查看了一下strcmp的源代码:
int strcmp(const char *dest, const char *source)
{
assert((NULL != dest) && (NULL != source));
while (*dest && *source && (*dest == *source))
{
dest ++;
source ++;
}
return *dest - *source;
/*如果dest > source,则返回值大于0,如果dest = source,则返回值等于0,如果dest < source ,则返回值小于0。*/
}
- ①字符串1小于字符串2,strcmp函数返回一个负值;
- ②字符串1等于字符串2,strcmp函数返回零;
- ③字符串1大于字符串2,strcmp函数返回一个正值;
因此可以比较容易的写以下代码:
#include <stdio.h>
#include <string.h>
int main()
{
int n;
scanf("%d",&n);
char str[n][1000];
char a[100];
for(int i=0;i<n;i++)
{
scanf("%s",str[i]);
}
for(int i=0;i<n;i++)
{
for(int j=0;j<n-1-i;j++)
{
if(strcmp(str[j],str[j+1])>0)
{
strcpy(a,str[j+1]);
strcpy(str[j+1],str[j]);
strcpy(str[j],a);
}
}
}
for(int i=0;i<n;i++)
{
printf("%s\n",str[i]);
}
}
不积小流无以成江河,不积跬步无以至千里。而我想要成为万里羊,就必须坚持学习来获取更多知识,用知识来改变命运,用博客见证成长,用行动证明我在努力。
如果我的博客对你有帮助、如果你喜欢我的博客内容,记得“点赞” “评论” “收藏”一键三连哦!听说点赞的人运气不会太差,每一天都会元气满满呦!如果实在要白嫖的话,那祝你开心每一天,欢迎常来我博客看看。