写在开头,首先面试要保持好良好的心态,不要过于自信,也不要过于自负。当面试官问问题时,要仔细听,如果不确定自己理解的意思是否符合面试官的想法,可以将自己的想法告知ta,问问可不可这样理解。如果问到一时间想不到答案的问题,可以谈谈自己的看法(千万不要说自己不会)。回答问题时,要清除的表达自己的答案。
好吧!这次的面试经过了1个小时,写一篇博客记录一下。希望能有第二次面试,得到一个进大厂的机会。人生之长,我在慢慢走!
最后,给看者一个建议:小伙子,不要怂,就是干!你都怂了,肯定不能发挥好,要自信,当然,不能过度自信,不然就是吹,就是自负了!
面试官:介绍一下你的开发经历。
我:大一使用C语言开发带有GUI界面2048游戏;大二使用Java开发过一个类似跑酷的游戏,在此期间也有过一个使用C#开发的项目;大三有过JavaWeb的开发;目前也有些项目在进行中。
面试官:2048那个游戏是怎么实现的(只记得大概意思了)
我:使用开源的Easy-X库函数实现的。
面试官:以下的代码有没有什么问题,如果有问题进行修改(代码如下)
void fun(){ char string[10]; char* str = "0123456789"; strcpy(string,str1); }
我:没有使用的错误,在输出方面存在问题。(要注意区别指针和数组的区别,我修改的代码如下)
#include <stdio.h> int main(){ char string[10]; char* str = "0123456789"; for(int i=0;I<10;i++){ string[i] = *(str + i); } printf("%s",string); return 0; }
面试官:指针和数组有什么区别。
我:(使用不多,先前学的也不大记得了)当时也就说了内存空间的使用问题。
具体参考如下:
1.指针变量用于保存数据的地址,数组用于直接保存数据(当然你可能见过,数组的每个元素是指针,不过,一组指针也是数据,它们各自的内容才是地址)。
2.访问方式:指针是间接访问,首先取得指针的内容作为地址,再去该地址访问数据;数组是直接访问,数组名即是地址。
3.指针通常用于动态数据;数组通常用于固定数目和类型的一组数据。
4.定义指针变量并不会带来内存分配,要自行分配内存并且将指针变量的内容改写为分配好的地址,通常用内存分配函数如malloc达到;定义数组会隐式分配内存。
5.对sizeof操作符的返回值影响,sizeof(指针)永远会返回平台指针大小,通常32位机返回4,64位返回8,而sizeof(数组名),则会返回数组的内存大小,这取决于数组包含多少个数据。
面试官:野指针是怎么出现的?会造成什么影响?如何避免?
我:指针用的不多,在实际开发中也不敢用,我说一说我的理解(.……记不大清了,说道了作用域,又扯了些数据交换)
具体参考如下:
野指针的产生有以下3种情况:
1、定义一个指针变量时没有初始化
2、动态开辟的内存空间在使用完后调用free函数释放掉这段内存空间,
3、对指针的操作已经超出了指针变量的作用域
使用野指针会产生的后果 ,这里分为3种情况:
1、指向不可访问的地址
危害:触发段错误。
2、指向一个可用的,但是没有明确意义的空间
危害:程序可以正确运行,但通常这种情况下,我们就会认为我们的程序是正确的没有问题的,然而事实上就是有问题存在,所以这样就掩盖了我们程序上的错误。
3、指向一个可用的,而且正在被使用的空间
危害:如果我们对这样一个指针进行解引用,对其所指向的空间内容进行了修改,但是实际上这块空间正在被使用,那么这个时候变量的内容突然被改变,当然就会对程序的运行产生影响,因为我们所使用的变量已经不是我们所想要使用的那个值了。通常这样的程序都会崩溃,或者数据被损坏。
何如何避免 :
1、定义一个指针变量时一定记得初始化
2、动态开辟的内存空间使用完free之后一定将对应的指针置为NULL
3、不要在函数中返回栈空间的指针和引用
4、注意在使用时对指针的合法性的判断
面试官:当有两个进程访问一块内容时会出现什么问题?怎么解决?(详细问法不大记得了,要问的是死锁的问题)
我:可能会出现死锁。当一个进程访问文件时,给当前被访问的文件加锁,在访问结束后再进行解锁,给其他进程访问该文件的权限。(答的不全面)
面试官:说一下TCP的三次握手和四次挥手
参加了三次面试都有问过,也算是个常见的问题。
具体参考如下:
三次握手过程理解
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
四次挥手过程理解
1)客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1,此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
2)服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
3)客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
4)服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
5)客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
6)服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。
博文推荐:
面试官,求你了别再问我TCP三次握手和四次挥手了(含面试题)
面试官:TCP和UDP有什么区别
我:在用户实际的使用过程中是感觉不到特别大的区别。在实际传输过程中TCP是可靠的连接,它要保证数据能够到达接收方,因此需要消耗一定的资源,而UDP仅仅只是发送数据,相比TCP的消耗要小一些(其他的忘记了说)
具体参考如下:
1.基于连接与无连接
2.TCP要求系统资源较多,UDP较少;
3.UDP程序结构较简单
4.流模式(TCP)与数据报模式(UDP);
5.TCP保证数据正确性,UDP可能丢包
6.TCP保证数据顺序,UDP不保证
博文参考:
面试官:一个视频通话需要什么连接
我:这需要基于用户使用量进行选择,如果用户数量少,可以优先考虑TCP;当使用量过高时,可以优先考虑UDP。综合来看应当将TCP和UDP结合使用。
面试官:SQL注入攻击是怎么引起的?有哪些具体的分类?
我:一般是由工程师没有严格控制用户输入的数据造成的,即工程师没有秉持“外部参数皆不可信的原则”。(具体的分类不记得了,就说具体的分类不大了解)
具体的参考如下:
SQL注入
SQL注入就是指Web应用程序对用户输入数据的合法性没有判断,前段传入后端的参数是攻击者可控的,并且参数带入数据库查询,攻击者可以通过构造不同的SQL语句来实现对数据库的任意操作。
SQL注入的分类
1、带内(In-band)SQLi,也叫经典SQLi
2、推测SQL注入(盲注)
3、带外SQLi
博文参考:
面试官:给定一个二叉树,找出路径上其和相等的任意两条路径
#include <stdio.h> struct TreeNode { struct TreeNode* left; struct TreeNode* right; int value; } int main(){ struct TreeNode* root = malloc(sizeof(struct TreeNode)); root->value = 1; struct TreeNode* left1 = malloc(sizeof(struct TreeNode)); left1->value = 2; left1->left = NULL; left1->right = NULL; struct TreeNode* right1 = malloc(sizeof(struct TreeNode)); right1->value = 3; right1->left = NULL; right1->right = NULL; root->left = left1; root->right = right1; return 0; }
我:这个编程可能会花一些时间,可以说一下我的想法吗(害,链表实在是接触不多,编程可能真的会好久)(面试官那边也同意了)。可以采用深度或广度优先遍历的方法对这棵树进行遍历。将数据存在结构体数组中(其他的数据结构也可以),结构体中包含一个链表存放路径,另外一个整形变量存放累加和。最后通过比较累加和,输出符合条件的两条路径。
面试官问道了许多有关算法的时间复杂度,一定要会计算。还有些开放性的问题,在这里就不一一阐述了。
还有一道编程,具体要求不记得了,代码如下:
//这是提交后的,自己也不知道对不对,看看就行 #include <iostream> using namespace std; struct Test { int a; }; int main() { Test a; fun(a); } void fun(Test a) { }
写在最后的话
机会遍地都是,但是能不能抓住,就要看你是否做好了准备了。
希望大家都能找到自己心仪的工作,如果通过努力进入了心仪的公司,也不要放松,学习就是逆水行舟,不进则退。
当大潮褪去,你才知道谁在裸泳。
你知道的越多,你不知道的越多,人才们的 【三连】 就是我创作的最大动力,我们下期见!
注:如果本篇博客有任何错误和建议,欢迎人才们留言,你快说句话啊!