C++秋招记录(一)
面试题目
以c++指针、数组、引用为主
一、指针、引用
1、指针和引用的区别:
总结:
- 引用是别名,指针实体(指针保存的是指向对象的地址,引用相当于变量的别名)
- 引用必须初始化(可以存着空指针,不能存着空引用,相对而言引用更加安全)
- 从一而终(引用初始化后不可修改,指针可以修改)
- sizeof引用,得到变量大小;sizeof指针,指针本身大小
- 引用的实现是指针,但是比指针多了类型检查
- 引用的创建不会调用类的拷贝构造函数
相同点:
1). 都是地址的概念;
2). 都是“指向”一块内存。指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名;
3). 引用在内部实现其实是借助指针来实现的,一些场合下引用可以替代指针,比如作为函数形参。
不同点:
1). 指针是一个实体,而引用(看起来,这点很重要)仅是个别名;
2). 引用只能在定义时被初始化一次,之后不可变;指针可变;
3). 引用不能为空,指针可以为空;
4). “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身的大小;
5). 指针和引用的自增(++)运算意义不一样;
6). 引用是类型安全的,而指针不是 (引用比指针多了类型检查)
7). 引用具有更好的可读性和实用性。
2、数组与指针的区别?
- 创建内存区域:
数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。指针可以随时指向任意类型的内存块。 - 用运算符sizeof:
sizeof 可以计算出数组的容量(字节数)。sizeof指针得到的是指针变量的字节数,而不是p所指变量的内存容量。C++/C语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。char a[] = “hello world”; char *p = a; cout<< sizeof(a) << endl; // 12 字节 cout<< sizeof(p) << endl; // 4 字节
- 当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。
//计算数组和指针的内存容量 void Func(char a[100]) { cout<< sizeof(a) << endl; // 4 字节而不是100 字节 }
3、将“引用”作为函数参数有哪些特点?
值传递
(1)传递引用给函数与传递指针的效果是一样的。被调函数的形参就成为原来调用函数中的实参变量或对象的一个别名来使用。
(2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数(值传递),当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。
(3)使用指针作为函数的参数虽然也能达到与使用引用的效果,需要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。
4、将“引用”作为函数返回值类型的格式、好处和需要遵守的规则?
格式:类型标识符 &函数名(形参列表及类型说明){ //函数体 }
好处:在内存中不产生被返回值的副本;(注意:正是因为这点原因,所以返回一个局部变量的引用是不可取的。因为随着该局部变量生存期的结束,相应的引用也会失效
注意事项:
(1)不能返回局部变量的引用。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知状态。
(2)不能返回函数内部new分配的内存的引用。虽然不存在局部变量的被动销毁问题,可返回函数内部new分配内存的引用,又面临memory leak。例如被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak。
(3)可以返回类成员的引用,但最好是const。如果其它对象可以获得该属性的非常量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。
(4)流操作符重载返回值申明为“引用”的作用:在程序中,流操作符>>和<<经常连续使用。因此这两个操作符的返回值应该是一个仍旧支持这两个操作符的流引用。其他的数据类型都无法做到这一点。注意:除了在赋值操作符和流操作符之外的其他的一些操作符中,如+、-、*、/等却千万不能返回引用。因为这四个操作符的对象都是右值,因此,它们必须构造一个对象作为返回值
5、char数组创建
6、指针常量和常量指针
const离谁近谁的值不可更改
指针常量——指针类型的常量(int *const p)
- 本质上一个常量,指针用来说明常量的类型,表示该常量是一个指针类型的常量。
- 指针自身的值是一个常量,不可改变,始终指向同一个地址。在定义的同时必须初始化。
- 用法如下:
int a = 10, b = 20;
int * const p = &a;
*p = 30; // p指向的地址是一定的,但其内容可以修改
常量指针——指向“常量”的指针(const int *p, int const *p)
- 常量指针本质上是一个指针
- 常量表示指针指向的内容,说明该指针指向一个“常量”。
- 指针指向的内容是不可改变的,指针看起来好像指向了一个常量。
- 用法如下:
int a = 10, b = 20;
const int *p = &a;
p = &b; // 指针可以指向其他地址,但是内容不可以改变
7、函数指针、指针函数
- 函数指针:本质是指针,该指针指向函数地址入口
int (*fun)(int a,int b);
int add(int a,int b);
//地址赋值:
fun=add; //fun=&add;
//调用方法:
(*fun)(2,3); //fun(2,3);
- 指针函数:本质函数,返回值为指针
int* fun(int a,int b); //括号优先级大于*
8、强引用、弱引用
其实就是share_ptr和weak_ptr(见STL博客专区)