C++ one hundred 面试题

题目类型

a.C++与C差异(1-18)

1.C和C++中struct有什么区别?

C没有Protection行为,不能定义函数,但可以有函数指针。

C++有Protection行为,默认是public(class默认private),可以定义函数;

2.C++中的struct和class有什么区别?

struct可以class所有功能,本质上是一个东西,struct成员和继承默认是public,class成员和继承默认是private。

3.如何判断一个程序是由c编译程序还是由C++编译程序编译的?

判断:检测宏

#ifdef __cpluspluc

cout<<"c++";

#else

printf("c“);

#endif

4.C和C++有什么不同?

机制上:C面向过程的(但也可编写面向对象);C++编写面向对象的程序比C容易

适用的方向:c适合要求代码体积小的,效率高的场合,如嵌入式;C++更适合上层的,复杂的

C语言是结构化编程语言,C++是面向对象编程语言。

C++侧重于对象而不是过程,侧重于类的设计而不是逻辑的设计。

5.“引用”与指针的区别是什么?

指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。

6.虚函数

虚函数是可以通过接口继承的

7.int id[sizeof(unsigned long)];这个对吗?

8.某文件定义静态全局变量,他的作用域。

静态全局变量只在源文件内有效,避免引用出错。类里面的静态变量可以不用实例化。C++没有静态类。

9.C++值的传递

三种:值传递,指针传递,引用传递

10.频繁使用的短小函数,C语言和C++?

C用宏定义#define,C++用inline函数(一般函数浪费的是调用和返回的时间)

11.引用和指针的差别?

引用须被初始化,指针不必。(C++11引用是可以改变的)

引用初始化不能被改变,但指针可以改变所指对象。

不存在指向空值的引用,但是存在指向空值的指针。

12.virtual与inline的含义分别是什么?

virtual意味着声明为虚函数,inline与函数定义体放在一起,使该函数称为内联。inline是一种用于实现的关键字,而不是用于声明的关键字。

虚函数的特点:如果希望派生类能够重新定义基类的方法,则在基类中将该方法定义为虚方法,这样可以启用动态联编。(多继承下只产生一个虚基类)

动态联编 和 静态联编

http://blog.csdn.net/gaoxin1076/article/details/8298279

内联函数的特点:使用内联函数的目的是为了提高函数的运行效率。

内联函数体的代码不能过长,因为内联函数省去调用函数的时间是以代码膨胀为代价的。

内联函数不能包含循环语句,因为执行循环语句要比调用函数的开销大。

13.VC中,编译工具Debug与Release选项是什么含义?

Debug通常称为调试版本,包含调试信息,不做优化,便于程序员调试进程。Release称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。Debug带有大量的挑调试代码和信息,运行需要相应的库,发布模式程序紧凑不含有调试代码和信息,可以直接运行(不需要运行库)。

14.函数assert的用法?

断言assert是仅在debug版本起作用的宏,用于检查“不应该”发生的情况。程序员可以把assert看成是一个任何系统状态下都可以安全使用的无害测试手段。

15.const与#define的比较,const有什么优点?

const常量有数据类型(定义不读内存),而宏常量没有数据类型,编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误(边际效应)

有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。

16.谈谈引用和指针的区别:

引用被创建的同时必须被初始化(指针可以在任何时候初始化)

不能有NULL引用,左值引用必须与合法的存储单元关联(指针可以是NULL)内存,右值引用引用寄存器。

一旦引用被初始化,就不能改变引用的关系(指针可以随时改变所指的对象)

17.有了malloc/free为什么还要new/delete?

malloc/free是C/C++语言的标准函数库,new/delete是C++ 的运算符,它们都可以申请动态内存和释放内存。

由于对象在创建的同时要自动执行构造函数,消亡之前要自动执行析构函数,因为malloc/free是库函数而不是运算符,不在编译器的控制权之内,不能把任务强加于malloc/free。因此需要一个能完成动态内存分配和初始化的运算符new,以及一个能清理和释放内存工作的运算符delete。

new可以把内存开在静态区,防止内存泄漏。

18.如果再申请动态内存找不到足够大的内存块,malloc和new将返回NULL指针,宣告内存申请失败。你是怎么处理内存耗尽的?

判断指针是否为NULL,是则马上return语句终止函数

判断指针是否为NULL,是则马上用exit(1)终止程序运行

为new和malloc设置异常处理函数。 例如Visual C++可以用_set_new_hander函数为new设置用户自己定义的异常处理函数,也可以让malloc享用与new 相同的异常处理函数。

#include big *p; p = new(std::nothrow) big[1000];

b.数据类型、关键字(19-37)

19.C++是不是类型安全的?

不是,两个不同类型的指针是可以强制转换的(用reinterpret cast)

20.const符号常量(1)const char *p(2)char const *p(3)char * const p 区别

(1)p是一个指向const char 的指针,p是可以改变指向的,但是p指向的值时不能改变的。

(2)p指向的恰好是一个指向const的char的普通指针。

(3)p是一个指针,这个指针是指向char的const指针,

(1)和(2)的定义是一样的,*左边值不能改变,*右边指针不能改变

21.用C++写个程序,如何判断一个操作系统是16位、32位?

定义一个指针,sizeof(p),4是32位,2是16位,如果64位系统兼容32位的话也是4字节

22.用C++写个程序,如何判断一个操作系统是16位、32位?不用sizeof()函数

int a = ~0;

if(a>65535){ cout<<"32"bit<

else{ cout<<"16"bit<

23.void *(*(*fp1)(int))[10]; float(*(* fp2)(int,int,int))(int); int(*(*fp3)())[10]();

(1)void *(*(*fp1)(int))[10]; fp1是一个指针,指向一个函数,这个函数的参数为int型,函数的返回值是一个指针,这个指针指向一个数组,这个数组有10个元素,每个元素是一个void*型指针。

(2)float(*(* fp2)(int,int,int))(int); fp2是一个指针,指向一个函数,这个函数的参数为3个int型,函数的返回值是一个指针,这个指针指向一个函数,这个函数的参数为int型,函数的返回值是float型。

(3)int(*(*fp3)())[10]();fp3是一个指针,指向一个函数,这个函数的参数为空,函数的返回值是一个指针,这个指针指向一个数组,这个数组有10个元素,每个元素是一个指针,指向一个函数,这个参数为空,函数的返回值是int型。

24.多态类中的虚函数表示Compile-Time,还是Run-Time时建立的?

虚拟函数表是在编译期就建立了,各个虚拟函数这时被组织成了一个虚拟函数的入口地址的数组。而对象的隐藏成员--虚拟函数表指针是在运行期--也就是构造函数被调用时进行初始化,这是实现多态的关键。(动态联编)

25.错误的转义字符'\091'八进制不能有9

26。数组名做实参,指针变量做形参,传数组名传过去的是数组的第一个元素地址

27.变量的指针指的是变量的地址

28.内存的分配方式有几种?

在四个地方分配内存1.静态存储区域。2.栈上创建。3.堆上动态内存分配。4.代码区

a从静态存储区分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量。

b在栈上创建。在执行函数时,函数内部局部变量的存储单元都可以在栈上创建,,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

c在堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也多。

栈连续,堆不连续(链表)

29.float a,b,c,问等式(a+b)+c==(b+a)+c 和 (a+b)+c==(a+c)+b能否成立?

两者都不行。在比较float或double时,不能简单地比较。由于计算误差,相等的概率很低。应判断两数之差是否落在区间(-e,e)内。这个e应比浮点数的精度大一个数量级。

30.全局变量和局部变量有什么区别?是怎么实现的?操作系统和编译器是怎么知道的?

生命周期不同:全局变量随主程序创建而创建,随主程序的销毁而销毁;

局部变量在局部函数内,甚至局部循环体等内部存在,退出就不存在;

内存中分配在全局数据区

使用方式不同:通过声明后全局变量程序的各个部分都可以用到;

局部变量只能在局部使用;

分配在栈区。

操作系统和编译器通过内存分配的位置来知道的,

全局变量分配在全局数据段并且在程序开始运行的时候被加载。

局部变量则分配在堆栈里面。

31.Heap与Stack 的差别

Heap是堆,Stack是栈(高效地节约内存,用完就马上释放)。

Stack的空间由操作系统自动分配/释放,Heap上的空间手动分配/释放

Stack空间有限,Heap是很大的只有存储区

C中的malloc函数分配的内存空间即在堆上,C++中对应的是new操作符

程序在编译期对变量和函数 分配内存都在栈上进行,且程序运行过程中函数调用时参数的传递也在栈上进行。

32.explict protected

explict关键字用来修饰类的构造函数,表明该构造函数是显式的,在某些情况下,我们要求类的使用者必须显示调用类的构造函数时就需要使用explicit,反之默认类型转换可能会造成无法预期的问题。

protected控制的是一个函数对一个类的成员(包括成员变量及成员方法)的访问权限。protected成员只有该类的成员函数及其派生类的成员可以访问。

33.重复多次fclose一个打开过一次的FILE *fp指针会有什么后果,解释

考察点:导致文件描述符结构中指针指向的内存被重复释放,进而导致一些不可预期的异常。

34.为什么数组名作为参数,会改变数组的内容,而其他类型如int却不会改变变量的值?

数组名为参数时,传递的实际上是地址。而其他类型如int作为参数时,由于函数参数值实质上是实参的一份拷贝,被调函数内部对形参的改变并不影响实参的值。

35.你觉得如果不使用常量,直接在程序中填写数字或字符串,将会有什么麻烦?

(1)程序的可读性(可理解性)变差。程序员自己会忘记那些数字或字符串是什么意思,用户则更加不知它们从何处来、表示什么。

(2)在程序的很多地方输入同样的数字或字符串,难保不发生书写错误。

(3)如果要修改数字或字符串,则会在很多地方改动,既麻烦又容易出错。

36.为什么需要使用堆,使用堆空间的原因?

直到运行时才知道一个对象需要多少内存空间;不知道对象的生存期到底有多长。

37.const关键字?有哪些作用?

(1)欲阻止一个变量被改变,可以使用const关键字。在定义该const变量时,通常需要对它进行初始化,因为以后就没有机会再去改变它了;

(2)对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const;

(3)在一个函数声明中,const可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值;(4)对于类的成员函数,若指定其为const类型,则表明其实一个常函数,不能修改类的成员变量;

(5)对于类的成员函数,有时候必须指定其返回值为const类型,以使得其返回值不为“左值”。

c.面型对象的特性(38-61)

38.是不是一个父类写了一个virtual函数,如果子类覆盖它的函数不加virtual,也能实现多态?

virtual修饰符会被隐形继承的。virtual可加不可加。子类的空间里有父类的所有变量(static除外)。同一个函数只存在一个实体(inline除外)。子类覆盖它的函数不加virtual,也能实现多态。在子类的空间里,有父类的私有变量。私有变量不能直接访问。

39.面向对象的三个基本特征,并简单叙述?

(1)封装:将客观事物抽象成类,每个类对自身的数据和方法实行protection(private,protected,public)

(2)继承:广义的继承有三种形式:实现继承(指使用基类的属性和方法而无需额外编码的能力)、可视继承(子窗体使用父窗体的外观和实现代码)、接口继承(仅使用属性和方法,实现滞后到子类实现)。

前两种(类继承)和后一种(对象组合=>接口继承以及纯虚函数)构成了功能复用的两种方式。

(3)多态:是将父对象设置成为和一个或更多的与他的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。

40.重载(overload)、重写(override,有的叫覆盖)、重定义(redefinition)的区别?

名称名字空间区别

重载同一名字空间是指允许存在多个同名函数,而这些函数的参数表不同

重定义/隐藏不同名字空间用于继承,派生类与基类的函数同名,屏蔽基类的函数

重写/覆盖不同名字空间用于继承,子类重新定义父类虚函数的方法

41.多态的作用?

主要的是两个:

(1)隐藏实现细节,使得代码能够模块化;扩展代码模块,实现代码重用;

(2)接口重用:为了类在继承和派生的时候,保证使用家族中任一类的实例的某一属性时的正确调用。

42.当一个类A中没有声明任何成员变量与成员函数,这时sizeof(A)的值时多少?如果不是零,请解释一下编译器为什么没有让它为零?

sizeof(A)=1

一个空类对象的大小是1byte。这是被编译器安插进去的一个字节,这样就使得这个空类的两个实例得以在内存中配置独一无二的地址。

43.如果ClassA中定义并实现虚函数int func(void),ClassB中也实现该函数,那么上述变量a->func()将调用哪个类里面的函数?如果int func(void)不是虚函数,情况又如何?为什么?

第一问是调用B的。第二问是调用A的。虚函数的一个典型应用,虚函数只能借助于指针或者引用来达到多态的效果

44.C++里面是不是所有的动作都是main()函数引起的?如果不是请举例

class A{};

A a; //a的构造函数限执行

int main(){}

45.内联函数在编译的时候是否做参数类型检查?

内联函数要做参数类型检查,这是内联函数跟宏相比的优势。

46.讲一讲析构函数和虚函数的用法和作用?

析构函数是特殊的类成员函数,它没有返回类型,没有参数,不能随意调用,也没有重载,只有在类对象的生命期结束的时候,系统自动调用。有释放内存空间的作用。(析构函数可以是虚函数,构造函数不行)

虚函数是C++多态的一种表现,使用虚函数,我们可以灵活的进行动态绑定,当然是以一定的开销为代价。

47.“new" in C++ is a: operator

malloc是库函数,不在编译器的控制范围之内;

new是运算符,从堆中申请内存;调用new时,从堆中申请内存并为内存调用构造函数。

48. 对于C++中类(class)与结构(struct)的描述正确的为:

D 结构和类对象都可以用new创建

49.类内部成员函数可以用private函数。

50.A对调用的虚函数和模板类都进行迟后编译,调用需要时间

B virtual,派生类必须要求名字相同,参数类型相同,但是返回类型可以不同

C inline内联函数可以是虚函数。静态成员函数不能是虚函数(因为不需要实例化就可以调用),友元函数,构造函数不能是虚函数,析构函数可以。

51.C++中有没有纯虚构造函数?

构造函数不能是虚的,只能有虚的析构函数。

52.throw表达式

(1)class  exception Type{};

throw exception Type();//函数需要括号

(2)enum mathErr { overflow, underflow, zeroDivide };

throw zeroDivide;//枚举不需要括号

53.谈谈你怎么认识C++ 的模板的?

模板使程序员能够快速建立具有类型安全的类库集合和函数集合,它的实现,方便了大规模的软件开发。(结合stl更好)

54.在C++的一个类中声明一个static成员变量有没有用?

在C++类的成员变量被声明为static(称为静态成员变量),意味着它为该类的所有实例所共享,也就是说当某个类的实例修改了该静态成员变量,也就是说不管创建多少对象,static修饰的变量只占有一块内存。其修改值为该类的其他所有实例所见;而类的静态成员 函数也只能访问静态成员(变量或函数)。static是加了访问控制的全局变量,不被继承。

55.C++中为什么要用模板类。

(1)可用来创建动态增长和减小的数据结构.

(2)它是类型无关的,因此具有很高的可复用性。

(3)它在编译时而不是运行时检查数据类型,保证了类型安全

(4)它是平台无关的,可移植性

(5)可用于基本数据类型

56.函数模板与类模板有什么区别?联系?

函数模板的实例化是由编译程序在处理函数调用时自动完成的

类模板的实例化必须由程序员在程序中显示地指定

57.

58.谈谈 在类中如何使用const的?

有时我们希望某些常量只在类中有效。由于#define定义的宏常量是全局的,不能达到目的,于是想当然地觉得应该用const修饰数据成员来实现。const数据成员的确是存在的,但其含义却不是我们所期望的。const数据成员只在某个对象生存期内是常量,而对于整个类而言却是可变的,因为类可以创建多个对象,不同的对象其const数据成员的值可以不同。不能在类声明中初始化const数据成员。

const数据成员的初始化只能在类构造函数的初始化表中进行。

59.函数重载,靠什么来区分调用的哪个函数,靠返回值判断可以不可以?

如果同名函数的参数不同(包括类型、顺序不同),那么容易区别出它们是不同的。如果同名函数仅仅是返回值类型不同,有时可以区分,有时却不能,例如:

void func(void);与int func(void);

C/C++程序中,可以忽略函数的返回值,但是这种情况下,编译器和程序员都不知道哪个func函数被调用,所以只能靠参数而不能靠返回值类型的不同来区分重载函数。

60.所有运算符都能重载吗?

有一些不行。这种限制是出于安全方面的考虑,可防止错误和混乱。

(1)不能改变C++内部数据类型(如int,float等)的运算符。

(2)不能重载'.',因为'.'在类中对任何成员都有意义,已经成为标准用法。

(3)不能重载目前C++运算符集合中没有的符号,如#,@,$等。

原因有两点,一是难以理解,二是难以确定优先级。

(4)对已经存在的运算符进行重载时,不能改变优先级规则,否则将引起混乱。

61.基类的析构函数不是虚函数,会带来什么问题?

派生类的西沟函数用不上,会造成资源的泄漏。

d.程序阅读题(62-90)

62.main函数执行以前,还会执行什么代码?

全局对象的构造函数会在main函数之前执行

63.不使用判断,找出a和b中最大值。

((a+b)+abs(a-b))/2

64.如何打印出当前源文件的文件名以及源文件的当前行号?

cout << __FILE__;

cout << __LINE__;

__FILE__和__LINE__是由系统预定义宏,这种宏并不是在某个文件中定义的,而是由编译器定义的。(C也有)

65下面有两种if语句判断方式。请问哪种写法更好?为什么?

int n;

if(n==10)//第一种

if(10==n)//第二种

这是一个风格问题,第二种方式如果少了个=号,编译时就会报错,减少了出错的可能性,可以检测出是否少了=。

66.写出运行结果:

{char str[]="word";cout<

char *p=str;cout<

char i=10;cout<

void *pp=malloc(10);cout<

6:4:1:4

67.不用第三方参数的情况下,交换两个参数的值。

(1)异或

(2)a=a+b; b=a-b; a=a-b;

68.以下代码如果有错,请改正,并写出输出结果?

main(void)

{int nArrLength(400), i=546;//命名上有问题

for(int i=0;i<99999999999;i++);//考对变量的越界理解,改为unsigned int a=~((int)0)/2,整数0取反,

cout<

cout<

69.int i=5,b=7;

cout<<(i+++b)<

不用调试,说出在gcc编译后的结果;

(i++ +b) 12

70.写一个能作为左值的函数(方法有很多)。

如:max(x,y) +=2874+55;    drwline(x,y)++;

int &max(int &x, int &y){

return x>y?x:y;

}

int x=55,y=77;

max(x,y)+=12+11;

cout<<"x="<

71.

class human{

public:

~human(){cout<<"human over...."<

void Disp(){cout<<"human disp...."<

};

class man:public human{

public:

~man(){cout<<"man over...."<

void Disp(){cout<<"man disp...."<

};

int main(){

human *p = new man;

p->Disp();

delete p;

return 0;

}

human disp....

human over....

72.下面的函数实现在一个固定的数上加上一个数,有什么错误,改正:

int add_n(int n){

static int i=100;

i+=n;

return i;}

因为static使得i的值会保留上次的值。以后的i会一直更新,使得第二次调用出现错误。

去掉static即可

73.unsigned short array[]={1,2,3,4,5,6,7};

int i=3;

cout<<*(array+i)<

4

74.写一个函数当参数为n(n很大)时的值1-2+3-4+5-6+7....+n.

long fn(long n)

{if(n<-0){printf("error:n >must >0");exit(1);}

if(0==n%2) return(n/2)*(-1);

else return (n/2)*(-1)+n;}

75.字符指针、浮点数指针、以及函数指针这三种类型的变量哪个占用内存最大?为什么?

指针变量也占用内存单元,而且所有指针变量占用内存单元的数量都是相同的。就是说,不管是指向何种对象的指针变量,它们占用内存的字节数都是一样的,并且要足够把程序中所能用到的最大地址表示出来(通常是一个机器字长)。4

76.以下三条输出语句输出

char str1[] = "abc";

char str2[] = "abc";

const char str3[] = "abc";

const char str4[] = "abc";

const char* str5 = "abc";

const char* str6 = "abc";

cout<

cout<

cout<

分别输出false,false,true。

str1和str2都是字符数组,每个都有其自己的存储区,它们的值则是各存储区首地址,不等;

str3和str4同上,只是按const语义,它们所指向的数据区不能修改。

str5和str6并非数组而是字符指针,并不分配存储区,其后的“abc”以常量形式存于静态数据区,而它们自己仅是指向该区首地址的指针,相等。

77.以下代码有什么问题?

(true?1:“1”)<

三元表达式“?:” 问号后面的两个操作数必须为同一类型。

78.能够编译

unsigned int const size1 = 2;

char str1[size1];

unsigned int temp = 0;

cin >> temp;

unsigned int const size2 = temp;

char str2[size2];

str2定义出错,size2非编译器期间常量,而数组定义要求长度必须为编译器常量。

79.以下代码输出语句为0吗?为什么?

struct CLS{

int m_i;

CLS(int i):m_i(i){}

// m_i没有初始化

CLS()

{

CLS(0);

}

};

CLS obj;

cout<

不能。在默认构造函数内部再调用带参的构造函数属用户行为而非编译器行为, 亦即仅执行函数调用,而不会执行其后的初始化表达式。只有在生成对象时,初始化表达式才会随相应的构造函数调用。

80.死循环

while(1){} 或 for(;1;;)

81.

int a=5,b=7,c;

c = a+++b;

a=6,b=7,c=12

82.在排序方法中,关键码比较次数与记录地初始排列无关的是() 选择排序

83.代码

void func(){static int val; ...}中,变量val的内存地址位于:A。已初始化数据段

84 入栈

85.判断表达式,写出a的值

int a = 4;

A.a+=(a++); B.a+=(++a); C.(a++)+=a;D.(++a)+=(a++);

a++是个右值,C错; 可改成(++a)=+a;答案:9,10,10,11

86.谈谈如何使用return语句

(1)return语句不可返回指向"栈内存"的“指针”或者“引用”,因为该内存在函数体结束时被自动销毁。

(2)要搞清楚返回的究竟是“值”、“指针”还是“引用”。

(3)如果函数返回值是一个对象,要考虑return语句的效率。

87.(1)return String(s1+s2); 和(2)String temp(s1+s2);return temp;一样吗?

(1)是临时对象的语法,表示“创建一个临时对象并返回它”。

(2)将发生三件事:

首先,temp对象被创建,同时完成初始化;

然后拷贝构造函数把temp拷贝到保存返回值的外部存储单元中;

最后,temp在函数结束时被销毁(调用析构函数)。

然而“创建一个临时对象并返回它”的过程是不同的,编译器直接把临时对象创建并初始化在外部存储单元中,省去了拷贝和析构的花费,提高了效率

88.下列程序的运行结果

const char *str="vermeer";

int main()

{const char *pstr=str;

cout<

vermeer

89.inline void max_out(int val1,int val2)

{ cout<<(val1>val2)?val1:val2;}

int main(){

int ix=10,jx=20;

cout<

cout<

max_out(ix,jx);}

<<优先级大于?优先级,所以输出的是(val1>val2)

90.  int max(int *ia, int sz);

int max(int *,int =10);

算函数重载?还是重复声明?

如果在两个函数的参数表中只有缺省实参不同则第二个声明被视为第一个的重复声明。

e.编程练习(91-100)

91.被置1的位的个数。

unsigned int One0(char log)

{

int  il

unsigned int num=0,val;

for(i=0;i<8;i++)

{val=log>>i;//移位

val &= 0x01;//与1相与

if(val) num++;}

return num;}

92.十六进制组成的字符串转换成十进制数字并返回

bool HexToDec(char* shex,int& idec)

{

int i,mid;

int len = strlen(shex);

if(len>8) return false;

mid=0, idec=0;

for(i=0;i

{

if(shex[i]>='0' && shex[i]<='9')

mid = shex[i]-'0';

else if(shex[i]>='a'&&shex[i]<='f')

mid = shex[i]-'a'+10;

else if(shex[i]>='A'&&shex[i]<='F')

mid = shex[i]-'A'+10;

else

return false;

mid <<= ((len-i-1)<<2);//移位表示变为2的n次方倍

idec =idec+mid;

}

return true;

}

93.字符串逆序输出

第一种:

void main()

{

char a[50];

memset(a,0,sizeof(a));

int i=0,j;

char t;

cin.geiline(a,50,'\n');

for(i=0,j=strlen(a)-1;i

{ t=a[i];a[i]=a[j];a[j]=t;}

}

第二种:

string str;

cin>>str;

str.replace;

cout<

94.编写一个算法frequency,统计在一个输入字符串中各个不同字符出现的频度。用适当的测试数据来验证这个算法。

void frequency(string& s,char A[],int C[],int& k)

{

int i,j,len=s.length();

if(!len){cout<<"empty"<

else{

A[0]=s[0];C[0]=1;k=1; /*语句s[i]是串的重载操作*/

for(i=1;i

for(i=1;i

{ //检测串中所有字符

j=0;while(j

if(j==k)

{A[k]=s[i];C[k]++;k++;}  //s[i]从未检测过

else C[j]++; //s[i]已经检测过

}

}

}

95.假设以数组Q[m]存放循环队列中的元素,同时以rear和length分别指示环形队列中的队尾位置和队列中所含元素的个数。试给出该循环队列的队空条件和队满条件,并写 出相应的插入(enqueue)和删除(dlqueue)元素的操作。

#include

template class Queue {    //循环队列的类定义

public:

Queue ( int=10 );

~Queue ( ) { delete [ ] elements; }

void EnQueue ( Type & item );

Type DeQueue ( );

Type GetFront ( );

void MakeEmpty ( ) { length = 0; }    //置空队列

int IsEmpty ( ) const { return length == 0; }  //判队列空否

int IsFull ( ) const { return length == maxSize; }  //判队列满否

private:

int rear, length;      //队尾指针和队列长度

Type *elements;      //存放队列元素的数组

int maxSize;      //队列最大可容纳元素个数

}

template

Queue:: Queue ( int sz ) : rear (maxSize-1), length (0), maxSize (sz) {

//建立一个最大具有maxSize个元素的空队列。

elements = new Type[maxSize];  //创建队列空间

assert ( elements != 0 );    //断言: 动态存储分配成功与否

}

template

void Queue :: EnQueue ( Type &item ) {

assert ( ! IsFull ( ) );    //判队列是否不满,满则出错处理

length++;      //长度加1

rear = ( rear +1) % maxSize;  //队尾位置进1

elements[rear] = item;    //进队列

}

template

Type Queue :: DeQueue ( ) {

assert ( ! IsEmpty ( ) );    //判断队列是否不空,空则出错处理

length--;      //队列长度减1

return elements[(rear-length+maxSize) % maxSize];  //返回原队头元素值

}

读取队头元素值函数

template

Type Queue :: GetFront ( ) {

assert ( ! IsEmpty ( ) );

return elements[(rear-length+1+maxSize) % maxSize];  //返回队头元素值

}

96.已知A[n]为整数数组,试写出实现下列算法的递归算法:

(1) 求数组 A 中的最大整数。

(2) 求 n 个整数的和。

(3) 求 n 个整数的平均值。

#include

class RecurveArray  //数组类声明

{

private:

int *Elements; //数组指针

int ArraySize; //数组尺寸

int CurrentSize; //当前已有数组元素个数

public :

RecurveArray (int MaxSize =10 ) : ArraySize ( MaxSize ), Elements ( new int[MaxSize] ) { }

~RecurveArray ( )

{

delete [ ] Elements;

}

void InputArray(); //输入数组的内容

int MaxKey ( int n ); //求最大值

int Sum ( int n ); //求数组元素之和

float Average ( int n ); //求数组元素的平均值

};

void RecurveArray :: InputArray ( )  //输入数组的内容

{

cout << "Input the number of Array: \n";

for ( int i = 0; i < ArraySize; i++ )

cin >> Elements[i];

}

int RecurveArray :: MaxKey ( int n )  //递归求最大值

{

if ( n == 1 ) return Elements[0];

int temp = MaxKey ( n - 1 );

if ( Elements[n-1] > temp )

return Elements[n-1];

else return temp;

}

int RecurveArray :: Sum ( int n )

{

//递归求数组之和

if ( n == 1) return Elements[0];

else return Elements[n-1] + Sum (n-1);

}

float RecurveArray :: Average ( int n )

{

//递归求数组的平均值

if ( n == 1) return (float) Elements[0];

else return ( (float) Elements[n-1] + ( n - 1) * Average ( n - 1 ) ) / n;

}

int main ( int argc, char* argv [ ] )

{

int size = -1;

cout << "No. of the Elements : ";

while ( size < 1 ) cin >> size;

RecurveArray ra ( size );

ra.InputArray();

cout<< "\nThe max is: " << ra.MaxKey ( ra.MaxSize ) << endl;

cout<< "\nThe sum is: " << ra.Sum ( ra.MaxSize ) << endl;

cout<< "\nthe avr is: " << ra.Average ( ra.MaxSize ) << endl;

return 0;

}

97.已知f为单链表的表头指针,链表中存储的都是整型数据,试写出实现下列运算的递归算法:

#include //定义在头文件中

class List;

class ListNode  //链表结点类

{

friend class List;

private:

int data; //结点数据

ListNode *link; //结点指针

ListNode ( const int item ) : data(item), link(NULL) { } //构造函数

};

class List  //链表类

{

private:

ListNode *first, current;

int Max ( ListNode *f );

int Num ( ListNode *f );

float Avg ( ListNode *f, int& n );

public:

List ( ) : first(NULL), current (NULL) { } //构造函数

~List ( ) { } //析构函数

ListNode* NewNode ( const int item ); //创建链表结点, 其值为

item void NewList ( const int retvalue ); //建立链表, 以输入 retvalue 结束

void PrintList ( ); //输出链表所有结点数据

int GetMax ( )

{

return Max ( first );    //求链表所有数据的最大值

}

int GetNum ( )

{

return Num ( first );    //求链表中数据个数

}

float GetAvg ( )

{

return Avg ( first );    //求链表所有数据的平均值

}

};

ListNode* List :: NewNode ( const int item )  //创建新链表结点

{

ListNode *newnode = new ListNode (item);

return newnode;

}

void List :: NewList ( const int retvalue )  //建立链表, 以输入 retvalue 结束

{

first = NULL;

int value;

ListNode *q;

cout <<"Input your data:\n"; //提示

cin >>value; //输入

while ( value != retvalue )  //输入有效

{

q = NewNode ( value ); //建立包含 value 的新结点

if ( first == NULL ) first = current = q; //空表时, 新结点成为链表第一个结点

else

{

current-> link = q; //非空表时, 新结点链入链尾

current = q;

}

cin >>value; //再输入

}

current->link = NULL; //链尾封闭

}

void List :: PrintList ( )  //输出链表

{

cout<< "\nThe List is :\n";

ListNode *p = first;

while ( p != NULL )

{

cout

p = p->link;

}

cout <<'\n';

}

int List :: Max ( ListNode *f )  //递归算法 : 求链表中的最大值

if ( f -> link == NULL ) return f -> data; //递归结束条件

int temp = Max ( f -> link ); //在当前结点的后继链表中求最大值

if ( f -> data > temp ) return f ->data; //如果当前结点的值还要大, 返回当前检点值

else return temp; //否则返回后继链表中的最大值

} int List :: Num ( ListNode *f )  //递归算法 : 求链表中结点个数

{

if ( f == NULL ) return 0; //空表, 返回 0

return 1+ Num ( f -> link ); //否则, 返回后继链表结点个数加 1

}

float List :: Avg ( ListNode *f , int& n )  //递归算法 : 求链表中所有元素的平均值

{

if ( f -> link == NULL ) //链表中只有一个结点, 递归结束条件

{

n = 1;

return ( float ) (f -> data );

}

else

{

float Sum = Avg ( f -> link, n ) * n;

n++;

return ( f -> data + Sum ) / n;

}

}

#include "RecurveList.h" //定义在主文件中

int main ( int argc, char* argv[ ] )

{

List test;

int finished;

cout <<"输入建表结束标志数据 : ";

cin >> finished; //输入建表结束标志数据

{

test.NewList ( finished ); //建立链表

test.PrintList ( ); //打印链表

cout <<"\nThe Max is :"<

cout <<"\nThe Num is :"<

cout <<"\nThe Ave is :"<

printf ( "Hello World!\n" );

return 0;

}

}

98.字符串的替换操作replace (String &s, String &t, String &v)是指:

若t是s的子串,则用串v替换串t在串s中的所有出现;若t不是s的子串,则串s不变。例如,若串s为“aabbabcbaabaaacbab”,串t为“bab”,串v为“abdc”,则执行replace操作后,串s中的结果为“aababdccbaabaaacabdc”。试利用字符串的基本运算实现这个替换操作。

String & String :: Replace ( String & t, String &v)

{

if ( ( int id = Find ( t ) ) == -1 ) //没有找到,当前字符串不改,返回

{

cout << "The (replace) operation failed." << endl;

return *this;

}

String temp( ch ); //用当前串建立一个空的临时字符串

ch[0] = '\0';

curLen = 0; //当前串作为结果串,初始为空

int j, k = 0, l; //存放结果串的指针

while ( id != -1 )

{

for ( j = 0; j < id; j++) ch[k++] = temp.ch[j];

curLen += id + v.curLen; //修改结果串连接后的长度

if ( curLen <= maxLen ) l = v.curLen; //确定替换串v传送字符数l

else

{

l = curLen - maxLen;

curLen = maxLen;

}

for ( j = 0; j < l; j++ ) ch[k++] = v.ch[j]; //连接替换串v到结果串ch后面

if ( curLen == maxLen ) break; //字符串超出范围

for ( j = id + t.curLen; j < temp.curLen; j++ )

temp.ch[j- id - t.curLen] = temp.ch[j]; //删改原来的字符串

temp.curLen -= ( id + t.curLen );

id = temp.Find ( t );

}

return *this;

}

99.试编写一个求解Josephus问题的函数。用整数序列1, 2, 3, ……, n表示顺序围坐在圆桌周围的人,并采用数组表示作为求解过程中使用的数据结构。然后使用n = 9, s = 1, m = 5,以及n = 9, s = 1, m = 0,或者n = 9, s = 1, m = 10作为输入数据,检查你的程序的正确性和健壮性。

void Josephus( int A[ ], int n, s, m )

{

int i, j, k, tmp;

if ( m == 0 )

{

cout << "m = 0是无效的参数!" << endl;

return;

}

for ( i = 0; i < n; i++ ) A[i] = i + 1; /*初始化,执行n次*/

i = s - 1; /*报名起始位置*/

for ( k = n; k > 1; i-- ){/*逐个出局,执行n-1次*/

if ( i == k ) i = 0;

i = ( i + m - 1 ) % k; /*寻找出局位置*/

if ( i != k-1 )

{

tmp = A[i]; /*出局者交换到第k-1位置*/

for ( j = i; j < k-1; j++ ) A[j] = A[j+1];

A[k-1] = tmp;

}

}

for ( k = 0; k < n / 2; k++ ){/*全部逆置, 得到出局序列*/

tmp = A[k];

A[k] = A[n-k+1];

A[n-k+1] = tmp;

}

}

100.class String

{

public:

String(const char *str = NULL); // 普通构造函数

String(const String &other); // 拷贝构造函数

~ String(void); // 析构函数

String & operate =(const String &other); // 赋值函数

private:

char *m_data; // 用于保存字符串

};

请编写String的上述4个函数。

// String 的析构函数

String::~String(void)

{

delete [] m_data;

// 由于m_data 是内部数据类型,也可以写成 delete m_data;

}

// String 的普通构造函数

String::String(const char *str)

{

if(str==NULL)

{

m_data = new char[1]; // 若能加 NULL 判断则更好

*m_data = ‘\0’;

}

else

{

int length = strlen(str);

m_data = new char[length+1]; // 若能加 NULL 判断则更好

strcpy(m_data, str);

}

}

// 拷贝构造函数

String::String(const String &other)

{

int length = strlen(other.m_data);

m_data = new char[length+1]; // 若能加 NULL 判断则更好

strcpy(m_data, other.m_data);

}

// 赋值函数

String & String::operate =(const String &other)

{

// (1) 检查自赋值

if(this == &other)

return *this;

// (2) 释放原有的内存资源

delete [] m_data;

// (3)分配新的内存资源,并复制内容

int length = strlen(other.m_data);

m_data = new char[length+1]; // 若能加 NULL 判断则更好

strcpy(m_data, other.m_data);

// (4)返回本对象的引用

return *this;

}

你可能感兴趣的:(C++ one hundred 面试题)