C/C++ 常见1000道面试题( 70 ) 511.左值和右值 不是很严谨的来说,左值指的是既能够出现在等号左边也能出现在等号右边的变量(或表达式),右值指的则是只能出现在等号右边的变量(或表达式)。举例来说我们定义的变量 a 就是一个左值,而malloc返回的就是一个右值。或者左值就是在程序中能够寻址的东西,右值就是一个具体的真实的值或者对象,没法取到它的地址的东西(不完全准确),因此没法对右值进行赋值,但是右值并非是不可修改的,比如自己定义的class, 可以通过它的成员函数来修改右值。 归纳一下就是:可以取地址的,有名字的,非临时的就是左值不能取地址的,没有名字的,临时的,通常生命周期就在某个表达式之内的就是右值 但是到了 C++11 之后概念变的略微复杂,引入了 lvalue, glvalue, rvalue, xvalue 和 prvalue。具体可以参考 What are rvalues, lvalues, xvalues, glvalues, and prvalues? 512.什么是内存泄漏?面对内存泄漏和指针越界,你有哪些方法?你通常采用哪些方法来避免和减少这类错误? 用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单即为内存泄露。 1). 使用的时候要记得指针的长度.2). malloc的时候得确定在那里free.3). 对指针赋值的时候应该注意被赋值指针需要不需要释放.4). 动态分配内存的指针最好不要再次赋值.5). 在C++中应该优先考虑使用智能指针. 513.C++11 中有哪些智能指针?shared_ptr 的引用计数是如何实现的?unique_ptr 的unique 是如何实现的?make_shared 和 make_unique 的作用?智能指针使用注意事项? C++ 11 中的智能指针有:shared_ptr, unique_ptr 和 weak_ptr。 shared_ptr 的引用计数是存放在堆上的,多个 shared_ptr 的对象的引用计数都指向同一个堆地址。 unique_ptr 中拷贝构造函数和赋值操作符都声明为delete或private。 优先使用 make_shared 和 make_unique 的原因是为了避免内存泄露。参考 C++11 中的 Smart Pointer(shared_ptr/weak_ptr/unique_ptr) 总结 智能指针使用注意事项:不使用相同的内置指针值初始化,或reset多个智能指针不delete get()返回的指针不使用get()初始化或reset另一个智能指针get()返回的智能指针可能变成dangling pointer如果智能指针管理的内存不是new出来的,需要提供删除器 拓展问题shared_ptr 是否线程安全?侵入式智能指针? 514.C和C++的区别? 1). C++是C的超集;2). C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现过程(事务)控制),而对于C++,首要考虑的是如何构造一个对象模型,让这个模型能够契合与之对应的问题域,这样就可以通过对象的状态信息得到输出或实现过程(事务)控制。 http://515.int fun() 和 int fun(void)的区别? 这里考察的是c 中的默认类型机制。在c中,int fun() 会解读为返回值为int(即使前面没有int,也是如此,但是在c++中如果没有返回类型将报错),输入类型和个数没有限制, 而int fun(void)则限制输入类型为一个void。在c++下,这两种情况都会解读为返回int类型,输入void类型。 516.const 有什么用途 主要有三点: 1).定义只读变量,或者常量(只读变量和常量的区别参考下面一条);2).修饰函数的参数和函数的返回值;3).修饰函数的定义体,这里的函数为类的成员函数,被const修饰的成员函数代表不能修改成员变量的值,因此const成员函数只能调用const成员函数, 可以访问非const成员,但是不能修改;4).只读对象。只读对象只能调用const成员函数。
517.在C中用const 能定义真正意义上的常量吗?C++中的const呢? 不能。c中的const仅仅是从编译层来限定,不允许对const 变量进行赋值操作,在运行期是无效的,所以并非是真正的常量(比如通过指针对const变量是可以修改值的),但是c++中是有区别的,c++在编译时会把const常量加入符号表,以后(仍然在编译期)遇到这个变量会从符号表中查找,所以在C++中是不可能修改到const变量的。补充: 1). c中的局部const常量存储在栈空间,全局const常量存在只读存储区,所以全局const常量也是无法修改的,它是一个只读变量。2). 这里需要说明的是,常量并非仅仅是不可修改,而是相对于变量,它的值在编译期已经决定,而不是在运行时决定。3).c++中的const 和宏定义是有区别的,宏是在预编译期直接进行文本替换,而const发生在编译期,是可以进行类型检查和作用域检查的。4).c语言中只有enum可以实现真正的常量。5 ). c++中只有用字面量初始化的const常量会被加入符号表,而变量初始化的const常量依然只是只读变量。6). c++中const成员为只读变量,可以通过指针修改const成员的值,另外const成员变量只能在初始化列表中进行初始化。 下面我们通过代码来看看区别。同样一段代码,在c编译器下,打印结果为*pa = 4,a = 4在c++编译下打印的结果为 *pa = 4, a = 8
另外值得一说的是,由于c++中const常量的值在编译期就已经决定,下面的做法是OK的,但是c中是编译通不过的。
另外 C++ 11 中引入了 constexpr,专门用来表示常量(在此之前 const 即表示只读,也表示常量)。所以在 C++11 以后,建议凡是「常量」语义的场景都使用 constexpr,只对「只读」语义使用 const。对于 constexpr 修饰的函数表示其结果在编译期就可以算出来(前提是为了算出它所依赖的东西也是在编译期可以算出来的)。更多可以参考:C++ const 和 constexpr 的区别。
518.宏和内联(inline)函数的比较? 1). 首先宏是C中引入的一种预处理功能;2). 内联(inline)函数是C++中引入的一个新的关键字;C++中推荐使用内联函数来替代宏代码片段;3). 内联函数将函数体直接扩展到调用内联函数的地方,这样减少了参数压栈,跳转,返回等过程;4). 由于内联发生在编译阶段,所以内联相较宏,是有参数检查和返回值检查的,因此使用起来更为安全;5). 需要注意的是, inline会向编译期提出内联请求,但是是否内联由编译器决定(当然可以通过设置编译器,强制使用内联);6). 由于内联是一种优化方式,在某些情况下,即使没有显示的声明内联,比如定义在class内部的方法,编译器也可能将其作为内联函数。7). 内联函数不能过于复杂,最初C++限定不能有任何形式的循环,不能有过多的条件判断,不能对函数进行取地址操作等,但是现在的编译器几乎没有什么限制,基本都可以实现内联。更多请参考inline关键字 519.C++中有了malloc / free , 为什么还需要 new / delete? 1). malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。2). 对于非内部数据类型(自定义类型)的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。最后补充一点题外话,new 在申请内存的时候就可以初始化(如下代码), 而malloc是不允许的。另外,由于malloc是库函数,需要相应的库支持,因此某些简易的平台可能不支持,但是new就没有这个问题了,因为new是C++语言所自带的运算符。
特别的,在C++中,如下的代码,用new创建一个对象(new 会触发构造函数, delete会触发析构函数),但是malloc仅仅申请了一个空间,所以在C++中引入new和delete来支持面向对象。
520.C和C++中的强制类型转换? C中是直接在变量或者表达式前面加上(小括号括起来的)目标类型来进行转换,一招走天下,操作简单,但是由于太过直接,缺少检查,因此容易发生编译检查不到错误,而人工检查又及其难以发现的情况;而C++中引入了下面四种转换: 1). static_casta. 用于基本类型间的转换b. 不能用于基本类型指针间的转换c. 用于有继承关系类对象间的转换和类指针间的转换2). dynamic_casta. 用于有继承关系的类指针间的转换b. 用于有交叉关系的类指针间的转换c. 具有类型检查的功能d. 需要虚函数的支持3). reinterpret_casta. 用于指针间的类型转换b. 用于整数和指针间的类型转换4). const_casta. 用于去掉变量的const属性b. 转换的目标类型必须是指针或者引用拓展在C++中,普通类型可以通过类型转换构造函数转换为类类型,那么类可以转换为普通类型吗?答案是肯定的。但是在工程应用中一般不用类型转换函数,因为无法抑制隐式的调用类型转换函数(类型转换构造函数可以通过explicit来抑制其被隐式的调用),而隐式调用经常是bug的来源。实际工程中替代的方式是定义一个普通函数,通过显式的调用来达到类型转换的目的。
1000道c/c++经典面试题PDF,进官方交流群
—————————————Linuxc/c++高性能服务器开发网官方3群—————————————–
2024最新激活全家桶教程,稳定运行到2099年,请移步至置顶文章:https://sigusoft.com/99576.html
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。 文章由激活谷谷主-小谷整理,转载请注明出处:https://sigusoft.com/81731.html