试题21.C++中,关键字struct和class的区别是什么?
答案:struct定义的类的默认成员为公有的,而class定义的类的默认成员为私有的。
试题22.C++函数中值的传递方式有哪几种?
答案:C++函数中值的传递方式有值传递、指针传递和引用传递3种。
试题23.函数模板与类模板有什么区别?
答案:函数模板的实例化是由编译程序在处理函数调用时自动完成的,而类模板的实例化必须由程序员在程序中显式地指定。
试题24.数组a[N]中存放了1~N-1个数,其中某个数重复一次。写一个函数,找出重复的数字,时间复杂度必须为O(N),函数原型为intdo_dup(int a[],int N)。
答案:如果数就是1~N-1,那么求出a[N]的和,然后减去1~N-1即可(确定数字1-N)。
S=N*(N-1)/2;
int i;
int s=0;
for(i=0;i<n;++i)
{
s+=a[i];
}
int res=s–S;</n;++i
试题25.程序由多个模块组成,所有模块都使用一组标准的include文件和相同的编译选项。在这种情况下,要将所有include文件预编译为一个预编译头,代码如下。
char * const p;
charconst * p
const char *p
上述3行代码有什么区别?
答案:
char * const p; //常量指针,p的值不可以修改
char const * p; //指向常量的指针,指向的常量值不可以修改
const char *p; //或者char const *p
试题26.对于无序数组[10,8,9,5,2,8,4,7,1,3],请设计排序算法,要求时间复杂度为O(n),空间复杂度为O(1),使用交换的思路,而且一次只能交换两个数。
答案:
#include
int main()
{
int a[]={10,6,9,5,2,8,4,7,1,3};
intlen=sizeof(a)/sizeof(int);
int temp;
forint i=0; i
{
temp=a[a[i]–1];
a[a[i]–1]=a[i];
a[i]=temp;
if ( a[i]==i+1)
i++;
}
for int j=0;j
cout<<a[j]<<",";
return 0;
}</a[j]<<",";
试题27.写一个函数,比较两个字符串str1和str2的大小。若相等,返回0;若str1大于str2,返回1;若str1小于str2,返回-1。
答案:
intstrcmp ( const char * str1,const char * str2)
{
int ret = 0 ;
while( ! (ret = *(unsigned char *)str1 – *(unsigned char *)str2) && *dst)//字符之差为整型
{
++str1;
++str2;
}
if ( ret < 0 ) ret = -1 ; else if ( ret > 0 )
ret = 1 ;
return( ret );
}
试题28.C++中为什么用模板类?
答案:(1)它可用于创建动态增长和减小的数据结构。
(2)它与类型无关,因此具有很高的可复用性。
(3)它在编译时而不是在运行时检查数据类型,保证了类型安全。
(4)它与平台无关,具有可移植性。
(5)它可用于基本数据类型。
试题29.指出全局变量、所有函数代码、静态变量和局部变量的存储位置。
答案:
全局变量存储在数据段。
所有函数代码存储在代码段。
静态变量存储在数据段或BSS段中。
局域变量存储在栈的静态数组。
试题30.什么是“引用”?声明和使用“引用”要注意哪些问题?
答案:引用就是某个目标变量的“别名”(alias),对引用的操作与直接操作变量的效果完全相同。声明一个引用的时候,切记要对其进行初始化。引用声明完毕后,相当于目标变量有两个名称,即该目标变量原名称和引用名,不能再把该引用名作为其他变量的别名。声明一个引用不是新定义一个变量,它只表示该引用名是目标变量的一个别名。引用不是一种数据类型,因此它不占存储单元,系统也不给引用分配存储单元。不能建立数组的引用。
试题31.使用“引用”传递函数的参数有哪些特点?
答案:(1)传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就作为原来主调函数中的实参或对象的一个别名来使用,所以在被调函数中对形参的操作就是对其相应的目标对象(在主调函数中)的操作。
(2)使用引用传递函数的参数,在内存中并没有产生实参的副本,而直接对实参进行操作。使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参是实参的副本;如果传递的是对象,还将调用构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率更高,所占空间更小。
(3)使用指针作为函数的参数虽然也能达到与使用引用相同的效果,但是在被调函数中同样要给形参分配存储单元,且需要重复使用“*指针变量名”的形式进行运算,这很容易产生错误且程序的阅读性较差。另外,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。
试题32.在什么时候需要使用“常引用”?
答案:如果既要利用引用提高程序的效率,又要保护传递给函数的数据,使其在函数中不改变,就应使用常引用。常引用声明方式为“const类型标识符&引用名=目标变量名”。
例1如下。
int a ;
const int &ra=a;
ra=1; //错误
a=1; //正确
例2如下。
string foo( );
void bar(string&s);
下面的表达式将是非法的。
bar(foo( ));
bar("hello world");
原因在于foo( )和“hello world”字符串都会产生一个临时对象,而在C++中,这些临时对象都是const类型的。上面的表达式试图将一个const类型的对象转换为非const类型,这是非法的。
引用型参数在能定义为const的情况下,应该尽量定义为const。
试题33.引用与多态的关系是什么?
答案:除指针外,引用是另一个可以产生多态效果的手段,这意味着一个基类的引用可以指向它的派生类实例。
试题34.引用与指针的区别是什么?
答案:指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。若在程序中使用指针,程序的可读性差,而引用本身是目标变量的别名,对引用的操作就是对目标变量的操作。
试题35.重载(overload)和重写(overide,也叫覆盖)的区别是什么?
答案:从定义上来说,重载是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同);重写是指子类重新定义父类虚函数的方法。
从实现原理上来说,重载是指编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。例如,如果有两个同名的函数functionfunc(p:integer):integer和functionfunc(p:string):integer,那么编译器做过修饰后的函数名称可能分别是int_func、str_func。对于这两个函数的调用,在编译期间就已经确定了,它们是静态的,即它们的地址在编译期间就绑定了(早绑定)。因此,重载和多态无关。
重写和多态真正相关。当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态地调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,函数地址是在运行期间绑定的(晚绑定)。
试题36.new、delete?与malloc、free?的联系与区别是什么?
答案:它们都在堆(Heap)上进行动态的内存操作。malloc函数需要指定内存分配的字节数并且不能初始化对象,new会自动调用对象的构造函数。delete 会调用对象的析构函数,而free不会调用对象的析构函数。
试题37.类成员函数的重载、重写和隐藏的特征是什么?
答案:重载的特征如下。
(1)范围相同(在同一个类中)。
(2)函数名字相同。
(3)参数不同。
(4)virtual关键字可有可无。
重写是指派生类的函数重写基类的函数,其特征如下。
(1)范围不同(分别位于派生类与基类中)。
(2)函数名字相同。
(3)参数相同。
(4)基类函数必须有virtual 关键字。
隐藏是指派生类的函数屏蔽了与其同名的基类函数,其特征如下。
(1)如果派生类的函数与基类的函数同名,但是参数不同,那么,不论有无virtual关键字,基类的函数都被隐藏(注意,不要与重载混淆)。
(2)如果派生类的函数与基类的函数同名,并且参数相同,但是基类函数没有virtual 关键字,那么基类的函数被隐藏(注意,不要与重写混淆)。
试题38.一个链表的节点结构如下。
struct Node
{
int data ;
Node *next ;
};
typedef struct Node Node ;
(a)已知链表的头节点head,写一个函数把这个链表逆序。
(b)已知两个链表有序head1和head2,请把它们合并成一个链表并依然有序(保留所有节点,即便长度相同)。
答案:(a)要把链表逆序,代码如下。
Node * ReverseList(Node *head) //链表逆序
{
if(head==NULL||head->next==NULL )
return head;
Node *p1=head ;
Node *p2=p1->next ;
Node *p3=p2->next ;
p1->next=NULL ;
while (p3!=NULL )
{
p2->next=p1 ;
p1=p2 ;
p2=p3 ;
p3=p3->next ;
}
p2->next=p1 ;
head=p2 ;
return head ;
}
(b)需合并链表,代码如下。
Node * Merge(Node *head1 , Node *head2)
{
if ( head1==NULL)
return head2;
if ( head2==NULL)
return head1;
Node *head=NULL;
Node *p1=NULL;
Node *p2=NULL;
if(head1->data<head2->data )
{
head=head1;
p1=head1->next;
p2=head2;
}
Else
{
head=head2;
p2=head2->next;
p1=head1;
}
Node *pcurrent=head;
while(p1!=NULL&&p2!=NULL)
{
if(p1->data<=p2->data)
{
pcurrent->next=p1;
pcurrent=p1;
p1=p1->next;
}
Else
{
pcurrent->next=p2;
pcurrent=p2;
p2=p2->next;
}
}
if(p1!=NULL)
pcurrent->next=p1;
if(p2!= NULL)
pcurrent->next=p2;
return head;
}
试题39.全局变量和局部变量在内存中是否有区别?如果有,区别是什么?
答案:有区别。全局变量存储在静态数据区中,局部变量存储在栈中。
试题40.栈溢出一般是由什么原因导致的?
答案:没有回收垃圾资源。
版权声明:51Testing软件测试网获得人民邮电出版社和作者授权连载本书部分章节。
任何个人或单位未获得明确的书面许可,不得对本文内容复制、转载或进行镜像,否则将追究法律责任。