现在的位置: 首页 > 综合 > 正文

C++问题

2014年09月07日 ⁄ 综合 ⁄ 共 8290字 ⁄ 字号 评论关闭

1. c++中指针的优缺点有哪些
答案:优点:
(1)提高程序的编译效率和执行速度。
(2)通过指针可使用主调函数和被调函数之间共享变量或数据结构,便于实现双向数据通讯。
(3)可以实现动态的存储分配。
(4)便于表示各种数据结构,编写高质量的程序。
缺点:
(1)使用未正确初始化的指针导致程序崩溃
(2)引用已释放的指针
(3)通过指针访问不该访问的内存
2. 宏和函数的区别
答案:(1)宏做的是简单的字符串替换(注意是字符串的替换,不是其他类型参数的替换),而函数的参数的传递,参数是有数据类型的,可以是各种各样的类型。
(2)宏的参数替换是不经计算而直接处理的,而函数调用是将实参的值传递给形参,是计算得来的。
(3)宏在编译之前进行,即先用宏体替换宏名,然后再编译的,而函数是编译之后,在执行时,才调用的。因此,宏占用的是编译的时间,而函数占用的是执行时的时间。
(4)宏的参数是不占内存空间的,因为只是做字符串的替换,而函数调用时的参数传递则是具体变量之间的信息传递,形参作为函数的局部变量,是占用内存的。
(5)函数的调用是需要付出一定的时空开销的,因为系统在调用函数时,要保留现场,然后转入被调用函数去执行,调用完,再返回主调函数,此时再恢复现场,这些操作,显然在宏中是没有的。
3. 宏定义是什么时期处理的(预处理?编译期?)
答案:预处理
4. 不同情况下类对象的大小(有数据成员,无数据成员,有虚函数等)
答案:(1)无任何数据成员和虚函数的类大小为1
(2)每个虚函数大小为4
(3)成员变量大小要考虑内存对齐,通常是4字节对齐
5. STL中vector使用的时候要注意什么
答案:(1) 如果元素是对象的指针,当该vector超出其作用域或调用erase删除元素时,那么元素本身在该vector中会被删除,但对象本身并没有得到销毁。在这种情况下,销毁的工作要由程序员自己来做。
(2) 用erase删除vector容器中的元素对象时,元素对象的析构函数会被多次调用。
6. 字符转整型数的函数是什么? 是怎样实现的?
答案:
strtol、strtoul。
#define TOLOWER(x) ((x) | 0×20)
#define isxdigit(c) ((’0′ <= (c) && (c) <= ’9′) \
|| (‘a’ <= (c) && (c) <= ‘f’) \
|| (‘A’ <= (c) && (c) <= ‘F’))

#define isdigit(c) (’0′ <= (c) && (c) <= ’9′)

unsigned long strtoul(const char *cp,char **endp,unsigned int base)
{
unsigned long result = 0,value;

if (!base) {
base = 10;
if (*cp == ’0′) {
base = 8;
cp++;
if ((TOLOWER(*cp) == ‘x’) && isxdigit(cp[1])) {
cp++;
base = 16;
}
}
} else if (base == 16) {
if (cp[0] == ’0′ && TOLOWER(cp[1]) == ‘x’)
cp += 2;
}
while (isxdigit(*cp) &&
(value = isdigit(*cp) ? *cp-’0′ : TOLOWER(*cp)-’a'+10) < base) {
result = result*base + value;
cp++;
}
if (endp)
*endp = (char *)cp;
return result;
}
long strtol(const char *cp,char **endp,unsigned int base)
{
if(*cp==’-')
return -strtoul(cp+1,endp,base);
return strtoul(cp,endp,base);
}
INT32S atoi(const INT8S *nptr)//
{
return strtol(nptr, ( INT8S **)NULL, 10);
}
7. 虚拟类和最终类能否派生出对象
答案:虚拟类可以派生对象
8. 你怎么理解虚拟类?虚拟类可以实例化一个对象吗?为什么?它的作用和其他类的区别
答案:虚拟类可以派生对象,纯虚类不可以实例化对象。因为纯虚类存在未定义的函数,只是个概念,不可真实存在。虚拟类用做多态,纯虚类做接口。
9. 内联函数怎么实现的,什么时期处理的,优缺点
答案:在程序编译时,编译器将程序中出现的内联函数的调用表达式用内联函数的函数体来进行替换。
优点:不会产生函数调用的开销
缺点:增加目标程序的代码量,即增加空间开销
10. 内存分配的几种方法与特点
答案:栈:就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区。里面的变量通常是局部变量、函数参数等。
堆:就是那些由new分配的内存块,
自由存储区:就是那些由malloc等分配的内存块
全局/静态存储区:全局变量和静态变量被分配到同一块内存中
常量存储区:这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改
11. 静态变量、全局变量、局部变量分别存储于什么位置
答案:静态变量:全局/静态存储区
全局变量:全局/静态存储区
局部变量:栈
12. static全局变量与普通全局变量的区别?static局部变量与普通变量的区别?static函数与普通函数的区别
答案:
static全局变量与普通的全局变量有什么区别:static全局变量只初使化一次,并且在其他文件单元中不可被引用
static局部变量和普通局部变量有什么区别:static局部变量只被初始化一次,值在程序生存期有效
static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝
13. 虚函数的机制,怎么理解。与其它函数的区别,如重载
答案:虚函数在c++中的实现机制就是用虚表和虚指针
普通函数编译时绑定,虚函数运行时绑定
14. 写一个复制字符串的方法,要求只能使用基本类型,用char数组表示字符串
答案:
char * strcpy(char * strDest,const char * strSrc)
{
if ((strDest==NULL)||(strsrc=”/=NULL”)) //[1]
throw “Invalid argument(s)”; //[2]
char * strDestCopy=strDest; //[3]
while ((*strDest++=*strSrc++)!=’\0′); //[4]
return strDestCopy;
}
[1]
(A)不检查指针的有效性,说明答题者不注重代码的健壮性。
(B)检查指针的有效性时使用((!strDest)||(!strSrc))或(!(strDest&&strSrc)),说明答题者对C语言中类型的隐式转换没有深刻认识。在本例中char *转换为bool即是类型隐式转换,这种功能虽然灵活,但更多的是导致出错概率增大和维护成本升高。所以C++专门增加了bool、true、false三个关键字以提供更安全的条件表达式。
(C)检查指针的有效性时使用((strDest==0)||(strsrc=”/=0″)),说明答题者不知道使用常量的好处。直接使用字面常量(如本例中的0)会减少程序的可维护性。0虽然简单,但程序中可能出现很多处对指针的检查,万一出现笔误,编译器不能发现,生成的程序内含逻辑错误,很难排除。而使用NULL代替0,如果出现拼写错误,编译器就会检查出来。
[2]
(A)return new string(“Invalid argument(s)”);,说明答题者根本不知道返回值的用途,并且他对内存泄漏也没有警惕心。从函数中返回函数体内分配的内存是十分危险的做法,他把释放内存的义务抛给不知情的调用者,绝大多数情况下,调用者不会释放内存,这导致内存泄漏。
(B)return 0;,说明答题者没有掌握异常机制。调用者有可能忘记检查返回值,调用者还可能无法检查返回值(见后面的链式表达式)。妄想让返回值肩负返回正确值和异常值的双重功能,其结果往往是两种功能都失效。应该以抛出异常来代替返回值,这样可以减轻调用者的负担、使错误不会被忽略、增强程序的可维护性。
[3]
(A)忘记保存原始的strDest值,说明答题者逻辑思维不严密。
[4]
(A)循环写成while (*strDest++=*strSrc++);,同[1](B)。
(B)循环写成while (*strSrc!=’\0′) *strDest++=*strSrc++;,说明答题者对边界条件的检查不力。循环体结束后,strDest字符串的末尾没有正确地加上’\0′。
2.返回strDest的原始值使函数能够支持链式表达式,增加了函数的“附加值”。同样功能的函数,如果能合理地提高的可用性,自然就更加理想。
链式表达式的形式如:
int iLength=strlen(strcpy(strA,strB));
又如:
char * strA=strcpy(new char[10],strB);
返回strSrc的原始值是错误的。其一,源字符串肯定是已知的,返回它没有意义。其二,不能支持形如第二例的表达式。其三,为了保护源字符串,形参用const限定strSrc所指的内容,把const char *作为char *返回,类型不符,编译报错。
15. 局部变量能否和全局变量重名
答案:能,局部会屏蔽全局。要用全局变量,需要使用”::”
局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内。
16. 如何引用一个已经定义过的全局变量
答案:extern
可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变理,假定你将那个变写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。
17. 全局变量可不可以定义在可被多个.C文件包含的头文件中 为什么
答案:可以,在不同的C文件中以static形式来声明同名全局变量。
可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错
18. 语句for( ;1 ;)有什么问题 它是什么意思
答案:和while(1)相同。
19. do……while和while……do有什么区别
答案:前一个循环一遍再判断,后一个判断以后再循环
20. static全局变量与普通的全局变量有什么区别 static局部变量和普通局部变量有什么区别 static函数与普通函数有什么区别
答案:全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。 这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序, 当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能 IT人才网(it.ad0.cn) 使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,
因此可以避免在其它源文件中引起错误。
从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域, 限制了它的使用范围。
static函数与普通函数作用域不同。仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件
static全局变量与普通的全局变量有什么区别:static全局变量只初使化一次,防止在其他文件单元中被引用;
static局部变量和普通局部变量有什么区别:static局部变量只被初始化一次,下一次依据上一次结果值;
static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝
21. 队列和栈有什么区别
答案:队列先进先出,栈后进先出
22. 头文件中的 ifndef/define/endif 干什么用?预处理
答案:防止头文件被重复引用
23. #i nclude 和 #i nclude “filename.h”有什么区别?
答案:前者用来包含开发环境提供的库头文件,后者用来包含自己编写的头文件。
24. 在C++ 程序中调用被 C 编译器编译后的函数,为什么要加 extern “C”声明?
答案:函数和变量被C++编译后在符号库中的名字与C语言的不同,被extern “C”修饰的变
量和函数是按照C语言方式编译和连接的。由于编译后的名字不同,C++程序不能直接调
用C 函数。C++提供了一个C 连接交换指定符号extern“C”来解决这个问题。
25. switch()中不允许的数据类型是?
答案:实型
26. C++中为什么用模板类。
答案:(1)可用来创建动态增长和减小的数据结构
(2)它是类型无关的,因此具有很高的可复用性。
(3)它在编译时而不是运行时检查数据类型,保证了类型安全
(4)它是平台无关的,可移植性
(5)可用于基本数据类型
27. C++中什么数据分配在栈或堆中,New分配数据是在近堆还是远堆中?
答案:栈: 存放局部变量,函数调用参数,函数返回值,函数返回地址。由系统管理
堆: 程序运行时动态申请,new 和malloc申请的内存就在堆上
28. 使用线程是如何防止出现大的波峰。
答案:意思是如何防止同时产生大量的线程,方法是使用线程池,线程池具有可以同时提
高调度效率和限制资源使用的好处,线程池中的线程达到最大数时,其他线程就会排队
等候。
29. 函数模板与类模板有什么区别?
答案:函数模板的实例化是由编译程序在处理函数调用时自动完成的,而类模板的实例化
必须由程序员在程序中显式地指定。
30. 一般数据库若出现日志满了,会出现什么情况,是否还能使用?
答案:只能执行查询等读操作,不能执行更改,备份等写操作,原因是任何写操作都要记
录日志。也就是说基本上处于不能使用的状态。
31. SQL Server是否支持行级锁,有什么好处?
答案:支持,设立封锁机制主要是为了对并发操作进行控制,对干扰进行封锁,保证数据
的一致性和准确性,行级封锁确保在用户取得被更新的行到该行进行更新这段时间内不
被其它用户所修改。因而行级锁即可保证数据的一致性又能提高数据操作的迸发性。
32. 如果数据库满了会出现什么情况,是否还能使用?
答案:只能执行查询等读操作,不能执行更改,备份等写操作,原因是任何写操作都要记
录日志。也就是说基本上处于不能使用的状态。
33. 关于内存对齐的问题以及sizof()的输出
答案:编译器自动对齐的原因:为了提高程序的性能,数据结构(尤其是栈)应该尽可能
地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问
;然而,对齐的内存访问仅需要一次访问。
34. int i=10, j=10, k=3; k*=i+j; k最后的值是?
答案:60,此题考察优先级,实际写成: k*=(i+j);,赋值运算符优先级最低
35. 对数据库的一张表进行操作,同时要对另一张表进行操作,如何实现?
答案:将操作多个表的操作放入到事务中进行处理
36. TCP/IP 建立连接的过程?(3-way shake)
答案:在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状
态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个
SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1)
,此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
37. ICMP是什么协议,处于哪一层?
答案:Internet控制报文协议,处于网络层(IP层)
38. 触发器怎么工作的?
答案:触发器主要是通过事件进行触发而被执行的,当对某一表进行诸如UPDATE、 INSERT
、 DELETE 这些操作时,数据库就会自动执行触发器所定义的SQL 语句,从而确保对数
据的处理必须符合由这些SQL 语句所定义的规则。
39. winsock建立连接的主要实现步骤?
答案:服务器端:socker()建立套接字,绑定(bind)并监听(listen),用accept()
等待客户端连接。
客户端:socker()建立套接字,连接(connect)服务器,连接上后使用send()和recv(
),在套接字上写读数据,直至数据交换完毕,closesocket()关闭套接字。
服务器端:accept()发现有客户端连接,建立一个新的套接字,自身重新开始等待连
接。该新产生的套接字使用send()和recv()写读数据,直至数据交换完毕,closesock
et()关闭套接字。
40. 动态连接库的两种方式?
答案:调用一个DLL中的函数有两种方法:
1.载入时动态链接(load-time dynamic linking),模块非常明确调用某个导出函数
,使得他们就像本地函数一样。这需要链接时链接那些函数所在DLL的导入库,导入库向
系统提供了载入DLL时所需的信息及DLL函数定位。
2.运行时动态链接(run-time dynamic linking),运行时可以通过LoadLibrary或Loa
dLibraryEx函数载入DLL。DLL载入后,模块可以通过调用GetProcAddress获取DLL函数的
出口地址,然后就可以通过返回的函数指针调用DLL函数了。如此即可避免导入库文件了

41. 一个32位的机器,该机器的指针是多少位
答案:指针是多少位只要看地址总线的位数就行了。80386以后的机子都是32的数据总线。所以指针的位数就是4个字节了。
42. 关键字volatile有什么含意?并举例?
答案:提示编译器对象的值可能在编译器未监测到的情况下改变。如多线程、多CPU,变量的值可能被其它线程或运行在其它CUP的代码更改。
43. c和c++中的struct有什么不同?
答案:c和c++中struct的主要区别是c中的struct不可以含有成员函数,而c++中的struct可以。c++中struct和class的主要区别在于默认的存取权限不同,struct默认为public,而class默认为private
44. 列举几种进程的同步机制,并比较其优缺点。
答案:原子操作
信号量机制
自旋锁
管程,会合,分布式系统
45. 进程之间通信的途径
答案:共享存储系统
消息传递系统
命名管道
46. 进程死锁的原因
答案:资源竞争及进程推进顺序非法
47. 死锁的4个必要条件
答案:互斥、请求保持、不可剥夺、环路
48. 操作系统中进程调度策略有哪几种?
答案:FCFS(先来先服务),优先级,时间片轮转,多级反馈
49. 类的静态成员和非静态成员有何区别?
答案:类的静态成员每个类只有一个,非静态成员每个对象一个
50. 纯虚函数如何定义?使用时应注意什么?
答案:virtual void f()=0;
是接口,子类必须要实现
51. 数组和链表的区别
答案:数组:数据顺序存储,固定大小
链表:数据可以随机存储,大小可动态改变
52. 线程与进程的区别和联系? 线程是否具有相同的堆栈? dll是否有独立的堆栈?
答案:进程是死的,只是一些资源的集合,真正的程序执行都是线程来完成的,程序启动的时候操作系统就帮你创建了一个主线程。
每个线程有自己的堆栈。
DLL中有没有独立的堆栈,这个问题不好回答,或者说这个问题本身是否有问题。因为DLL中的代码是被某些线程所执行,只有线程拥有堆栈,如果DLL中的代码是EXE中的线程所调用,那么这个时候是不是说这个DLL没有自己独立的堆栈?如果DLL中的代码是由DLL自己创建的线程所执行,那么是不是说DLL有独立的堆栈?
以上讲的是堆栈,如果对于堆来说,每个DLL有自己的堆,所以如果是从DLL中动态分配的内存,最好是从DLL中删除,如果你从DLL中分配内存,然后在EXE中,或者另外一个DLL中删除,很有可能导致程序崩溃

抱歉!评论已关闭.