C++常见面试题

1、声明和定义区别:声明不等于定义,声明只是指出了变量的名字,并没有为其分配存储空间;定义指出变量名字同时为变量分配存储空间,定义包含了声明。

2、malloc 和 new  区别:new是操作符,可以重载,new的时候会调用构造函数,delete的时候会调用析构函数,malloc是库函数,不会调用构造析构函数。new可以不用指定分配大小,malloc必须指定。使用malloc分配内存后,发现内存不足的时候,可以realloc重新分配内存,new不能。new分配成功返回对象类型指针,malloc返回void*,需要强制类型转换。

3、delete与 delete []区别:delete只会调用一次析构函数,而delete[]会调用每一个成员的析构函数。

4、内存分配方式:,
1、 全局/静态/常量存储区,是在程序编译时就已经分配好的,在整个运行期间都存在,如全局变量、静态局部变量、静态全局变量、常量。
2、 栈上分配,由编译器在需要的时候分配,在不需要的时候自动清除,局部变量、函数参数就是从这分配的,但分配的内存容易有限。对于栈来讲,它的生长方式是向下的,是向着内存地址减小的方向增长。在vc编译器中,默认的栈大小是1M,可自己修改。
3、 堆上分配,也称动态分配,由new,malloc分配内存,他们的释放编译器不管,用delete,free来释放的内存。如果没有释放掉,程序结束后,操作系统会自动回收。对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;一般来讲,在32为系统下面,堆内存可达到4G的空间。(注:堆是操作系统维护的一块内存,它提供了动态分配的功能,而自由存储是C++中通过new与delete动态分配和释放对象的抽象概念。基本上,所有的C++编译器默认使用堆来实现自由存储,但也可以不用堆实现。)

3、内存空间划分:
 1) 栈区:栈中保存基本数据类型的变量和自定义对象的引用(不是对象,对象本身放堆区),被执行的方法的也是pull到栈中,当方法执行完后再push出栈。比如局部变量
 2) 堆区:Test t = new Test(); 对象的引用t存在栈中,new Test()对象在堆中。堆中存储的都是对象,每个对象包含一个与之对应的class信息。
 3) 代码区:函数、类中的方法,存在代码区。
 4) 全局数据区:静态变量、全局变量、常量。类的static变量是全局的,是类的所有对象都能访问的,非static变量是私有的,是每个对象独有的特有的,并且只有非static方法才可以访问。

4、堆和栈的主要区别由以下几点:
 1)、管理方式不同;
 2)、空间大小不同;
 3)、能否产生碎片不同;
 4)、生长方向不同;
 5)、分配方式不同;
 6)、分配效率不同;

5、把局部变量改为静态变量,是改变了变量的生存期。把全局变量改为静态变量,是改变变量的作用域,限定为当前文件使用。static全局变量只初始化一次,防止在其他文件被引用。

6、extern变量称为外部存储变量,要使用在其他文件定义的全局变量,可以用extern或者引用头文件。用头文件方式,如果变量写错了,编译期间报错,用extern方式,链接期间才报错。

7、常量指针:const char *p和指针常量char *  const p; 的区别:如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。const char 没有顺序区分。

8、字符数组和字符串:

  char a[] = “hello”;
  a[0] = ‘X’;
  char *p = “world”; // 注意p 指向字符串常量
  p[0] = ‘X’; // 编译器不能发现该错误,运行时错误

9、引用与指针有什么区别:指针是一个新的变量,存储了另一个变量的地址,我们可以通过访问这个地址来修改另一个变量;引用只是一个别名,还是变量本身,对引用的任何操作就是对变量本身进行操作,以达到修改变量的目的。

10、extern "C" 用于告诉C++这段代码是告诉编译器按C语言方式编译代码。因为C++编译后函数名会变得很长(加各种符号),与C生成的不一致,导致引用函数时,找不到函数。
如:extern "C" 使用封装DLL后,通过函数指针引用函数时 和 在C++包含C函数或C头文件时使用。

11、头文件""和<>区别:对于#include <filename.h> ,编译器从标准库路径开始搜索 filename.h
对于#include "filename.h",编译器从用户的工作路径开始搜索 filename.h

12、指针数组,指向数组的指针,函数返回值为指针,指向函数的函数指针,

 int *p[n];—–指针数组,每个元素均为指向整型数据的指针。
 int (*)p[n];—p为指向一维数组的指针,这个一维数组有n个整型数据。
 int *p();——定义一个函数,返回值为int型指针,参数为空。
 int (*p)();—-定义一个函数指针:函数返回int,参数为空。

13、this指针:是一个const指针,指向的是当前对象,只能用在类的内部,通过他可以访问当前对象所有成员。只有对象被创建后,通过调用成员函数时,才给this赋值,是编译器自动完成的。就是说this在成员函数的开始执行前构造,在成员的执行结束后清除。(this 实际上是成员函数的一个形参,在调用成员函数时将对象的地址作为实参传递给 this。不过 this 这个形参是隐式的,它并不出现在代码中,而是在编译阶段由编译器默默地将它添加到参数列表中。)在全局函数、静态成员函数中都不能用this,因为他们是通过类调用的,不是通过对象。
this指针的使用:一种情况就是,在类的非静态成员函数中返回类对象本身的时候,直接使用 return *this;另外一种情况是当形参数与成员变量名相同时用于区分,如this->n = n (不能写成n = n)

14、野指针不是NULL指针,是未初始化或者未清零的指针,它指向的内存地址不是程序员所期望的,可能指向了受限的内存。

15、sizeof 结构体(按顺序计算每个成员偏移量,偏移量必须是当前成员类型的倍数,再计算最后成员偏移量+最后成员大小,最后判断是否需要补充为最大类型的整数倍)、类对象大小(和结构体一样,静态变量和成员函数不计算大小,他们存储在数据区和代码区)

16、#define和const的区别
  1)#define定义的常量没有类型,所给出的是一个立即数;const定义的常量有类型名字,存放在静态区域
  2)处理阶段不同,#define定义的宏变量在预处理时进行替换,可能有多个拷贝,const所定义的变量在编译时确定其值,只有一个拷贝。
  3)#define定义的常量是不可以用指针去指向,const定义的常量可以用指针去指向该常量的地址
  4)#define可以定义简单的函数,const不可以定义函数

17、实现回调函数的两种方法:

一、函数指针。
1)定义函数指针 typedef bool (* pFunc)(char *p, void *pParam);
2)定义函数中使用函数指针 void test(int x, pFunc *pF) { ...; pF("daf", &x); };
3)实现函数指针 bool Output(char *p, void *pParam) {}
4)使用test函数 test(2, Output);

二、函数对象

class Demo
{
public:
    Demo() {};
    ~Demo() {};
public:
    template <class T> 
    T operator() (T t) const 
    { 
        return t * t; 
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    Demo d;
    cout << d(3.14);
    return 0;
}

18、虚函数:虚函数的作用主要是实现多态的机制。关于多态就是用父类型的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。纯虚函数:类中有纯虚函数,则不能生成对象,派生类中必须重载虚函数,才能生成对象。构造函数不能是虚函数,析构函数常常是虚函数。若类中使用了虚拟函数,析构函数一定要是虚拟函数,C++默认的析构函数不是虚函数,而是只有当需要当作父类时,设置为虚函数。

19、实现strcpy函数

char * strcpy( char *strDest, const char *strSrc )
{
    assert( (strDest != NULL) && (strSrc != NULL) );
    char *address = strDest;
    while( (*strDest++ = * strSrc++) != '\0' );
    return address;
}

20、实现String类

#include <string.h>
#include <assert.h>

class String
{
public:
    String(char *str = NULL);
    String(const String &other);
    String &operator=(const String &other);
    ~String();
protected:
private:
    char *m_data;
};

String::String(char *str /* = NULL */)
{
    m_data = NULL;
    if (str == NULL)
    {
        m_data = new char[1];
        assert(m_data != NULL);
        *m_data = '\0';
    } 
    else
    {
        int len = strlen(str);
        m_data = new char[len + 1];
        assert(m_data != NULL);
        strcpy(m_data, str);
    }
}

String::~String()
{
    delete m_data;
}

String::String(const String &other)
{
    int len = strlen(other.m_data);
    m_data = new char[len + 1];
    assert(m_data != NULL);
    strcpy(m_data, other.m_data);
}

String &String::operator=(const String &other)
{
    if (this == &other)
    {
        return *this;
    }
    delete m_data;
    int len = strlen(other.m_data);
    m_data = new char[len + 1];
    assert(m_data != NULL);
    strcpy(m_data, other.m_data);
    return *this;
}

21、用#define实现 交换x, y的值
#define swap(x, y) x = x + y; y = x - y; x = x - y;


21、实现函数:查找1到N-1 中,重复的数,总数为N个
int do_dup(int a[], int N)
{
    int sum1 = 0, sum2 = 0;
    for (int i = 0; i < N; i++)
    {
        sum1 += a[i];
        sum2 += i + 1;
    }

    return N - (sum2 - sum1);
}

22、用#define实现 计算数组元素个数
#define N_KEYWORD(Array) (sizeof(Array) / sizeof(Array[0]))  

23、假如数组long T[16]; T地址为0x00d7f888,则long *p = T + 5; p地址为:0x00d7f89c。因为long在32位程序是4字节,64位程序8字节。

24、sizeof 和 strlen 计算数组或字符串的区别

 char p1[220] = "dafsa";
 char *p2 = "dafsa";
 int x1 = sizeof(p1);         // 输出:220
 int x2 = sizeof(p2);         // 输出:4
 int x3 = sizeof("dafsa");     // 输出:6
 int x4 = strlen(p1);         // 输出:5
 int x5 = strlen(p2);         // 输出:5
 int x6 = strlen("dafsa");     // 输出:5

25、 实现一个算法,确定一个字符串的所有字符是否全都不同
bool isUniqueChars(char *str)
{
    int length = strlen(str);
    if (length > 256)
        return false;
    bool charSet[256] = { false };  //声明一个bool数组
    for (int i = 0; i < length; i++) {
        int var = str[i];       //将第i个字符对应的ASCII值作为布尔数组的索引值
        if (charSet[var])
            return false;
        charSet[var] = true;
    }
    return true;
}

26、爬楼梯算法
假设你正在爬楼梯,需要n步你才能到达顶部。但每次只能爬一步或者两步,你能有多少种不同方法爬到顶部?
/*爬楼梯问题其实就是斐波那契数列*/
递归法:
int func(int n)
{
    return (n == 1 || n == 2) ? n : func(n - 2) + func(n - 1);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值