您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 招聘面试 > 程序员面试宝典知识点总结
程序员面试宝典知识点总结【预处理、const与sizeof】1.BNF范式常用的三种语法描述符号是:[]表示[]中的内容可以缺省,也就是[]中的内容可以不写出来;{}表示{}中的内容可以重复有限次,而{}n表示固定重复n次;|表示或者。2.编译预处理指令就是在源程序编译之前,由编译程序处理的指令。如:#include“math.h”,#definePI3.14注意:宏不能以“;”结束;宏中应把参数用括号括起来。3.#include“”,#include,使用””时,编译程序在系统当前目录与C语言系统指定的INCLUDE目录中查找包含文件,使用时,编译程序仅在TC指定的INCLUDE目录中查找包含文件。4.#ifdef宏名字(#ifndef)源程序1#else源程序2#endif在大型软件开发过程中,用户自定义头文件可能会无意识地被直接或间接地重复包含,使用条件编译指令可以有效解决上述问题。5.C语言的整型根据存储长度分为8bit,16bit,32bit,根据存储格式可分为无符号整数和有符号整数。Int16bit(-32768~+32767),unsignedint16bit(0~65535),float32bit,char8bit(-128~+127),unsignedchar8bit(0~255)。6.整型常量+L占8字节;无后缀字母的实数位double型,占用8字节存储;有后缀字母F的实数为float型,占4字节存储;char占1个字节;7.const的用法主要有定义常量、修饰函数参数、修饰函数返回值、函数的定义体等用处。被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。8.const常量有数据类型,而#define定义的常量没有数据类型,编译器可以对const进行类型安全检查,而宏定义只进行字符替换,没有类型安全检查,并且在字符替换中可能产生意料不到的错误;有些集成化的调试工具可以对const常量进行调试,但不能对宏常量进行调试。9.内联函数和普通函数相比可以加快程序运行的速度,因为不需要中断调用,在编译的时候内联函数可以直接被镶嵌到目标代码中,而宏只是一个简单的替换。内联函数要做参数类型检查。10.在C++程序中,类里面的数据成员加上mutable后,修饰为const的成员函数就可以修改它了。11.exp(x)计算ex;log10(x)计算lg(x);pow(x,y)计算xy;ceil(x)求大于或等于x的最小整数;floor(x)求小于或等于x的最大整数。12.后置形式运算规则是先用变量原来的值参与表达式运算,然后对含有后置自加自减运算符的变量进行加减运算。13.C中printf计算参数时是从右到左压栈的。14.C++语言支持函数重载,C语言不支持,C++提供了C连接符号extern“C”解决名字匹配问题。15.指针的大小是一个定值,就是4个字节;对于最初未定大小的数组来说,具体大小由具体的填充值决定,注意要加上隐含的”\0”;结构体的长度是最长的数据元素的整数倍;静态变量时存放在全局数据区的,而sizeof计算栈中分配的大小,故计算时不算在内;空类所占空间为1,单一继承和多重继承的空类空间还是1,但虚继承涉及到虚表(虚指针),其占用空间为4;【指针及引用】1.不允许用一个整型常量表达式直接向指针变量赋初值;C语言允许用一个字符串常量初始化一个char*型的指针变量。2.局部数组时局部变量,它所对应的是内存中的栈,全局数组时全局变量,它所对应的是内存中的全局区域。3.指针和引用的区别:(1)非空区别。在任何情况下都不能使用指向空值的引用。一个引用必须总是指向某些对象。使用引用的代码效率比使用指针要高;(2)合法性区别。在使用引用之前不需要测试它的合法性,相反,指针则应该总是被测试,防止其为空;(3)可修改区别。指针可以被重新赋值以指向另一个不同的对象,但引用则总是指向在初始化时被指定的对象,以后不能改变,但是指定的对象的内容可以改变;(4)应用区别。总的来说,在以下情况下应该使用指针:一是考虑到存在不指向任何对象的可能,二是需要能够在不同的时间指向不同的对象。如果总是指向一个对象并且一旦指向一个对象后就不会改变指向,那么使用引用。4.句柄和指针式两个截然不同的概念。Windows系统用句柄标记系统资源,用句柄隐藏系统的信息,是个32bit的uint。指针则标记某个物理内存地址。5.智能指针是存储指向动态分配(堆)对象指针的类。指针使用时有一些要注意的地方:有new就要有delete,对COM指针,要AddRef和Release,即这些动作要成对的出现,而往往大家会在这方面犯错误,应运而生的智能指针就是为了解决这个问题。首先把指针变量作为成员变量封装起来,在只能指针类对象离开作用域时,就会在析构的过程完成指针的释放。此外,智能指针类重载了如”&””*”之类的运算符,所以,用起来感觉和用一般指针一样。不过,使用智能指针类会使开销增大,还会因为太多行为是隐式调用反而造成混乱。智能指针带来的最好好处是安全。6.float(**def)[10]:def是一个二级指针,它指向的是一个一维数组的指针,数组的元素都是float;double*(*gh)[10]:gh是一个指针,它指向一个一维数组,数组的元素都是double*;double(*f[10])():f是一个数组,f有10个元素,元素都是函数的指针,指向的函数类型是没有参数且返回double的函数;Int*((*b)[10]):b是一维数组的指针;Long(*fun)(int):函数指针;Int(*(F)(int,int))(int):F是一个函数指针,指向的函数的类型是有两个int参数并且返回一个函数指针的函数,返回的函数指针指向有一个int参数且返回int的函数。【循环、递归与概率】1.设a、b的最大公约数为gcd(a,b),则a、b的最小公倍数lcm(a,b)=(a*b)/gcd(a,b)。根据求最大公约数的欧几里德辗转相除法,while(b!=0){t=a%b;a=b;b=t};当b=0时,gcd(a,b)=a;当b!=0时,gcd(a,b)=gcd(b,a%b);2.一个过程或函数直接调用自己本身或通过其他的过程或函数调用语句间接地条用自己的过程或函数,成为递归过程或函数。递归过程的执行总是一个过程体未执行完,就带着本次执行的结果又进入另一轮过程体的执行,如此反复,不断深入,知道某此过程的执行时终止递归调用的条件成立,不再深入,二执行本次的过程体余下的部分,然后又返回到上一次调用的过程体中,执行余下的部分,如此反复,知道回到起始位置上,才最终结束整个递归过程的执行,得到相应的执行结果。3.在程序设计面试中,一个能够完成任务的解决方案是最重要的,解决方案的执行效率要放在第二位考虑。如果题目是一个递归性的方案,不妨向面试官说明一下递归算法天生的低效率问题。【面向对象】1.对于一个空类,编译器默认产生4个成员函数:默认构造函数、析构函数、拷贝构造函数和赋值函数。2.C++中的struct其实和class意义一样,唯一不同的就是struct里面默认的访问控制是public,class中默认的访问控制是private。3.静态成员变量可以在同一个类的实例之间共享。如果把静态成员变量设为私有,可以通过共有静态成员函数访问。4.初始化列表的初始化变量顺序是根据成员变量的声明顺序来执行的。常量必须在构造函数的初始化列表里面初始化,或者将其设置成static。5.virtual关键字用于修饰方法、属性、索引器或事件声明,并使它们可以在派生类中被重写。virtual修饰符不能与static、abstract、private或override修饰符一起使用。6.虚函数采用一种虚调用的办法,虚调用是一种可以在只有部分信息的情况下工作的机制,特别允许我们调用一个只知道接口而不知道其准确对象类型的函数。但是如果要创建一个对象,必须知道对象的准确类型,所以构造函数不能为虚。7.带参数的构造函数如果不添加explicit关键字,会定义一个隐含的类型转换(从参数的类型转换到自己的类型),添加explicit可以消除这种隐含转换。8.C++中,下面三种对象需要调用拷贝构造函数:1)一个对象以值传递的方式传入函数体;2)一个对象以值传递的方式从函数返回;3)一个对象需要通过另外一个对象进行初始化;9.override是指派生类重写基类的虚函数,重写的函数必须有一致的参数表和返回值;overload指编写一个与已有函数同名但参数表不同的函数。10.友元是一种定义在类外部的普通函数,但它需要在类体内进行说明,为了与该类的成员函数加以区别,在说明时前面加以关键字friend。友元不是成员函数,但是他可以访问类中的私有成员。友元的作用在于提高程序的运行效率,但它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。例如:编写类String的构造函数、析构函数和赋值函数classString//类String的原型{public:String(constchar*str=NULL);//普通构造函数String(constString&other);//拷贝构造函数~String(void);//析构函数String&operate=(constString&other);//赋值函数private:char*m_data;//用于保存字符串}String::~String(void)//析构函数{delete[]m_data;//由于m_data是内部数据,也可以写成deletem_data}String::String(constchar*str)//构造函数{if(str==NULL){m_data=newchar[1];*m_data='\0';}else{intlength=strlen(str);m_data=newchar[length+1];strcpy(m_data,str);}}String::String(constString&other)//拷贝构造函数{intlength=strlen(other.m_data);m_data=newchar[length+1];strcpy(m_data,other.m_data);}String&String::operate=(constString&other){if(this==&other)//检查自赋值return*this;delete[]m_data;//释放原有的内存资源intlength=strlen(other.m_data);//分配新的内存资源,并赋值内容m_data=newchar[length+1];strcpy(m_data,other.m_data);return*this;//返回本对象的引用}【继承与接口】1.构造函数从最初始的基类开始构造,各个类的同名变量没有形成覆盖,都是单独的变量。2.虚函数是被子类同名函数所覆盖的。3.公有继承的特点:基类的公有成员和保护成员作为派生类的成员时,它们都保持原有的状态,而基类的私有成员仍然是私有的;私有继承的特点:私有继承的特点是基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问;保护继承的特点:基类的所有公有成员和保护成员都成为派生类的保护成员,并且只能被它的派生类成员函数或友元访问,基类的私有成员仍然是私有的;4.如果一个类中有一个虚函数,那么必须得有一个对应的虚函数表来记录对应的函数入口地址,每个地址需标有一个虚指针,指针的大小为4。5.虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的。AABC//\/BCD类D继承自类B和C,而BC都继承自A,所以会出现AA\/BC\/D类D中会出现两次A,为了节省内存空间,可以将B、C对A的继承定义为虚拟继承,而A就成了虚拟基类。最后形成A/\BC\/D代码如下:classA;classB:publicvirtualA;cl
本文标题:程序员面试宝典知识点总结
链接地址:https://www.777doc.com/doc-3972831 .html