笔试:
一天晚上在公司和小伙伴们一起做的,题目不难。一堆选择题,两道编程题。
选择题各种类型的都有,c++、Java基础、数学题、数据结构、机器学习算法。
编程题特别水,也不知道出题人拿这么两道题来是怎么想的。
第一道是斐波那契数列(小明上楼梯,可以迈一步,可以迈两步),这题还真是第一次编程被考,我还写了个递归的答案····而且最后还笔试还过了····
第二道,好吧,已经不记得了,是一道很常考的题。
面试:
面试还是要好好写一写,感觉京东这次是面试以来收获最大的吧。可能面试官看我第一题写的很费劲,觉得我需要充充电····
上来先让介绍了一下项目,领域和面试官不太相关,他也就是听了听,随便问了几个问题。
第一道题:
有一个很大的char数组,现在要求把其中每一个字符(8位),转化成两个16进制数。(每4位刚好可以用一个16进制数表示)
刚听到题我其实是比较蒙的,最不喜欢做char数组的题了,到处都是坑,后来面试官也和我说,这道题考的就是编程细节。
拿到题,我的思路是把char分成前后两部分(前4位和后4位),然后分别传入一个实现十进制到十六进制转换的函数。
然后就先写了这么两个函数
char * transform(const char* src,char* dst,int n)//主函数
{
}
char 10to16(char num)
{
}
面试官问了下主函数里的参数都是什么意思,问我为什么要传入目标数组了还把他返回了。
这个问题问的我也比较奇怪,之前看的实现字符串拼接、复制的函数不都这么要求的么。
我就和他说是为了函数嵌套调用,这样写的话,函数本身就可以作为参数传入其他函数了。
不过面试官之前好像对这个没有概念,一脸迷惑,这么一点东西我解释了好半天,最后他依旧表示没这个必要····
之后他又问我,你这里把目标数组当做参数了,这样好么,有什么问题。
我想了想,说因为函数的实现调用者并不清楚,很有可能开辟大小不正确的数字传进来,这样程序会有很多隐患。
面试官问,那怎么解决这个问题?
我说也可以只传入源数组,函数中自己开辟目标数组。
问:自己开辟的时候需要注意什么问题。
答:首先是数组的大小,这里明显应该是源数组的两倍大小。另外不应该使用数组,而应该使用char指针。
问:为什么不能用数组?
这个说白了就是不同数据类型生命周期的问题,数组的话会随栈一起被释放掉。
我之前竟然一直不知道有函数栈这个东西,所以只能说线程和栈是一一对应的,定义成数组的话线程结束数组便被释放了。
面试官就纠正我,这个和线程关系不大,这里是函数栈,还要注意别的么。
我没想到其他的就说没了。
面试官补充,函数内开辟数组,那么调用者可能会忘记释放这部分空间,或者错误的释放,这些都是隐患。那么怎么解决这个问题?
说实在的,他这问题问的也太多了,虽然都是些小问题,但是我已经被他问的有点蒙了。
一会他就提示,是不是可以使用其他的结构体。
我缓了缓说可以用string,string是动态的,不需要固定大小。
问:还有呢?string类型是如何释放的?程序退出之后是不是系统自动回收释放的?
这尼玛不是把答案都说了····
之后我便把第二个函数改成了返回string的一个新函数:
<pre name="code" class="cpp">string 10to16(char num)
{
string res;
while(num)
{
int tmp=num%16;
num/=16;
res=nums[tmp]+res;
}
return res;
}
这里nums是之前定义好的一个char数组‘1’,‘2’,······,’E‘,’F‘。
问:你清楚string的+运算符的原理么。
我犹豫了一下,面试官拿起笔就开始给我讲了。
str1+str2,先回开辟一块等于两个大小和的空间大小,然后分别将两块内容复制过来。
所以我想了想就把函数改成了这样:
string 10to16(char num)
{
string res(2);
int i=1;
while(num)
{
int tmp=num%16;
num/=16;
res[i]=nums[tmp];
i--;
}
return res;
}
说实话,后来反省,这次面试问题是很多的,我当时就是一味的按面试关说的做,自己很少思考。
这次的改动有什么意义?面试官看了也有些失望。
你在函数里是不需要重复开辟空间了,但是你把返回值拼起来呢?你应该在主函数里开辟一个大小为2n的string,直接在主函数中操作。
我:这种有重复操作的运算一般不都会实现一个函数封装起来么?
面试官:这里我们数据量比较大,你那样做反而不好。
······
第一题总算是完了,能打个40分就算不错了。