程序员笔试题收集汇总(一)

来源:互联网 发布:淘宝企业店铺能注销吗 编辑:程序博客网 时间:2024/06/05 09:00

收集的笔试题,各处摘抄加自己的理解
相关文章:
程序员笔试题收集汇总(一)
http://blog.csdn.net/youyou1543724847/article/details/52383530
程序员笔试题收集汇总(二)
http://blog.csdn.net/youyou1543724847/article/details/52728001
程序员笔试题收集汇总(三)
http://blog.csdn.net/youyou1543724847/article/details/52728079

1.下列 C 代码中,不属于未定义行为的有_
A: Int i=0;i=(i++);
B: char *p=”hello”;p[1]=’E’;
C: char *p=”hello”;char ch=*p++;
D: int i=0;printf(“%d%d\n”,i++,i–);
E: 都是未定义行为
F: 都不是未定义行为
正确答案: C
解析:C语言中的未定义行为(Undefined Behavior)是指C语言标准未做规定的行为。同时,标准也从没要求编译器判断未定义行为,所以这些行为有编译器自行处理,在不同的编译器可能会产生不同的结果,又或者如果程序调用未定义的行为,可能会成功编译,甚至一开始运行时没有错误,只会在另一个系统上,甚至是在另一个日期运行失败。当一个未定义行为的实例发生时,正如语言标准所说,“什么事情都可能发生”,也许什么都没有发生。
所以,避免未定义行为,是个明智的决定。本文将介绍几种未定义行为,同时欢迎读者纠错和补充。
1.同一运算符中多个操作数的计算顺序(&&、||、?和,运算符除外)

例如:x = f()+g(); //错误
f()和g()谁先计算由编译器决定,如果函数f或g改变了另一个函数所使用变量的值,那么x的结果可能依赖于这两个函数的计算顺序。
参考: 《C程序设计语言(第2版)》 P43
2.函数各参数的求值顺序

例如: printf(“%d,%d\n”,++n,power(2,n)); //错误
在不同的编译器可能产生不同的结果,这取决于n的自增运算和power调用谁在前谁在后。
需要注意的是,不要和逗号表达式弄混,都好表达式可以参考这篇文章:c语言中逗号运算符和逗号表达式
参考: 《C程序设计语言(第2版)》 P43
3.通过指针直接修改 const 常量的值

直接通过赋值修改const变量的值,编译器会报错,但通过指针修改则不会

2. 6支笔,其笔身和笔帽颜色相同:但6支笔颜色各不相同,求全部笔身都戴错笔帽的可能性有多少种?
A:265
B: 266
C:267
D:268
答案:A
解析:网上摘抄(排错公式)
第一步,把第n个元素放在一个位置,比如位置k,一共有n-1种方法;
第二步,放编号为k的元素,这时有两种情况:⑴把它放到位置n,那么,对于剩下的n-1个元素,由于第k个元素放到了位置n,剩下n-2个元素就有D(n-2)种方法;⑵第k个元素不把它放到位置n,这时,对于这n-1个元素,有D(n-1)种方法(相当与K于原N的位置是一对,当时由于K不放在N的位置上,形成类似与“排错,不能构成匹配的语言”,则有n-1个元素);
综上得到
D(n) = (n-1) [D(n-2) + D(n-1)]

3. 假定变量I,f,d数据类型分别为int,float和double(int用补码表示,float和double分别用IEEE754单精度和双精度浮 点数据格式表示),已知i=785,f=1.5678e^3,d=1.5e^100若在32位机器 中执行下列关系表达式,则结果为真是()
(I)i==(int)(float)I
(II)f==(float)(int)f
(III)f==(float)(double) f
(IV)(d+f)-d==f
A:仅I和II
B:仅I和III
C:仅II和III
D:仅III和IV
答案:B
(I)i==(int)(float)I 由于i(int)经过强制类型转换从int->float->int和左边相同 正确
(II)f==(float)(int)f 由于f(float)经过强制类型转换 从float->int,虽然int也强制类型转换了但是小数点已经去掉,故精度丢失,和左边不一样,错误
(III)f==(float)(double) f 由于f(float)经过强制类型转换 从float->double->float和左边相同 正确
(IV)(d+f)-d==f 左边为了尽量保证精度不丢失,一般会把低转化为高精度从float->double 和右边float不同 错误

4. 每份考卷都有一个8位二进制序列号。当且仅当一个序列号含有偶数个1时,它才是有效的。例如,00000000、01010011都是有效的序列号,而11111110不是。那么,有效的序列号共有() 个
A:127
B:128
C:255
D:256
答案:B
总共有2^8=256个序列,其中要么含有偶数个1,要么奇数个,所以对半分为128个。
(可理解为二项分布 (1 +(-1))^8, 由于 (1-1)^8=0,则 结果中有效的无效的对半)

5. 求输出结果

int a[2][2][3]= { {{1,2,3},{4,5,6}},{{7,8,9},{10,11,12}}};int *ptr=(int *)(&a+1);printf(“%d %d”, *(int*)(a+1), *(ptr-1));

A:7 12
B:1 6
C:1 3
D:7 9
正确答案: A
6. 有哪几种情况只能用intialization list 而不能用assignment?

A:当类中含有const成员变量
B:基类无默认构造函数时,有参的构造函数都需要初始化表。
C:当类中含有reference成员变量
D:当类中含有static成员变量
正确答案: A B C
因为const对象以及引用只能初始化而不能赋值,所以只能使用成员初始化列表。
对于非内置类型,在进入函数体之前,如果没有提供显式初始化,会调用默认构造函数进行初始化。若没有默认构造函数,则编译器尝试调用默认构造函数将会失败,所以如果没有默认构造函数,则必须在初始化列表中显示的调用构造函数。
static 成员在执行构造函数前就已经构造好了,即使不存在类对象,也可以被使用,不需要初始化列表
7. 下列TCP连接建立过程描述正确的是:
A:服务端收到客户端的SYN包后等待2*ml时间后就会进入SYN_SENT状态
B:服务端收到客户端的ACK包后会进入SYN_RCVD状态
C:当客户端处于ESTABLISHED状态时,服务端可能仍然处于SYN_RCVD状态
D:服务端未收到客户端确认包,等待2*ml时间后会直接关闭连接
正确答案: C
关于D,如果服务器处于SYN_Recv状态,发送了同步+确认包后,没有收到客户端的确认包,则一般会重试,重新发送同步+确认包后,并等待一段时间后丢弃这个未完成的连接,这段时间的长度我们称为SYN Timeout,一般来说这个时间是分钟的数量级(大约为30秒-2分钟);一个用户出现异常导致服务器的一个线程等待1分钟并不是什么很大的问题,但如果有一个恶意的攻击者大量模拟这种情况,服务器端将为了维护一个非常大的半连接列表而消耗非常多的资源—-数以万计的半连接,即使是简单的保存并遍历也会消耗非常多的CPU时间和内存,何况还要不断对这个列表中的IP进行SYN+ACK的重试。此时从正常客户的角度看来,服务器失去响应,这种情况我们称做:服务器端受到了SYN Flood攻击(SYN洪水攻击)

8. 以下对CSMA/CD描述正确的是?
A:在数据发送前对网络是否空闲进行检测
B:在数据发送时对网络是否空闲进行检测
C:在数据发送时对发送数据进行冲突检测
D:发生碰撞后MAC地址小的主机拥有发送优先权
答案:AC
CSMA/CD协议即带冲突检测的载波监听多路访问协议。
A,发送前空闲检测,只有信道空闲才发送数据
B,发送时当前信号占据信道,信道必定不为空闲,检测空闲没意义
C,发送过程中冲突检测,如果发生冲突,立即停止发送,随机避让。
D,冲突发送后,两个发送端都随机避让一段时间,避让的时间是随机的,优先级相等,没有哪个优先权高的说法。
9.以下哪些线程同步锁可以为递归锁
1.信号量 2.读写锁 3.互斥量 4.事件 5.临界区(Critical Section)
A: 1,3,4,5
B:5
C:3,5
D:1,3,5
正确答案: C
进程/线程同步方法
常见的进程/线程同步方法有互斥锁(或称互斥量Mutex)、读写锁(rdlock)、条件变量(cond)、信号量(Semophore)等。
在windows系统中,临界区(Critical Section)和事件对象(Event)也是常用的同步方法。
递归锁/非递归锁
Mutex可以分为递归锁(recursive mutex)和非递归锁(non-recursive mutex)。 递归锁也叫可重入锁(reentrant mutex),非递归锁也叫不可重入锁(non-reentrant mutex)。
二者唯一的区别是:
同一个线程可以多次获取同一个递归锁,不会产生死锁。
如果一个线程多次获取同一个非递归锁,则会产生死锁。
Windows下的Mutex和Critical Section是可递归的。
Linux下的pthread_mutex_t锁是默认是非递归的。可以通过设置PTHREAD_MUTEX_RECURSIVE属性,将pthread_mutex_t锁设置为递归锁。
10. A、B、C、D四人应聘一个程序员职位,此职务的要求条件是:Java熟练;懂数据库开发;会Web开发;有C++经验。谁满足的条件最多,谁就被雇用。(1)把上面四个要求条件两两组合,每个组合都恰有一人满足。同时已知(2)A和Bjava熟练(3)B和C会Web(4)C和D懂数据库(5)D有C++经验那么,被雇用的是__
A:A
B:B
C:C
D:D
E:四人机会均等
F:以上均错
解析:经过推测为(s为数据库)
A B C D
java java X X
X web web X
S X S S
X C X C
所以为B
11. 下面程序的结果是:

class Supper{    public Integer get()    {        System.out.println("s");        return 4;    }}public class test extends Supper{    public Long get()    {        System.out.println("b");        return new Long("5");    }     public static void main(String args[])     {         Supper s=new Supper();         test test=new test();         s.get();         test.get();     }}

答案:编译错误

扩展:
11. 1下面程序的结果是:

class Supper{    public Integer get()    {        System.out.println("Supper");        return new Integer("5");    }}public class Sub{    public int get()    {        System.out.println("Sub");        return 5;    }     public static void main(String args[]) {         new Supper().get();         new Sub().get();     }}

答案:Supper Sub

11. 2下面程序的结果是:

class Supper{    public int get()    {        System.out.println("Supper");        return 5;    }}public class Sub{    public int get()    {        System.out.println("Sub");        return new Integer("5");    }     public static void main(String args[]) {         new Supper().get();         new Sub().get();     }}

答案:Supper Sub
12. 以上程序的运行结果是:

int* pint = 0; pint += 6; cout << pint << endl;

A:12
B:72
C:24
D:0
E:6
F:任意数
答案:C
13. 以上程序的运行结果是:

public class Base {    static Base a=new Base();    {System.out.print("C");}    static{ System.out.print("S"); }    Base(){}     public static void main(String args[]) {         new Base();     }}

答案:CSC
14. 字符串 alibaba 有多少个不同的排列
思路:先有序排列:aaabbli。首先递归a(aabbli), b(aaabli), l(aaabbli) ,i(aaabbl)…依 次交换不相同的。 http://blog.csdn.net/a45872055555/article/details/38490785 只计算个数的话,就用:A(7,7) / (A(3,3)*A(2,2)) = 420
15. 某校园网用户无法访问外部站点210.102.58.74,管理人员在windows 操作系统 下可以使用( )判断故障发生在校园网内还是校园网外

16. 那些应用层协议采用的UDP,那些是TCP
21/tcp FTP 文件传输协议
22/tcp SSH 安全登录、文件传送(SCP)和端口重定向
23/tcp Telnet 不安全的文本传送
25/tcp SMTP Simple Mail Transfer Protocol (E-mail)
69/udp TFTP Trivial File Transfer Protocol
79/tcp finger Finger
80/tcp HTTP 超文本传送协议 (WWW)
88/tcp Kerberos Authenticating agent
110/tcp POP3 Post Office Protocol (E-mail)
113/tcp ident old identification server system
119/tcp NNTP used for usenet newsgroups
220/tcp IMAP3
443/tcp HTTPS used for securely transferring web pages

UDP支持的应用层协议主要有:NFS(网络文件系统)、SNMP(简单网络管理协议)、DNS(主域名称系统)、TFTP(通用文件传输协议)等

PS:DNS服务器在更新数据时采用的是TCP,其他查询的时候使用的是TCP
17. 写出new和malloc、delete和free的区别

从面向对象来说,new/delete和malloc/free的区别是:malloc/free只是单纯的进行内 存空间的分配和释放,而使用new/delete时,不仅分配了内存空间,若new/delete的 是一个类,还会调用类(经测试,基本类型好像不会进行默认初始化)的构造函数或析 构函数。   简单来说,两者的区别主要有:
1. malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符, 与”+“、”-“、”*“、”/“有一样的地位。
2. new/delete是可以重载的,而重载之后,就成为了函数。
3. malloc在申请内存的时候,必须要提供申请的长度,而且返回的指针是void* 型,必须要强转成需要的类型。
4. 当new/delete在类中被重载的时候,可以自定义申请过程,比如记录所申请内 存的总长度,以及跟踪每个对象的指针。
5. new/delete,其实内部也调用了malloc/free。

两者的共同点有: 1. 都必须配对使用,防止内存泄露。 2. 都可用于申请动态内存和释放内存,都是在堆中分配内存。

18. 下面程序输出:
Object o1 = true ? new Integer(1) : new Double(2.0);

Object o2;
if (true)
o2 = new Integer(1);
else
o2 = new Double(2.0);
System.out.println(o1);
System.out.println(o2);

答案:
1.0
1
解析:当第二第三操作时可转化成数值类型时,可能发生类型提升、自动拆装箱
参考:https://blog.jooq.org/2013/10/08/java-auto-unboxing-gotcha-beware/

19. 下面程序输出:

class Y{    public Y(){        System.out.println("Y");    }}class Supper{    Y y=new Y();    public Supper(){        System.out.println("Supper");    }}public class Sub extends Supper{    Y y=new Y();    public Sub(){        System.out.println("Sub");    }     public static void main(String args[]) {        new Sub();        }}

答案:
Y
Supper
Y
Sub

20. 存在使i + 1 < i的数吗()
答案:存在 解析:如果i为int型,那么当i为int能表示的最大整数时,i+1就溢出变成负数了,此时不就< i了吗。
扩展:存在使i > j || i <= j不成立的数吗()
答案:存在 解析:比如Double.NaN或Float.NaN

21. 0.6332的数据类型是()
A float B double C Float D Double
答案:B 解析:默认为double型,如果为float型需要加上f显示说明,即0.6332f
扩展:34892234343的数据类型为int,即使在使用是可能存在溢出,如果要定义成Long,则需要加上l,如34L.

22. 不通过构造函数也能创建对象吗()
A 是 B 否
答案:A 解析:Java创建对象的几种方式(重要):
(1) 用new语句创建对象,这是最常见的创建对象的方法。
(2) 运用反射手段,调用java.lang.Class或者java.lang.reflect.Constructor类的newInstance()实例方法。
(3) 调用对象的clone()方法。
(4) 运用反序列化手段,调用java.io.ObjectInputStream对象的 readObject()方法。 (1)和(2)都会明确的显式的调用构造函数 ;(3)是在内存上对已有对象的影印,所以不会调用构造函数 ; (4)是从文件中还原类的对象,也不会调用构造函数。

23.

     public static void main(String args[]) {        String s;        System.out.println("s:"+s);     }

A 代码得到编译,并输出“s=”
B 代码得到编译,并输出“s=null”
C 由于String s没有初始化,代码不能编译通过
D 代码得到编译,但捕获到 NullPointException异常
答案:C 解析:开始以为会输出null什么的,运行后才发现Java中所有定义的基本类型或对象都必须初始化才能输 出值。

24. Java中如何实现代理机制(JDK、CGLIB)
JDK动态代理:代理类和目标类实现了共同的接口,用到InvocationHandler接口(重新invoke方法)。缺点:只能代理接口,不能代理类。
CGLIB动态代理:代理类是目标类的子类, 用到MethodInterceptor接口

25. 多线程的实现方式
继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。

26. 如何停止一个线程
不建议使用Thread的stop,suspend等相关方法(这些都是废弃了的方法,会导致不确定的状态)
可以使用Thread.interrupt()方法,设置中断标注。该方法能参数不同的结果:
1.如果线程处于阻塞在 waitXX(), join(XX), sleep(XX)系统放上,则线程的中断标志会被清楚,并抛出InterruptedException异常。
2.如果线程阻塞在某些IO操作上(如 InterruptibleChannel, Selector),则会设定中断状态,并从IO操作中返回,并抛出相应的异常(ClosedByInterruptException)。
3.普通状态:只会设置interrupt标志(即如果你不做状态检查并做相应的处理,和没有收到是一回事)
4.如果线程已经死亡,则不会有任何效果。

27. 什么是线程安全
线程安全就是多线程访问同一代码,不会产生不确定的结果。

28. 如何保证线程安全
将共享变量变成局部变量,或是用ThreadLocal(其实是一个map,key为thread标识)
使用线程安全的类
自己控制,如加锁等。

29. Synchronized如何使用
synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:
一. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
二. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
三. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类对象;

30. 多线程如何进行信息交互
void notify() 唤醒在此对象监视器上等待的单个线程。
void notifyAll() 唤醒在此对象监视器上等待的所有线程。
void wait() 导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll()方法。
void wait(long timeout) 导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll()方法,或者超过指定的时间量。
void wait(long timeout, int nanos) 导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll()方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。

31. sleep和wait的区别(考察的方向是是否会释放锁)
都会抛出InterruptedException异常
sleep()方法是Thread类中方法,而wait()方法是Object类中的方法。
sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态,在调用sleep()方法的过程中,线程不会释放对象锁。而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备
32. 多线程与死锁
死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。
产生死锁的原因:
一.因为系统资源不足。
二.进程运行推进的顺序不合适。
三.资源分配不当。

33. 如何才能产生死锁
一.互斥条件:所谓互斥就是进程在某一时间内独占资源。
二.不剥夺条件:进程已获得资源,在末使用完之前,不能强行剥夺。
三.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
四.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

34. 死锁的预防
一.打破互斥条件。即允许进程同时访问某些资源。但是,有的资源是不允许被同时访问的,像打印机等等,这是由资源本身的属性所决定的。所以,这种办法并无实用价值。
二.打破不可抢占条件。即允许进程强行从占有者那里夺取某些资源。就是说,当一个进程已占有了某些资源,它又申请新的资源,但不能立即被满足时,它必须释放所占有的全部资源,以后再重新申请。它所释放的资源可以分配给其它进程。这就相当于该进程占有的资源被隐蔽地强占了。这种预防死锁的方法实现起来困难,会降低系统性能。
三.打破占有且申请条件。可以实行资源预先分配策略。即进程在运行前一次性地向系统申请它所需要的全部资源。如果某个进程所需的全部资源得不到满足,则不分配任何资源,此进程暂不运行。只有当系统能够满足当前进程的全部资源需求时,才一次性地将所申请的资源全部分配给该进程。由于运行的进程已占有了它所需的全部资源,所以不会发生占有资源又申请资源的现象,因此不会发生死锁。
四.打破循环等待条件,实行资源有序分配策略。采用这种策略,即把资源事先分类编号,按号分配,使进程在申请,占用资源时不会形成环路。所有进程对资源的请求必须严格按资源序号递增的顺序提出。进程占用了小号资源,才能申请大号资源,就不会产生环路,从而预防了死锁。

35. 什么叫守护线程,用什么方法实现守护线程
守护线程是为其他线程的运行提供服务的线程。
setDaemon(boolean on)方法可以方便的设置线程的Daemon模式,true为守护模式,false为用户模式。 必须在线程启动前设置才有效

36. Java线程池技术及原理
http://www.importnew.com/19011.html
http://www.cnblogs.com/dolphin0520/p/3932921.html

37. java并发包concurrent及常用的类
并发包诸类概览:http://www.raychase.net/1912
线程池:http://www.cnblogs.com/dolphin0520/p/3932921.html
锁:http://www.cnblogs.com/dolphin0520/p/3923167.html
集合:http://www.cnblogs.com/huangfox/archive/2012/08/16/2642666.html

38. volatile关键字
用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最的值。volatile很容易被误用,用来进行原子性操作。
Java语言中的volatile变量可以被看作是一种 “程度较轻的 synchronized”;与 synchronized 块相比,volatile 变量所需的编码较少,并且运行时开销也较少,但是它所能实现的功能也仅是synchronized的一部分。锁提供了两种主要特性:互斥(mutual exclusion)和可见性(visibility)。互斥即一次只允许一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的协调访问协议,这样,一次就只有一个线程能够使用该共享数据。可见性必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的,如果没有同步机制提供的这种可见性保证,线程看到的共享变量可能是修改前的值或不一致的值,这将引发许多严重问题。Volatile变量具有synchronized的可见性特性,但是不具备原子特性。这就是说线程能够自动发现 volatile 变量的最新值。
要使volatile变量提供理想的线程安全,必须同时满足下面两个条件:对变量的写操作不依赖于当前值;该变量没有包含在具有其他变量的不变式中。
第一个条件的限制使volatile变量不能用作线程安全计数器。虽然增量操作(x++)看上去类似一个单独操作,实际上它是一个由读取-修改-写入操作序列组成的组合操作,必须以原子方式执行,而volatile不能提供必须的原子特性。实现正确的操作需要使 x 的值在操作期间保持不变,而 volatile 变量无法实现这点。
每一个线程运行时都有一个线程栈,线程栈保存了线程运行时候变量值信息。当线程访问某一个对象时候值的时候,首先通过对象的引用找到对应在堆内存的变量的值,然后把堆内存变量的具体值load到线程本地内存中,建立一个变量副本,之后线程就不再和对象在堆内存变量值有任何关系,而是直接修改副本变量的值,在修改完之后的某一个时刻(线程退出之前),自动把线程变量副本的值回写到对象在堆中变量。这样在堆中的对象的值就产生变化了。

一下来源于“程序员面试宝典”

39 i++问题、&&和||运算优化
&&运算中,如果第一操作数为假,就不会执行第二个条件判断,||运算中,如果第一操作数为真,则不会进行第二个条件判断。

40 printf计算参数时,是从右到左压栈的

   int *p={1,2,3};   printf("%d,%d",*p,*(++p));

打印2,2

41 注意类型扩展和类型转化,知道那些类型是有符号的还是无符号的(c++中没有byte类型)
右移时,进行的是符号右移(即如果是负数,则添1,否则补0)

42 运算的优先级
总体来说,一元运算符优先级大于二元运算符
对于一元运算符:() > [] > -> > . > :: > 后缀++,– > !如if(!done) > ~,如flags=~flags > 前缀++,– > -,+(如int i=+1)> 取地址,指针*(如data=*p,address=&obj)> type,sizeof

    对于二元运算符:乘除>加减>移位

Java中的无符号右移:>>>
int x=-1;
System.out.println(Integer.toBinaryString(x>>>3 ));
System.out.println(Integer.toBinaryString((x>>>3)<<3));
System.out.println(Integer.toBinaryString(x>>3));

结果:
11111111111111111111111111111
11111111111111111111111111111000
11111111111111111111111111111111

运算符优先级:括号,下标,->和.(成员)最高;
         单目的比双目的高;
         算术双目的比其他双目的高;
         移位运算 高于 关系运算(比较大小);
         关系运算 高于 按位运算(按位与,或,异或);
         按位运算 高于 逻辑运算(逻辑与,逻辑或);
         三目的只有一个 条件运算,低于逻辑运算;
         赋值运算仅比 , (顺序运算)高。

这里写图片描述

这里写图片描述

43 X&(X-1)的作用
将X最右边的一个1清零

44 不用比较判断,输出a,b中的大数

方法一:int max=( (a+b)  +abs(a-b)  )/2方法二:    char *strs[2]={"a Large","b Large"};           int c=a-b;           c=unsinged(c) >>(sizeof(int)*8 -1);           cout << strs[c];

45 不用中间变量,将a,b交换

-   方法一:(缺点:将a+b的结果可能会溢出)                a=a+b;                b=a-b;                a=a-b;    方法二:                a=a^b;                b=a^b;                a=a^b;

46 在C++中调用被C编译器编译后的函数,为什么后面要交extern“c”

  • 被不同的编译器编译后的代码会和语言支持的功能相关,如C++支持重载,编译器需要将函数重命名来达到区分不同的函数的目的,但是C中就没有重载的概念,函数编译命名规则就会和C++不同。因此,使用extern “c”,就可以告诉编译器这些差别,不要让他找不到这些符号

47 求结构体某个变量相对于struct的偏移
- (size_t) &( ((struct *)0) ->var ),将0转化成struct类型的指针变量*P,用该变量取var成员变量的偏移地址。
*p的起始地址为0,则成员变量var的地址即是它的偏移。

48 使用sizeof计算类的大小时,不要考虑static变量
- 类、结构体最小大小为1byte,就算没有任何成员变量

49 使用sizeof计算类、结构体大小时,需要考虑对齐问题
- 所占的大小为最大长度变量的整数倍(考虑数组类型的变量能够好取),且内部地址也要对齐,如int类型的成员变量地址必须是4的整数倍,如:

struct A{   bool m;   int  n;   bool k;}struct B{   int  n;   bool m;   bool k;}

则A占用12,B占用8字节(考虑B,如果B只占用6字节,如果有 B bb[2],则bb[0]地址为0,bb[1]地址为6,则bb[1]中的int变量n地址为6,不是int类型长度的整数倍,不好管理,则B编译器会将B变成占用8byte的,没有使用到的用0填充)

50 区别如下指针的含义

-       int *a,一个指向int类型的指针        int **a,一个二级指针,它指向一个指针(该指针指向一个intint *a[10]:一个数组,里面有10个指向int类型的指针        int (*a)[10]:一个指针,指向一个有10个元素的int数组        int (*a)(int):函数指针,返回值为int,参数一个int的函数指针        int  (*a[10])int :一个数组,里面有10个函数指针,函数指针指向返回值为int,参数一个int的函数

51 注意容器元素中拷贝带来的问题(浅拷贝、深拷贝)

特别是容器中存放的类型类成员中还有指针时,使用浅拷贝,则会导致容器中的数据指针悬挂,如   Vecotr <A>v=new Vector<A>()   A a;   a.p=new char[32];   v.push_back(a)   delete a//这里会释放掉a.p所指向的内存,但由于是浅拷贝,则容器中的数据temp.p成了悬挂指针。
  • 当类中还有指针类型的数据成员时,则需要仔细考虑它的构造函数(如何初始化),析构函数(如果该指针不为null,则需要delete掉),拷贝构造函数,赋值操作符函数(是否需要进行深拷贝)

52 C++中如何阻止 一个类被实例化
- 使用抽象类,或者将构造函数声明为private

53 一般在什么时候将构造函数声明为private
- 比如需要阻止编译器生成默认的构造函数的时候(或是某种类型的构造函数只是为其他重载形式的构造函数调用的时候)

54 什么时候编译器会生成默认的copy constructor
- 如果你没有写,而又需要使用,则会自动生成

55 如果某个方法没有使用任何成员变量,不需要this指针,不需要动态绑定(一般来说非virtual方法),则使用null就能激活

- 如 SomeType *p =null;   p->a();//能正常运行       ( (X*)0 )->x(); //能正常运行        ((X*)NULL)->x();//能正常运行

JAVA 里是不可以的,因为Java方法都是动态绑定的

以下来源于“关于C++的222个问题”

56 C++支持多重继承,为了解决多重继承中的数据多份拷贝的情况,C++采用虚基类
- 虚基类:基类定义方式不变,子类在继承时,加上virtual关键字,如:Sub A:virtual Super B

57 多态,又分为静态多态和动态多态
- 静态多态主要是模版(编译期就处理好实际采用的类型)
动态多态:主要是通过virtual关键字的

58 C++中的RTTI(Runtime Type identifier)
- C++中的动态类型标识,主要是typeid操作符和dynamic_cast的使用。注意:使用动态类型标识需要在运行时重新编译部分代码或是在编译时,保留一些类型信息,导致效率比较低,且转换不安全。在使用dynamic_cast进行类型转化时,需要在类中至少有一个virtual函数。

59 C++中的强制类型转换运算符
- 有4中:
dynamic_cast:
static_cast:
reinterpret_cast:
const_cast:

60 面向对象的主要思想
- 抽象、封装、继承、多态

61 多态的类型
- 强制多态(类型转换)、重载、类型参数化多态(模版)、包含多态(类继承和虚函数)

61 C++的动态性
- C++中的动态性包括:虚函数、多态性、动态联编
关于虚函数:为了让通过基类指针调用的方法和子类方法对应,如Super A=new Sub(); A->func(),为了让A是调用的Sub中的func版本,需要将func声明为virtual的,这是通过vtbl,vptr实现的)
关于动态联编:即有的信息需要在运行时进行绑定,又叫晚期联编。

62 数组创建:

   int *a=new int[3];//创建了一个指向int数组的指针,该数组长度为3,对应删除方式为delete []a;   int *b=new int(3);//创建了一个int型指针,且指向的值为 3,对应删除方式为delete b;   int  c[3];//声明了一个数组长度为3int型数组,该中声明方式将c放在栈上,且这个时候,数组的长度必须为常量。

63 常用类型比较

   int直接比较 : a==b   char直接比较 : a==b   float,double: abs(a-b)<=某个误差值   char *p,或是char []:strcmp( a,b)==0   string : a==b

64 在自动计算大小的char数组中,最终得到的长度=实际长度+1
(会补充一个\0进去,不管实际串中是否存在\0),但是输出串时,遇到\0,就不输出了。
这里写图片描述

这里写图片描述

65 使用sizeof计算类的大小时,不要考虑static变量,不需要考虑它的方法
使用sizeof计算类、结构体变量时,需要考虑对其问题(按最长的字段的整数倍(如果最长长度的变量超过了cpu长度,则按照cpu长度对其))

sizeof和strlen()的区别

        strlen:是函数,参数为char*,计算规则是从字符串开始,遇到\0结束,长度不包括\0。如char a[]="ab\0\0",strlen(a)=2,sizeof(a)=5;        sizeof:类似于宏,大部分编译程序在编译期就可以计算出其值,而strlen是在运行期得出结果。        (int *p = (int*)malloc(sizeof(int) * 100);            cout << sizeof(p) << endl;sizeof计算是指针的空间,32位系统下为4)(关于这点:如果对没有经过初始化的动态char*使用strlen,则结果是未定义的,这是strlen的逻辑,只有遇到\0才结束)         sizeof:

66 virtual修饰符会被隐形继承的
即在父类中方法是virtual的,子类中重写方法时,没有加virtual关键字,但是该方法还是虚函数。

67 基本数据类型所占字节数
16位编译器

char1个字节char*(即指针变量): 2个字节short int : 2个字节int2个字节unsigned int : 2个字节float:  4个字节long:   4个字节unsigned long:  4个字节long long:  8个字节double:   8个字节

32位编译器

char1个字节char*(即指针变量): 4个字节(32位的寻址空间是2^32, 即32个bit,也就是4个字节。同理64位编译器)short int : 2个字节int4个字节unsigned int : 4个字节float:  4个字节long:   4个字节unsigned long:  4个字节long long:  8个字节double:   8个字节

64位编译器

char1个字节char*(即指针变量): 8个字节short int : 2个字节int4个字节unsigned int : 4个字节float:  4个字节long:   8个字节unsigned long:  8个字节long long:  8个字节double:   8个字节

68 STL常用头文件

#include <algorithm>    //STL 通用算法   #include <bitset>     //STL 位集容器   #include <cctype>   #include <cerrno>   #include <clocale>   #include <cmath>   #include <complex>     //复数类   #include <cstdio>   #include <cstdlib>   #include <cstring>   #include <ctime>   #include <deque>      //STL 双端队列容器   #include <exception>    //异常处理类   #include <fstream>   #include <functional>   //STL 定义运算函数(代替运算符)   #include <limits>   #include <list>      //STL 线性列表容器   #include <map>       //STL 映射容器   #include <iomanip>   #include <ios>       //基本输入/输出支持   #include <iosfwd>     //输入/输出系统使用的前置声明   #include <iostream>   #include <istream>     //基本输入流   #include <ostream>     //基本输出流   #include <queue>      //STL 队列容器   #include <set>       //STL 集合容器   #include <sstream>     //基于字符串的流   #include <stack>      //STL 堆栈容器       #include <stdexcept>    //标准异常类   #include <streambuf>    //底层输入/输出支持   #include <string>     //字符串类   #include <utility>     //STL 通用模板类   #include <vector>     //STL 动态数组容器   #include <cwchar>   #include <cwctype>   using namespace std;   

69 常用C头文件

#include <assert.h>    //设定插入点#include <ctype.h>     //字符处理#include <errno.h>     //定义错误码#include <float.h>     //浮点数处理#include <iso646.h>        //对应各种运算符的宏#include <limits.h>    //定义各种数据类型最值的常量#include <locale.h>    //定义本地化C函数#include <math.h>     //定义数学函数#include <setjmp.h>        //异常处理支持#include <signal.h>        //信号机制支持#include <stdarg.h>        //不定参数列表支持#include <stddef.h>        //常用常量#include <stdio.h>     //定义输入/输出函数#include <stdlib.h>    //定义杂项函数及内存分配函数#include <string.h>    //字符串处理#include <time.h>     //定义关于时间的函数#include <wchar.h>     //宽字符处理及输入/输出#include <wctype.h>    //宽字符分类

70 包含文件的多种写法的区别

<>仅仅在系统指定的路径下面寻找,”“会首先在源文件的路径查找,找不到就到系统路径中寻找

  • include包含头文件的语句中,双引号和尖括号的区别是什么?
  • include <>格式:引用标准库头文件,编译器从标准库目录开始搜索

    incluce “”格式:引用非标准库的头文件,编译器从用户的工作目录开始搜索

    • 有木有h都无所谓,只要include这个文件名,确实存在就行。
      比如经常写的#include ,那么系统的包含路径下,是确实有iostream这个文件存在的。
      .h只是一个惯例,提示这是个头文件,并非强制。

C++头文件加H和不加H有什么区别
iostream是C++的头文件,iostream.h是C的头文件,即标准的C++头文件没有.h扩展名,将以前的C的头文件转化为C++的头文件后,有时加上c的前缀表示来自于c,例如cmath就是由math.h变来的。 iostream.h里面定义的所有类以及对象都是在全局空间里,所以你可以直接用cout 但在iostream里面,它所定义的东西都在名字空间std里面,所以你必须加上 using namespace std才能使用cout 一般一个C++的老的带“.h”扩展名的库文件,比如iostream.h,在新标准后的标准库中都有一个不带“.h”扩展名的相对应,区别除了后者的好多改进之外,还有一点就是后者的东东都塞进了“std”名字空间中。 但唯独string特别。 问题在于C++要兼容C的标准库,而C的标准库里碰巧也已经有一个名字叫做“string.h”的头文件,包含一些常用的C字符串处理函数,比如strcmp。 这个头文件跟C++的string类半点关系也没有,所以并非的“升级版本”,他们是毫无关系的两个头文件。

1 0
原创粉丝点击