面试问题总结
问题列表:
问题1:指针常量,常量指针和指向常量的常量指针
指针常量(Pointer to const):不能修改指向变量的值,int const *p
常量指针(const Pointer):不能改变指向,不能指向常量,int *const p
指向常量的常量指针(const Pointer to const):不能改变指向,可以指向常量,const int *const p
其中常量是指不能修改。
问题2:重载、重定义、重写的区别
主要区别:
(1)作用域;
(2)参数列表。
不能重载的情况:
(1)函数只有返回值不同;
(2)语意不明,函数参数列表出现多个匹配。
问题3:构造函数和析构函数调用顺序
构造函数:(类间按照继承顺序构造,成员间按声明顺序)
(1)虚拟基类的构造函数;
(2)非虚拟基类的构造函数;
(3)设定虚函数表指针值;
(4)成员对象的构造函数;
(5)类本身的构造函数。
析构函数:由于采用函数栈的形式,因此,析构顺序与构造顺序相反。
问题4:宏定义中的#,##,#@
(1)#:返回字符串
(2)##:表示子串连接
例如:#define Conn(x,y) x##y
(3)#@:返回const char
问题5:利用memset对vector和string等容器初始化
问题6:C++中指针和引用的区别
- 定义和性质区别
- 指针:指针是一个变量,存储的是一个内存地址,指向内存的一个存储单元;通过指针获取这个指针指向的内存中的值称为解引用;引用:是原变量的一个别名(同义词),引用跟原来的变量实质上是同一个东西,它保存着所指对象的存储地址,并且使用的时候会自动解引用。
int a = 1; int *p = &a;int &s = a;
其中,p是指针变量,该指针变量指向整型变量a的存储单元,即p的值是a存储单元的地址;s是整型变量a的引用,a与b在内存中占用同一存储单元 - 引用不可以为空,当被创建的时候必须初始化,而指针可以是空值,可以在任何时候被初始化。
- 指针可以有多级,但是引用只能是一级(int **p;合法 而 int &&a是不合法的)
- 作为参数传递时,指针需要被解引用才可以向对象进行操作,而直接对引用的修改都会改变引用所指向的对象。
- 指针的值可以为空,但是引用的值不能为NULL,并且引用在定义的时候必须初始化;
- 指针的值在初始化后可以改变,即指向其它的存储单元,而引用在进行初始化后就不会再改变了。
- sizeof(引用)得到的是所指向的变量(对象)的大小,而sizeof(指针)得到的是指针本身的大小;
- 如果返回动态内存分配的对象或者内存,必须使用指针,引用可能引起内存泄漏;
- 可以有const指针,但是没有const引用;
- 指针和引用的自增(++)运算意义不一样。
- 指针:指针是一个变量,存储的是一个内存地址,指向内存的一个存储单元;通过指针获取这个指针指向的内存中的值称为解引用;引用:是原变量的一个别名(同义词),引用跟原来的变量实质上是同一个东西,它保存着所指对象的存储地址,并且使用的时候会自动解引用。
- 作为函数参数的区别
函数使用指针传递参数,可以实现对实参进行改变的目的,是因为传递过来的是实参的地址。
// 函数定义
void swap_int(int *a, int *b){ }
void test_int(int *p){ } // 传指针
void test_cite(int &a){ } //传引用
void test_int_cite(int *&p) { } // 传指针的引用
int main(){
int a =1,b = 2;
int *p = &a; //
swap_int(&a,&b); //传地址,函数形参*对地址进行取值
test_int(p); // 传指针变量
test_cite(a);
test_int_cite(a);
return 0;
}
- *a和*b实际上是取存储实参的内存单元里的数据,即是对实参进行改变可以达到目的。
- test_int函数传递的是地址,只不过传递的是指针的地址(变量的地址)。当把指针作为参数进行传递时,也是将实参的一个拷贝传递给形参,即上面程序main函数中的p和test函数中使用的p不是同一个变量,存储2个变量p的单元也不相同(只是2个p指向同一个存储单元),那么在test_int函数中对p进行修改,并不会影响到main函数中的p的值。如果要想达到也同时修改的目的的话,就得使用引用了.
- 引用作为函数参数进行传递时,实质上传递的是实参本身,即传递进来的不是实参的一个拷贝,因此对形参的修改其实是对实参的修改,所以在用引用进行参数传递时,不仅节约时间,而且可以节约空间。
- 如果需要同步修改主函数和函数体中的指针变量,就得使用引用。
问题7:直接调用构造函数和使用new操作符的区别
-
直接调用构造函数
直接调用构造函数,就和普通函数一样按顺序执行。如果构造函数中创建了属性,这个属性会挂载到调用者this所指向的对象上。不用new,也就是普通的函数调用而已,所以若是函数本身没有返回值,普通的函数调用没有什么意义.
this关键字的使用:本质来说,是函数内部的特殊变量 是在函数被调用时,保存了所处的作用域; -
使用new操作符
使用new操作符 + 构造函数,在这种方式调用构造函数时,会执行以下几个步骤:
(1)创建一个新对象;
(2)将构造函数的作用域赋给这个新对象;(this指针就指向了这个对象)
(3)执行构造函数中的代码;(为这个新对象添加属性)
(4)返回这个对象。 -
区别
- new创建类对象需要指针接收;
- new创建类对象使用完需delete销毁;
- new创建对象直接使用堆(heap)空间,而局部不用new定义类对象则使用栈(stack)空间;
- 频繁调用场合并不适合new,就像new申请和释放内存一样、
-
三种创建类对象的方式:
1、 new创建类对象
new创建类对象需要类指针接收
2、不用new,直接使用类定义申明
3、类指针+new
(1)先定义类指针,在new之前并未为该类对象分配任何内存空间,因此如果未经过对象初始化则不需要delete释放;
(2)再使用的时候new。
#include<iostream>
class A {
private:
int a;
int b;
public:
A() {a = 1;b = 2;}
~A(){}
};
int main()
{
A* pA = new A(); // tpye 1
A mA; // type 2
A* pB = NULL; // type 3
pB = new A();
return 0;
}
构造函数返回值的问题(???)
如果一个函数的返回值是引用类型(数组,对象或者函数)的数据,那么这个函数作为构造函数用new运算符执行构造时,运算的结果将被它的返回值取代,这时候,构造函数体内的this值丢失了,取而代之的是被返回的对象;
问题8:代码实现字符串中重复字符和下标的查找
题目描述:给定一字符串,从中找出重复出现的字符,并返回首次重复的下标。
python:
def find_char_in_string(str):
"""
characters are stored in dictionary
format of dictionary :
dict_char = {char : [occurrence number,index]}
"""
dict_char = {}
for i, char in enumerate(str):
if char in dict_char:
dict_char[char][0] += 1
dict_char[char].append(i)
else:
dict_char.update({char: [1, i]}) # dict_char[char] = [1, i]
return dict_char
if __name__ == '__main__':
s = '&acs1234^3123$%^&$#'
d = find_char_in_string(s)
for key, value in d.items():
if value[0] > 1:
print("{}:{}".format(key, value[2]))
C++:
#include <iostream>
#include <vector>
#include <map>
#include <string>
using namespace std;
void count_char_in_string(string s, map<char, vector<int>> &m)
{
for (int i = 0; i < s.length(); i++)
{
map<char, vector<int>> ::iterator it = m.begin();
if (!m.count(s[i]))
{
vector<int> index; //index[0] is occurrence number,[1]、[2]...is index;
index.push_back(1);
index.push_back(i);
m.insert({ s[i], index });
}
else {
it = m.find(s[i]);
it->second.push_back(i);
it->second[0]++;
}
}
}
int main()
{
string str = "&acs1234^3123$%^&$#";;
map<char, vector<int>> map_char;
count_char_in_string(str, map_char);
return 0;
}