记第一次面试,面的CTVE嵌入式应用开发岗位,之前一直没有给面试通知,上课到半突然来了一个广州的电话一开始以为是骚扰电话没接,挂了之后又打过来觉得有些不对劲,匆匆忙忙跑出教室接了电话,便收到通知问我下午有没有空面试。于是下午就开始面试了
一开始因为没有经验略显尴尬,简单的做了一下自我介绍,因为第一次面试自我介绍也说得卡卡壳壳不流畅,看到牛客面试网站旁边有上传文件的功能,就把个人简历上传了给面试官看,简单的介绍了一下做的项目之后,面试官就开始就着我的简历问问题,后来问的问题基本上都是根据简历来问的
上面部分是我简历上面写的,这些东西都用过但是都没深入的去了解过,问些浅的还能回答出来,再问深一点就回答不上来了。面试官问的问题问深一点我也只能尴尬的说不太了解带过了...
具体问的问题大概如下:
1.(1)makefile语法规则是什么,(2)如果修改了文件,输入make会更新文件吗(3)makefile问怎么进入下一个文件夹
2.git用法 除了git外还知道什么版本控制
3.c语言中几个关键字的作用,如const和static作用 static函数是什么.
4.sizeof和strlen的区别,sizeof是一个函数吗
5.对进程和线程了解多少,线程间的通信
6.对操作系统有没有了解,死锁怎么产生
7.自己做过觉得最满意的项目,用了哪些知识
8.写一道十进制的整数转进制的题
9.对公司的了解
回去总结了一下这些问题的回答:
1.Makefile目标加上依赖,第一条目标为总的目标,依赖可以是文件(目录)或为其他目标,命令或动作可以是Linux命令但那一行必须以TAB键开头。伪目标没有依赖文件的目标,只会执行命令。make会在当前目录下找名字叫”Makefile”或”makefile”的文件。如果找到,它会找文件中的第一个目标文件(target)并把这个文件作为最终的目标文件。根据时间戳生成目标文件。递归去寻找目标文件依赖文件,并且递归生成(同样有时间戳问题)。(2)makefile会存在时间戳的问题,只要目标文件比依赖文件(源文件)新,那么就不会重新编译。(3)makefile嵌套:-C dir 读入指定目录下面的makefile,-f file 读入当前目录下的file文件为makefile
2.git colone, git add然后git commit -m”提交信息”提交新的代码给git管理 恢复:git checkout.从本地硬盘掩藏的.git文件夹中检出代码,git log查看每次提交的版本号,git reset --hard (版本号)就可以实现版本回退;除此之外还有svn(之后他还问知道怎么用吗....我觉得现在很少用SVN了吧,这里也不去做了解了)
3.static作用于变量时,变量地址存储在数据段中,初始化过的静态变量位于.data区未初始化的静态变量位于.bss区,编译时就为变量分配内存,直到程序退出才释放存储单元。这样,使得该局部变量有记忆功能,可以记忆上次的数据,不过由于仍是局部变量,因而只能在代码块内部使用。用static声明全局变量时,编译时分配内存,程序结束时释放内存单元。同时其作用域很广,整个文件都有效甚至别的文件也能引用它。static作用于函数时,使得函数只在本文件内部有效,对其他文件是不可见的。这样的函数又叫作静态函数。使用静态函数的好处是,不用担心与其他文件的同名函数产生干扰。const作用: 只读,修饰变量时,定义的变量只能读取不能更改,且只能在定义时初始化。定义指针时:
const int * p; //指向整形常量 的指针,它指向的值不能修改
int * const p; //指向整形的常量指针 ,它不能在指向别的变量,但指向(变量)的值可以修改。
const int *const p; //指向整形常量 的常量指针 。它既不能再指向别的常量,指向的值也不能修改。
4.sizeof()是运算符,其值在编译时即计算好了,因此sizeof不能用来返回动态分配的内存空间的大小,strlen()是函数,作用是返回字符串的长度,碰到/0就会返回。
5.(1)多进程,子进程从父进程中继承了进程的资格(真实(real)/有效(effective)/已保存(saved)用户号(UIDs)和组号(GIDs))、环境(environment)变量、堆栈、内存、打开文件的描述符,采用copy-on-write写时复制,即再数据更改之后,再进行拷贝。具体实现:当子进程创建的时候,子进程的正文段,数据段,堆,栈都只有虚拟地址指向父进程的物理地址。即开始并不为子进程分配物理空间。当数据改变之后,子进程会先开辟自己的物理空间,将父进程的数据拷贝一份到自己的物理空间。注意:当改变数据之后其值会改变,但是其虚拟地址没改变。父子进程的虚拟地址都一样。
(2)多线程:所有的线程都是在同一进程空间运行,这也意味着多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。但是线程会存在对临界区资源的访问问题,这就需要互斥锁。
(3)线程间通信:1.信号,用 pthread_kill 对线程发信号或设置信号singal。
2.互斥锁
int pthread_mutex_lock(pthread_mutex_t* mutex); //上锁;
int pthread_mutex_trylock(pthread_mutex_t* mutex); //只有在互斥被锁住的情况下才阻塞
int pthread_mutex_unlock (pthread_mutex_t* mutex); //解锁
int pthread_mutex_destroy (pthread_mutex_t* mutex); //清除互斥锁
3.条件变量、4.信号量等
6.操作系统五大功能:1、处理机管理:主要控制和管理CPU的工作。2、存储管理:主要进行内存的分配和管理3、设备管理:主要管理基本的输入输出设备4、文件管理:负责对计算机文件的组织、存储、操作和保护等。5、进程管理:也称为作业管理,是指对计算机所进行的操作进行管理,三态:就绪态(只差时间片的到来)、等待态(除了时间片外还需要等待别的事件满足)、运行态,五态:创建态、就绪态、等待态、运行态和终止态。
死锁产生的4个必要条件:
1、互斥:某种资源一次只允许一个进程访问,即该资源一旦分配给某个进程,其他进程就不能再访问,直到该进程访问结束。
2、占有且等待:一个进程本身占有资源(一种或多种),同时还有资源未得到满足,正在等待其他进程释放该资源。
3、不可抢占:别人已经占有了某项资源,你不能因为自己也需要该资源,就去把别人的资源抢过来。
4、循环等待:存在一个进程链,使得每个进程都占有下一个进程所需的至少一种资源。
当以上四个条件均满足,必然会造成死锁,发生死锁的进程无法进行下去,它们所持有的资源也无法释放。这样会导致CPU的吞吐量下降。所以死锁情况是会浪费系统资源和影响计算机的使用性能的。那么,解决死锁问题就是相当有必要的了产生死锁需要四个条件,那么,只要这四个条件中至少有一个条件得不到满足,就不可能发生死锁了。由于互斥条件是非共享资源所必须的,不仅不能改变,还应加以保证,所以,主要是破坏产生死锁的其他三个条件。
a、破坏“占有且等待”条件
方法1:所有的进程在开始运行之前,必须一次性地申请其在整个运行过程中所需要的全部资源。
优点:简单易实施且安全。
缺点:因为某项资源不满足,进程无法启动,而其他已经满足了的资源也不会得到利用,严重降低了资源的利用率,造成资源浪费。使进程经常发生饥饿现象。
方法2:该方法是对第一种方法的改进,允许进程只获得运行初期需要的资源,便开始运行,在运行过程中逐步释放掉分配到的已经使用完毕的资源,然后再去请求新的资源。这样的话,资源的利用率会得到提高,也会减少进程的饥饿问题。
b、破坏“不可抢占”条件
当一个已经持有了一些资源的进程在提出新的资源请求没有得到满足时,它必须释放已经保持的所有资源,待以后需要使用的时候再重新申请。这就意味着进程已占有的资源会被短暂地释放或者说是被抢占了。该种方法实现起来比较复杂,且代价也比较大。释放已经保持的资源很有可能会导致进程之前的工作实效等,反复的申请和释放资源会导致进程的执行被无限的推迟,这不仅会延长进程的周转周期,还会影响系统的吞吐量。
c、破坏“循环等待”条件
可以通过定义资源类型的线性顺序来预防,可将每个资源编号,当一个进程占有编号为i的资源时,那么它下一次申请资源只能申请编号大于i的资源。
8.这里贴上一个大哥的博客里面有怎么实现转进制的问题:
(https://blog.csdn.net/Dian0dian0/article/details/89330972)
视频面对面敲给别人看还是有点紧张了,之前其实见过这题但是没好好看,就现场发挥了一下,因为也不能出去用别的编辑器,就只是在网上敲而已,大概写了一下思路,写的时候比较紧张一开始忘记倒序输出,面试官提醒了一下应该倒序输出,然后定义了个128大小的int型数组,倒序输出,或许是空间复杂度的问题,最后写完了他问你这里定义了一个128大小的数组来处理吗,他笑了一下就觉得自己做错了QAQ. ,笔试题做完最后问了一下对公司的了解面试就结束了......
写的时候思路大概还是对的,面试完之后,就复制下来改了几个逻辑判断,比如写的时候写了>10的情况下来改成>=10,下面还是贴上我的代码
/*********************************************************************************
* Copyright: (C) 2019 WuYujun<[email protected]>
* All rights reserved.
*
* Filename: cover.c
* Description: This file
*
* Version: 1.0.0(25/04/19)
* Author: WuYujun <[email protected]>
* ChangeLog: 1, Release initial version on "25/04/19 16:41:06"
*
********************************************************************************/
#include
#include
#include
int cover(int M,int N) ;
int main(int argc, char **argv) {
int M ,N ;
if(argc != 3)
{
printf("Usage:%s [M] [N]\n",argv[0]) ;
return 0 ;
}
M = atoi(argv[1]) ;
N = atoi(argv[2]) ;
printf("M=%d,N=%d\n",M,N) ;
cover(M,N) ;
}
int cover(int M,int N)
{
int i = 0,j ;
int num ;
int a[M] ;
if(N<2||N>16)
{
return 0 ;
}
if(N<10)
{
while(M!= 0)
{
num=M%N ;
M=M/N ;
a[i] = num ;
i++ ;
}
for(j=0;j=10)
{
while(M!=0)
{
num = M%N ;
M=M/N ;
a[i] = num ;
i++ ;
}
for(j=0;j=10)
{
printf("%c",a[i-j-1]-10+'A') ;
}
}
}
printf("\n") ;
}
上面是我整理的答案,可能还是不够好或不够完整,而且面试的时候主要是看自己的理解的程度和随机应变的能力,恩...面试官挺和蔼的,没开始前挺紧张面试交谈中慢慢就好了一些,自己答不上来的时候也还是挺尴尬的哈哈哈,总的来说还是自己太菜了,很多时候觉得自己理解但是真正让自己说出来的时候却说不出来,理解得不够透彻是一个原因,个人的表达能力我觉得也存在一些问题.....之后会好好加强自己这方面的锻炼,会做不算真本事,能理解透彻并能说给别人听教会别人才是真的大佬!经过这次教训积攒经验并提升自己~