c++经典面试题

来源:互联网 发布:比较好的vpn 知乎 编辑:程序博客网 时间:2024/06/07 00:17

1、头文件中的 ifndef/define/endif 干什么用?

答:防止该头文件被重复引用。

 

2、#include <filename.h> 和 #include “filename.h” 有什么区别?

答:对于#include <filename.h> ,编译器从标准库路径开始搜索 filename.h

对于#include “filename.h” ,编译器从用户的工作路径开始搜索 filename.h

 

3、const 有什么用途?(请至少说明两种)

答:(1)可以定义 const 常量,(2)const 可以修饰函数的参数、返回值,甚至函数的定义体。被const 修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。

 

4、在C++ 程序中调用被 C 编译器编译后的函数,为什么要加 extern “C”?

答:C++语言支持函数重载,C 语言不支持函数重载。函数被C++编译后在库中的名字与C 语言的不同。假设某个函数的原型为: void foo(int x, int y);该函数被C 编译器编译后在库中的名字为_foo , 而C++编译器则会产生像_foo_int_int之类的名字。C++提供了C 连接交换指定符号extern“C”来解决名字匹配问题。

 

5、请简述以下两个for 循环的优缺点

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

{

    if(condition)

       DoSomething();

    else

       DoOtherthing();

}

优点:程序简洁

缺点:多执行了N-1 次逻辑判断,并且打断了循环“流水线”作业,使得编译器不能对循环进行优化处理,降低了效率。

 

if (condition)

{

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

       DoSomething();

}

else

{

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

   DoOtherthing();

}

优点:循环的效率高

缺点:程序不简洁

 

6.

void GetMemory(char *p)

{

   p = (char*)malloc(100);

}

void Test(void)

{

    char *str= NULL;

   GetMemory(str);

    strcpy(str,"hello world");

   printf(str);

}

请问运行Test 函数会有什么样的结果?

答:程序崩溃。

因为GetMemory 并不能传递动态内存,Test 函数中的 str 一直都是 NULL。strcpy(str,"hello world");将使程序崩溃。

 

7.

char *GetMemory(void)

{

    char p[] ="hello world";

    return p;

}

void Test(void)

{

    char *str= NULL;

    str =GetMemory();

   printf(str);

}

请问运行Test 函数会有什么样的结果?

答:可能是乱码。

因为GetMemory 返回的是指向“栈内存”的指针,该指针的地址不是 NULL,但其原现的内容已经被清除,新内容不可知。

 

8.

void GetMemory2(char **p, int num)

{

    *p = (char*)malloc(num);

}

void Test(void)

{

    char *str= NULL;

    GetMemory(&str,100);

   strcpy(str, "hello");

   printf(str);

}

请问运行Test 函数会有什么样的结果?

答:(1)能够输出hello;(2)内存泄漏

 

9.

void Test(void)

{

    char *str= (char *) malloc(100);

   strcpy(str, “hello”);

    free(str);

    if(str !=NULL)

    {

       strcpy(str, “world”);

       printf(str);

    }

}

请问运行Test 函数会有什么样的结果?

答:篡改动态内存区的内容,后果难以预料,非常危险。

因为free(str);之后,str 成为野指针,if(str != NULL)语句不起作用。

 

10.编写strcpy 函数

已知strcpy 函数的原型是

char *strcpy(char *strDest, const char *strSrc);

其中strDest 是目的字符串,strSrc 是源字符串。

(1)不调用C++/C 的字符串库函数,请编写函数 strcpy

char *strcpy(char *strDest, const char *strSrc);

{

   assert((strDest!=NULL) && (strSrc !=NULL)); 

    char*address = strDest; 

    while((*strDest++ = *strSrc++) != '\0' ) 

         NULL;

    returnaddress ; 

}

(2)strcpy 能把strSrc 的内容复制到strDest,为什么还要char * 类型的返回值?

答:为了实现链式表达式。 

例如 int length = strlen( strcpy( strDest, “hello world”) );

 

11.编写类String 的构造函数、析构函数和赋值函数

已知类String 的原型为:

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

    {

        intlength = 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;

}