C++笔试题和面试题(上)——软件测试工程师面试秘籍(21)

发表于:2021-12-22 08:58

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:G.li    来源:51Testing软件测试网原创

  2.6  语言类
  2.6.1  C++笔试题和面试
  试题1.符号常量const char *p、char const *p、char * const p分别表示什么含义?
  分析:如果const位于“*”的左侧,则const用来修饰指针所指向的常量,即指针指向常量。如果const位于“*”的右侧,则const修饰指针本身,即指针本身是常量。
  答案:const char *p和char const *p表示指针指向常量,char * const p表示指针本身是常量。

  试题2.请说明析构函数和虚函数的用法与作用。
  答案:析构函数的作用是当对象生命周期结束时释放对象所占用的资源。析构函数是特殊的类函数,它的名字和类名相同,没有返回值,没有参数,不能随意调用也没有重载,只在类对象生命周期结束时由系统自动调用。虚函数用在继承中,当在派生类中需要重新定义基类中的函数时,需要在基类中将该函数声明为虚函数,作用为使程序支持动态联编。

  试题3.请说明C++中堆和栈的区别。
  答案:栈由编译器自动分配、释放,存放函数的参数值、局部变量值等,其操作方式类似于数据结构中的栈。
  堆一般由程序员分配、释放,若不释放,程序结束时可能由操作系统回收。注意,它与数据结构中的堆是两个概念,但分配方式类似。

  试题4.头文件的作用是什么?
  答案:通过头文件来调用库功能。头文件能加强类型安全检查。

  试题5.内存分配方式有几种?
  答案:内存分配方式有3种。
  (1)从静态存储区域分配。内存在程序编译时已经分配好,这块内存在程序运行期间都存在,如全局变量。
  (2)从栈上分配。运行函数时,函数内部局部变量的存储单元都可以从栈上分配,函数运行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器中,效率高,但是分配的内存容量有限。
  (3)从堆上分配,也称动态内存分配。

  试题6.以下为Windows NT下的32位C++程序,请计算sizeof的值。
Char str[]="Hello";
Char *p=str;
Int n=10

  答案:
sizeof(str)=6
sizeof(p)=4
sizeof(n)=2

  试题7.#include<filename.h>和#include "filename.h"有什么区别?
  答案:对于#include<filename.h>,编译器从标准库路径开始搜索filename.h;对于#include "filename.h",编译器从用户的工作路径中开始搜索filename.h。

  试题8.(a)在以下代码中,运行Test()函数会有什么样的结果?
Void GetMemory(char *p)
{
        P=(char *)malloc(100);
}
Void Test(void)
{
        Char *str=NULL;
        GetMemory(str);
        Strcpy(str,"hello world");
        Printf(str);
}//函数内的变量是独立于main()的,改变它们不会影响main()中的变量

  答案:程序会崩溃,因为GetMemory()并不能传递动态内存,Test()函数中的str一直是NULL。

  (b)在以下代码中,运行Test()函数会有什么样的结果?
Char *GetMemory(void)
{
    Char p[]="hello world";
    Return p;
}
Void Test(void)
{
    Char *str=NULL;
    Str=GetMemory();
    Printf(str);
}

  答案:可能出现乱码。因为GetMemory()返回的是指向“栈内存”的指针,该指针的地址不是NULL,但其原先的内容已经被清除,新内容不知。

  (c)在以下代码中,运行Test()函数会有什么样的结果?
Void GetMemory2(char **p,int num)
{
    *P=(char *)malloc(num);
}
Void Test(void)
{
    Char *str=NULL;
    GetMemory(&str,100);
    Strcpy(str,"hello");
    Printf(str);
}

  答案:能够输出hello,造成内存泄漏。

  (d)在以下代码中,运行Test()函数会有什么样的结果?
Void Test(void)
{
    Char *str=(char *) malloc(100);
    Strcpy(str,"hello");
    Free(str);
    If(str!=NULL)
    {
     Strcpy((str,"world");
      Printf(str);
     }
}

  答案:篡改动态内存区的内容,后果难以预料,非常危险。因为执行Free(str)后,str成为野指针,If(str!=NULL)语句不起作用。

  试题9.请说明引用与指针的区别。
  答案:指针是一个实体,而引用仅是一个别名;引用在使用时无须解引用(*),指针需要引用;引用只能在定义时初始化一次,之后不可变,指针可变;引用没有const,指针有const;“sizeof(引用)”得到的是所指向的变量(对象)的大小,而“sizeof(指针)”得到的是指针本身(所指向的变量或对象的地址)的大小;指针和引用的自增(++)运算的意义不一样;从内存分配上看,程序为指针变量分配内存区域,而引用不需要分配内存区域。

  试题10.请说明sizeof和strlen的区别。
  答案:区别如下。
  (1)sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型,该类型能容纳所建立的最大对象。
  (2)sizeof是运算符,strlen是函数。
  (3)sizeof可以以类型作为参数;strlen只能以char*作为参数,且必须以换行符(\0)结尾。
  (4)strlen的结果要在运行时才能计算出来,用于计算字符串的长度,而不是类型占内存的大小。
  (5)传递给sizeof的参数不退化,传递给strlen的参数退化为指针。

  试题11.请说明malloc与new的区别。
  答案:区别如下。
  (1)new是C++中的操作符,malloc是C中的一个函数。
  (2)new不仅会分配内存,还会调用类的构造函数;同理,delete会调用类析构函数。而malloc只分配内存,不会进行初始化类成员的工作;同样,free也不会调用析构函数。
  (3)内存泄漏对于malloc或者new都可以检查出来,区别在于new可以指明是哪个文件的哪一行导致的,而malloc没有这些信息。
  (4)new等价于malloc加构造函数的执行。
  (5)new返回的指针是直接带类型的信息,而malloc返回的都是void指针。

  试题12.要从双向链表中删除一个节点P,在节点P后插入一个节点,编写两个函数。
  答案:从双向链表中删除一个节点P的代码如下。
Template<class type> void list<type>::delnode(int p)
{
   int k=1;
   listnode<type> *ptr,*t;
   ptr=first;
While(ptr->next!=NULL&&k!=p)
{
      ptr=ptr->next;
      k++;
}
t=ptr->next;
cout <<"你已经将数据项"<<t->data<<"删除"<<endl;
ptr->next=ptr->next->next;
length–;
delte t;
}

  在节点P后插入一个节点的代码如下。
Template<class type> bool list<type>::insert(type t,int p)
{   Listnode<type> *ptr;
    Ptr=first;
    int k=1;
while(ptr!=NULL && k<p)
{
    ptr=ptr->next;
    k++;
}
If(ptr==NULL&&k!=p)
{
    return false;
}
else
{
    Listnode<type> *tp;
    tp=new listnode<type>;
    tp->data=t;
    tp->next=ptr->next;
    ptr->next=tp;
    length++;
    return true;
}
}

  试题13.运行以下代码会产生什么结果?为什么?
Char szstr[10];
Strcpy(szstr,"0123456789");

  答案:正常输出,但两个字符串的长度不一样,会覆盖其他内容。

  试题14.请描述多态的作用。
  答案:不必编写每一子类的功能调用,可以直接把不同子类当作父类,屏蔽子类间的差异,提高代码的通用率/复用率。

  试题15.如何输出当前源文件的名称及源文件的当前行号?
  答案:通常使用_ _FILE_ _和_ _LINE_ _,在调试函数中利用"%s"与"%ld",输出。

  试题16.main()主函数运行完毕后,是否可能会再运行一段代码?给出说明。
  答案:会运行另一些代码,进行处理工作。如果需要加入一段在main()退出后运行的代码,可以使用atexit()函数,注册一个函数。

  试题17.与#define定义的常量相比,const有何优点?
  答案:(1)const有数据类型,而使用#define定义的常量没有数据类型。编译器可以对前者进行类型安全检查;而对后者只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误。
  (2)有些集成化的调试工具可以对const进行调试,但是不能对#define定义的常量进行调试。

  试题18.简述数组与指针的区别。
  答案:区别如下。
  (1)数组要么在静态存储区(如全局数组)中创建,要么在栈上创建。指针可以随时指向任意类型的内存块。
  (2)两者在修改内容上的差别如下。
char a[]="hello";
a[0]='X';
char *p="world"; //p 指向常量字符串
p[0]='X'; //编译器不能发现该错误,运行时出现错误

  (3)用运算符sizeof 可以计算出数组的容量(字节数)。p为指针,sizeof(p)得到的是一个指针变量的字节数,而不是p 所指的内存容量。C++/C无法知道指针所指的内存容量,除非在申请内存时记住它。注意,当作为函数的参数传递数组时,该数组自动退化为同类型的指针。
char a[]="hello world";
char *p=a;
cout<<
cout<<

  计算数组和指针的内存容量。
voidFunc(char a[100])
{
cout<<
 }

  试题19.const的作用是什么?
  答案:(1)可以定义常量。
  (2)const可以修饰函数的参数和返回值,甚至函数的定义体。被const修饰的内容都受到强制保护,可以预防意外的变动,增强程序的健壮性。

  试题20.在C++里如何声明const void f(void)函数为C程序中的库函数?
  答案:在该函数前添加extern"C"声明。由于编译后的名字不同,因为C++程序不能直接调用C函数。


查看《软件测试工程师面试秘籍》全部连载章节
版权声明:51Testing软件测试网获得人民邮电出版社和作者授权连载本书部分章节。
任何个人或单位未获得明确的书面许可,不得对本文内容复制、转载或进行镜像,否则将追究法律责任。
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号