一、简历注意事项:
简短、客观、不过分自谦、写明职位、无语法错误、简洁直白、不注水不意味着将所有弱项都写进去。
二、程序员笔试内容:
C++、数据结构、数据库、设计模式、网络、智力测验,要注意C++中指针,继承多态等问题。
要习惯手写程序。
三、电话面试:
自信、礼貌、认真、严肃。外企电面一般不会涉及过多技术,要准备自我介绍。
四、面试:
守时,掌控谈话方向,保持目光接触,允许沉默用来思考。
Tips:日程本记录,总结。
五、职业生涯:
初试要点是基本功扎实,自信乐观,英语交流能力不错,够聪明,机灵。
整体形势与个人形势没有必然联系。8/2原则。
需要复习的基础课程:数据结构,C/C++,TCP/IP,操作系统,计算机网络,UML,OOA&OOP,自己做过的项目等。
频繁跳槽对职业生涯无益!
六、程序设计基本功:
&是按位与,&&是与。
::是全局符号。
逗号表达式,x?y:z;x为真执行y,否则z.
执行效率:x++优于x+=1优于x=x+1.原因是元操作的减少。
与运算一旦发现有假马上不算。
比较相等时候把常数放前面好,可以检查错误。防止“==”变“=”。
循环中操作越少,效率更优。一般与循环变量无关的都移除。
类型转换:最宽数据类型为目标类型,赋值时候目标类型为被赋值对象类型,传递函数参数时候目标类型为形式参数类型,函数返回值目标类型为函数类型。
不用判断语句找出两者之大者:int max=(a+b+abs(a-b))/2。画两根长短不一的棍棍立刻明白。小者也是同样:int min=(a+b-abs(a-b))/2。
不用中间变量进行两者值交换:a=a^b;b=a^b;a=a^b;原理见P36。
C++提供了C连接交换符号extern “C”解决名字匹配问题,因为同样函数被C和C++编译后名字不一样。C++支持重载。
包含头文件时候用<>表示从标准库路径开始搜索,“”表示从用户工作路径开始搜索。
C++编译加了定义:_cplusplus。C编译加了_STDC_。
要在main()函数退出后执行,需要用atexit()函数,如atexit(void (* function)(void))。
预处理命令#define:#define SECONDS_PER_YEAR (365*25*60*60)UL.1、无分号;2、大写;3、UL!防止溢出。
宏定义:一定小心把参数括起来。
const的作用:1、定义const常量;2、修饰函数定义,返回值;3、定义类中某个成员函数为恒态函数,不改变类中的数据成员。
const比#define好的地方:1、const有类型,宏定义没有,不进行检查。2、部分调试工具不可对宏定义调试。C++中const可以完全代替宏定义。
sizeof:指针都是4位,数组按照实际占用来计算。而结构体一定是最长元素的倍数,不足自动补齐。空类也要占1位,有元素就将元素相加,结构体与其相同。类的对象与类相同。类中的静态变量放在全局数据区中,所以sizeof时候不计其内。float4位,double8位。
sizeof和strlen区别:sizeof给出容量,占用内存的大小。而strlen给出字符串长度,循环计算直到碰到”\0″,不能用strlen计算非字符数组的长度。sizeof是算符,strlen是函数。sizeof可以用类型和函数做参数,strlen只能用char*做参数,且必须是以”\0″结尾的。sizeof后如是是类型一定要加括号,如果是变量名则不需要。
注意:数组作为参数传递给函数的时候传递的是指针而非数组本身,在函数内无法获得数组的长度,要利用长度,需要另用参数传递进去,然后用memcpy函数将数组拷贝出来。
空类占用空间为1,多重继承的空类占用空间还是1,但是虚继承涉及到虚指针,因此为4.
内联函数在编译的时候直接镶嵌到目标代码中,而宏只是在代码处不加验证的简单替换,内联函数要做参数类型检查,这个比宏高明的地方。当然,要以牺牲空间为代价。inline函数一般在满足如下两个条件时候使用:一个函数不断被重复调用;函数只有短短几行,不包含for,while,switch等语句。
七、指针与引用
指针和引用的区别:
1、非空区别,引用不可以指向空值,而指针允许在某些时候不指向任何值。引用效率比指针要高。
2、合法性测试,使用引用之前不需要测试其合法性,而指针总是被测试。
3、可修改区别,指针可以重新赋值,而引用只在初始化被赋值,而后不容改变。
声明引用时候必须同时初始化,不可以空着,如int &reiv是错误的。
给一个不知道指向何方的指针赋值是错误的,如int *pi;*pi=5;.
常量必须在定义时候初始化:const double di=5;,否则错误。
关于this指针:
1、this只能在成员函数中使用,全局函数、静态函数都不能使用this.事实上成员函数的第一个参数为T*const this.
2、this在成员函数的开始前构造,在成员的结束后清除。
在C++中,类和结构只有一个区别:类的成员默认是private,结构默认是public.
要在一个函数中申请内存,需要使用返回值或者使用指向指针的指针,如:
char * GetMemory(char *p,int num)
{
p=(char *)molloc(sizeof(char)*num);
return p;
}
使用str=GetMemory(str,100);调用.
void GetMemory(char **p,int num)
{
*p=(char*)molloc(sizeof(char)*num);
}
调用时候使用Getmemory(&str,100);
函数指针:void (*f)() 注意一定要有括号,int *p=&max是不可以的。而要int (*p)(int,int)=&max.
函数返回指针:void * f()
const指针:const int*
指向const的指针:int * const
指向const的const指针:const int * const
几个拗口的指针:int *a[10]; //一个有10个指针的数组,该指针是指向一个整型数的。
int (*a)[10]; //一个指向有10个整型数数组的指针。
int (*a[10])(int); //一个有是个指针的数组,这个数组的指针指向一个函数,该函数有一个整型参数并且返回一个整型数。
malloc/free是C/C++语言的标准库函数,而new/delete是C++的运算符。
句柄和指针的区别:句柄是指针的指针,句柄地址(稳定)->记载着对象在内存中的地址->对象在内存中的地址(不稳定)->实际对象。它是一个32bit的uint,而指针是标记某个物理内存地址,两者不同。
八、循环、递归与概率
打靶问题:共打十次,问打中90环的可能性。
分析:很容易想到的是穷举法,需要用到嵌套的循环来穷举所有可能,然后判断出符合条件的打印出来。
for (i1=0;i1<=10;i1++)
{
for (i2=0;i2<=10;i2++)
{
for (i3=0;i3<=10;i3++)
{
for (i10=0;i10<=10;i10++)
{
if(i1+i2+i3++i10=90)
Print();
}
}
}
}
但是这样做有两点不足:
1)如果题目改为连打1000枪,得分为900的可能性,估计这种写法的要哭了
2)考虑不周全,如果第一次打靶得分为0,还有9次机会,这9次机会,就要求枪枪都是满分,如果第二枪,得分不是10,那第三枪不用打就知道可能没有可能性了。就比如乒乓球比赛一样,5局3胜制,如果进行了3局都是一个人胜利的话,比赛这时候就可以宣告结束。而继续下去就是浪费时间和精力
2。采用第归的方法来解决上述问题
递归就是自己调自己,如果没有结束限制的话,递归的效果和dead loop是一样的,但是递归正常情况下都会有结束标志,而且递归的意义就在于完成循环层数不明确或者层数明确但是数值非常大的情形。使用它的注意点就是递归函数肯定要具有一个或者一个以上的形参,没有参数的递归就形成了死循环。而且递归中函数每次调用自己的时候,需要小心谨慎的控制参数。尽量防止死循环的 产生,递归和栈关系密切。
要实现上述功能,递归函数要完成的功能主要有:
1)当传入的当前打靶次数为小于1,或者大于规定次数的时候,应该退出递归函数的执行
2)当余下的打靶次数中每次都得满分,但能无法达到目标分数的时候,应该退出递归
3)如果没有上述两种情况,就应该执行第归
实现代码:
#include <iostream>
using namespace std;
int sum=0;
int store[10];
compute(int score,int num) //这里的score是表示要求打出的分数,而num是剩下的次数。
{
if (score<0||score>(num+1)*10) //即第一种停止条件:要求后面打出负分或者都打十分都不够。
return;
if(num==0) //第二种终止条件:打到最后一次了。
{
store[num]=score;
sum++;
return;
}
for(int i=0;i<=10;i++) 否则进行递归
{
store[num]=i;
compute(score-i,num-1);
}
}
int main()
{
compute(90,9);
cout<<“zongshu is:”<<sum<<endl;
}
程序结果 sum=92378
还有一种用到了类:
public class ShotScore
{
//总共有多少种可能性
int SumRate = 0;
//每次可能命中的几率范围
int[] ScoreArray;
//总共需要多少分
int totalScore=0;
//一共能打多少次
int totalShot=0;
//当前共打中环数
public ShotScore(int[] sa,int ts,int t)
{
this.ScoreArray = sa;
this.totalShot = ts;
this.totalScore = t;
}
public int GetSum()
{
return SumRate;
}
public void Compute(int currentShot,int cNum) //currentShot代表已经打过的次数。cNum代表环数。
{
//打多打少都不行
if(currentShot<0||currentShot>totalShot) //已经超出了
{
return;
}
//以后枪枪都中10都不能满足条件,game over
if(((totalShot-currentShot+1)*10)<(totalScore-cNum))
{
return;
}
//打够次数了并且总共达到了预期环数
if(currentShot==totalShot)
{
//这种可能性成立
SumRate++;
return;
}
for(int i=0;i<ScoreArray.Length;i++)
{
Compute(currentShot+1,cNum+ScoreArray[i]);
}
}
}
}
56最后结果为:92378
九皇后问题太复杂了,先没研究!
0-1背包问题
九、STL模板与容器暂时跳过。
十、面向对象
对于一个空类,编译器默认产生4个成员函数:默认构造函数、析构函数、拷贝构造函数和赋值函数。
类和结构体的区别是:类的变量默认是private的,而结构体默认是public的。
类的静态成员变量在一个类的所有实例间共享数据,如果想限制对静态成员变量的访问,应该声明城保护型或者私有型。不允许用静态成员变量存放某一个对象的数据。
常量必须在构造函数的初始化列表里面初始化或者将其设置成static。
析构函数可以是内联函数。
MFC将Cobject类的析构函数设置成呢个virtual的原因是因为这样的话它的派生类的析构函数都会自动变成virtual,这就保证了在任何情况下不会出现由于析构函数未被调用而导致的内存泄露。
何为虚调用?
虚函数需要维护一个V表?
字符串赋值:
If (str==NULL)
{
m_data=new char(1);
*m_data=’\0’;
}
Else
{
Int length=strlen(str);
M_data=new char(length+1);
Strcpy(m_data,str);
}
多态性可以简单概括为“一个接口,多种方法”,在程序运行过程中才决定调用的函数。
覆盖是指子类重新定义负累的虚函数的做法,而重载是指允许存在多个同名函数,而这些函数的参数表不同。重载的概念并不属于“面向对象编程”,重载的实现是:编译器根据函数不同的参数表,对同名函数的名称进行修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。重载与多态无关,真正和多态相关度的是“覆盖”,当子类重新定义了父类的虚函数后,父类指针根据赋给他的不同的子类指针,动态地调用属于子类的该函数,这样的函数调用是在编译期间无法确定的,因此,这样的函数地址是在运行期间绑定的(晚绑定),结论就是:重载只是一种语言特性,与多态无关,与面向对象也无关。
封装可以隐藏实现细节,使得代码模块化;继承可以扩展已经存在的代码模块;他们的母的都是代码重用,而多态则是为了实现另一个目的——接口重用!而实际上的情况往往是:要实现代码重用很难,而真正最有加之的重用是接口重用。多态的本质是将子类类型的指针赋值给负累类型的指针。
重载与覆盖是有本质区别的!
十一、继承与接口
虚函数会被子类覆盖,而普通函数不会,当出现Parent *p = new Son()时候,p指向的是父类。
私有继承使父类中所有元素无法与子类联系。
一个私有的或者保护的派生类不是子类,因为非公共的派生类不能做基类能做的事。
公有集成就像是三口之家的小孩,饱受父母的温暖,享有父母的一切(public和protected的成员),其中保护的成员不能被外界所享有,但可以为小孩所拥有,只是父母还有一点点隐私(private成员)不能为小孩所知道。
私有继承就像是离家出走的小孩,一个人在外面漂泊,不能拥有父母的住房和财产,在外面也不能代表父母,甚至他不算是父母的小孩,但是在他的身体李,流淌着父母的血液,在其自己的行为中有与其父母相似的成分。注意:虽然私有继承的类不可以使用父类的方法,但是可以在自己的行为中调用父母的方法。保护继承则不能在公共场合使用基类的成员。
三种继承方式:P135
公有继承时,派生类的对象可以访问基类的公有成员,派生类的成员函数可以访问基类中的公有成员和保护成员。
私有继承时,基类的成员只能由直接派生类类访问,无法在往下继承(因为已经转化为私有了)。
保护继承时,与私有继承相同,唯一不同是对于派生类的成员而言,都变成了保护类型。
保护继承和私有继承只是在技术上讨论时有一席之地。
虚继承?虚表?
虚继承是为了解决多重继承的问题的,比如B,C都继承于A,然后D继承于B和C,这样A就出现了两次,即所谓“菱形继承”,可以设置B和C虚继承于A来解决。
鸵鸟和鸟的问题:鸵鸟has some kind of鸟的特性,而不是a kind of鸟。因此继承时候可以将适合鸵鸟的函数挑选出来。重载一下。
注意:如果不指定继承方式,默认的是私有继承。
若是逻辑上A是B的一部分,则不允许B从A派生,而是要用A和其他东西组合出B,即在A中选用那些元素类的对象作为成员。P144
注意:子类的初始化要包含负累的初始化,如derived(int x,int y):base(x)
含有纯虚函数的类是不可以实例化一个对象的。所谓纯虚函数是指:virtual void Draw()=0这样的,改成vortual void Draw(){}就变成了普通虚函数,就可以实例化对象了。P146
虚指针或虚函数指针是一个虚函数的实现细节,带有虚函数的类中每一个对象都有一个虚指针指向该类的虚函数表。
COM是什么?
十二、位运算与嵌入式编程
#include <stdio.h>
int main()
{
printf(“%f\n”,5);
printf(“%d”,5.01);
}
居然第一个是0.000000,第二个是一个大数,出乎意料啊!
八进制转十进制:P153
书上是oct/10*8+oct%10;
这个显然只是适合两位的八进制数,而要扩展到任意位数,可以用:
Int r=1;
While(oct!=0)
{dec+=(oct%10)*r;
Oct/=10;
R*=8;
}
这里的思路是:首先从低位算起,然后幂升级,直到位数算完。
四种casting算符:完全不懂!
Static_cast数制转换
Dynamic_cast用于执行向下转换和在继承之间的转换。
Const_cast去掉const
Reinterpret_cast用于执行并不安全的implementation_dependent类型转换。
ISR(中断服务子程序)
1、 不能有返回值。
2、 不能传递参数。
3、 浮点一般是不可重入的。
4、 Printf一般也有重入和性能上的问题,因此一般也不可用。
Volatile的作用:
当一个对象的值可能会在编译器的控制或监测之外被改变时,例如一个被系统时钟更新的变量,那么该对象应该被声明成volatile。主要母的是提示编译器该对象的值可能在编译器未检测到的情况下被改变,因此编译器不能武断地对这些对象的代码做优化处理。
Static的作用:
在C语言中,static有三个明显的作用:
1、 在函数体内,一个被声明为静态的变量在这一函数被调用的过程中维持其值不变。
2、 在模块内(但在函数体外,)一个被声明为静态的变量可以被模块内所有函数访问,但不能被模块外其他函数访问。
3、 它是一个本地的全局变量,在模块内,一个被声明为静态的函数只可以被这一模块内的其他函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。
Const int *a :a是一个指向常整型数的指针(数不可以修改,但指针可以)
Int * const a: a是一个指向整型数的常指针(数可以修改,但指针不可以)
Int const* a const: a是一个指向常整型数的常指针(两者皆不可以修改)
访问一个绝对地址的方法是将绝对地址整型数强制转化为一个指针:
Int * ptr;
Ptr=(int *) 0x67a9;
*ptr=0xaa55;
#define dPS struct s*
Typedev struct s* tPS
两者相比后者更佳,因为当dPS p1,p2时,仅仅将第一个定义为指针,后者定为普通结构。
十三、数据结构基础
单链表
双链表
循环链表
以上操作分为:创建,测长,插入节点,删除节点,逆置,打印。相应算法要熟悉。
如何证明一个表是循环链表:
可以设置两个步长不等的游标,一个步长为1,一个步长为2,两个游标同时触发若能再次相遇则证明该表是循环链表。
Heap和stack的区别:P184
Heap是堆,stack是栈。Stack的空间由操作系统自动分配和释放,而heap的空间手动分配和释放。
Stack空间有限,而heap是很大的自由存储区。
C中的malloc函数分配的内存空间在堆上,而C++对应的是new操作符。
程序在编译期间对变量和函数分配内存都在栈上进行,而程序运行过程中函数调用时参数的传递也在栈上进行。
平衡二叉树是一棵空树或者具有下列特点的二叉树:它的左子树和右子树都是平衡二叉树,且左子树和右子树深度之差不超过1。
排序的稳定性:当待排记录的关键字存在相同记录,经过排序后这些关键字之间相对顺序不变的,称为是稳定的,如果发生了变化称为不稳定的。
若在排序过程中,整个文件都是放在内存中处理的,称之为内排序,若涉及到内外存的交换,称之为外部排序。
快速排序:
冒泡排序:
希尔排序:
对于已经接近有序的情况,冒泡是最快的。
哈希表是什么?
霍夫曼编码是什么?
十四、字符串
整数转化为字符串,可以采用加’0’,在逆序的办法,整数加’0’后隐形转化为char类型的数,反过来也是一样,要将字符串转化为整数,可以采用减’0’乘十然后累加的形式。P203
字符串拷贝函数:
Char *strcpy(char *strDest,const char* strSrc)
{
Assert((strDest!=NULL)&&(strSrc!=NULL));
Char *address=strDest;
While((*strDest++=*strSrc++)!=’\0’)
NULL;
Return address;
}
这里的返回值是为了实现链式表达式。
动态内存分配:
用到两个函数,一个是void *malloc(unsigned int size),这个函数分配size长度的连续空间,返回的是指向这个地址的指针,如果分配失败,返回NULL。分配的内存也需要释放,用到void free(void *p)函数,注意这里的指针p必须是先前用malloc分配时候返回的那个,否则将引起不可预料的结果。重要的是指针所指向的地址,而非指针本身!
Strcpy()和memcpy()的区别:前者是拷贝字符串的,遇到\0则删去该字符,结束拷贝。而memcpy可以拷贝任意类型的数据,需要执行要拷贝的字节数。
通常在拷贝字符串时候用strcpy()函数,而拷贝其他的用memcpy()函数。
自己写memcpy函数也是跟strcpy()差不多:
Void * memcpy2(char *pvTo,char *pvFrom,size t_size)
{
Assert((pvTo!=NULL)&&(pvForm!=NULL));
Char *pbTo=pvTo;
Char *pbFrom=pvFrom;
While(size>0)
*pbTo++=*pbFrom++;
Return pvTo;
}
字符数组并不要求最后一个字符为’\0’,是否需要加入’\0’,完全由系统需要决定,但是字符数组的初始化要求最后一个字符必须为’\0’,否则会出错,因此,插入char c[5]={‘C’,’h’,i’,’n’,’a’}
不允许建立空数组,int a[]是错误的。
字符串操作部分是比较有难度的,要多看几遍。
十五、设计模式(跳过)
十六、操作系统
进程和线程的差别
进程是程序的一次执行。
线程可以理解为进程执行的一段程序片段。
进程是独立的,这表现在内存空间、上下文环境上;线程运行在进程空间中。
一般而言,进程无法突破进程边界存取其他进程内的存储空间,而线程由于出于进程空间中,所以统一进程所产生的线程共享统一内存空间。
统一进程中的两段代码不能够同时执行,除非引入线程。
线程是属于进程的。
进程间通信的方式:信号,信号量,消息队列,共享内存。
Windows中互斥器mutex可以用于进程之间互斥,临界区critical section用于线程之间的互斥。
进程进入等待状态的方式:1、CPU调度给了优先级更高的线程,原来的线程就进入等待状态。2、阻塞的Thread获得资源或信号,进入等待状态。3、在时间片轮转的情况下,如果时间片到了,也进入等待状态。
垃圾回收(内存管理)问题?
操作系统中的缓存是快表——用来存放当前访问最频繁的少数活动页面的页号。
CPU中的缓存——高速缓冲存储器——介于CPU和内存之间。
十七、数据库与SQL语言
数据库范式:
1NF:每一个值都是不可分解的。
2NF:第一范式的基础上,如果R中每一个非主属性完全函数依赖于R中的某个候选键。
3NF:第二范式的基础上,每个非主属性不传递依赖于某个候选键。
BCNF:第一范式的基础上,每个属性都不传递依赖于R的候选键
4NF:D是R上的多值依赖集合,如果D中成立非平凡多值依赖X->->Y时,X必是R的超键,那么称R是第四范式的模式。
存储过程与函数的区别:
存储过程是一系列SQL语句的集合,涉及特定表或者对象的任务,函数不涉及特定用户表。
事务是什么?ACID?p274
SQL注入性攻击?
SQL查询语句:
找出表ppp中num最小的数,不用min
Select * from ppp where num<=all(select num from num)
或者:
Select top 1 num from ppp order by num
找出表中最小的数,可以用min
Select * from ppp where num=(select min(num) from ppp)
选出ppp中num重复的记录
Select * from ppp
Where num in (select num from ppp group by num having(count(num)>1))
十八、计算机网络及分布式系统
OSI模型中,物理层的作用是透明的传输比特流。
对等实体在一次交互作用中传送的信息单位称为协议数据单元,包括控制信息和用户信息两部分。
七层:物理层,数据链路层,网络层,传输层,会话层,表示层,应用层。
物理层设计到在信道上传输的原始比特流。
数据链路层主要任务是加强物理层传输原始比特流的功能,封装成帧。
网络层关系到子网的运行控制,其中一个关键问题就是确认从源端到目的端如何选择路由。
传输层的基本功能是从会话层接收数据而且将其分成较小单元传递给网络层。
会话层允许不同的及其的用户建立会话关系。
表示层用来完成某些特定的功能。
应用层包含着大量人们普遍需要的协议。
交换和路由的区别?P287
让主网分成两个网段,子网掩码分别是0xff 0xff 0x80 0x00和0xff 0xff 0x00 0x00
FTP是基于TCP协议的。
一个C类网络最多容纳254台主机。
SNMP?P292
没有细看!
十九、英语面试
May I coming?
Excuse me, Is this personel department?
Excuse me for interrupting you. I’m here for an interview as requested.
-Heavy traffic?
-Yes, it was heavy but since I came here yesterday as a rehearsal, I figured out a direct bus line from my school to your company, and of course, I left my school very early so it doesn’t matter to me.
Sorry, I beg your pardon.
Thank you sir!
Yes, As you mentioned just now….As far as I know…..As is shown in my resume…. As my previous experience shows…
-Can you sell yourself in two minutes?
-With my qualifications and experience, I fell I am hardworking, responsible and diligent in any project I undertake. Your organization could benefit from my analytical and interpersonal skills.
I will try to present my ideas in a more clear and civilized manner in order to get my points across.
I will stay as long as I can continue to learn and to grow in my field.
Perhaps, an opportunity at a management position would be exciting.
二十、电话面试
I was admitted by xxx university. My field of study is xxx which is a famous one in China. My undergraduate study gave me a wide range of vivison, I fulfilled the courses like English, Network and Programming, I have a deep understanding in Programming. I developed several professional interests, like Histrory and microeconomics at my spare time. The several years working experiece give me full play to my creativity, diligence and interlligence , I believe I can do my job well.
Idea job :P326
END