c++面试题
- 1. malloc、free和new、delete的区别
- 2. 引用与指针作用以及区别
- 3. const 关键字的作用
- 4. c++什么时候生成构造函数?
- 5. extern 关键字作用
- 6. c_c++中强制类型转换使用场景
- 7. 如何避免野指针?
- 8. static关键字的作用
- 9. c++ 什么是深拷贝?什么是浅拷贝?
- 10. 简述strcpy、sprintf与memcpy的区别?
1. malloc、free和new、delete的区别
语言关联:
malloc 和 free 是C语言中的标准库函数。
new 和 delete 是C++中的操作符。
类型安全:
malloc 返回的是 void* 类型,需要显式类型转换。
new 返回的是确切类型的指针,不需要类型转换,因此更类型安全。
构造和析构:
malloc 只分配内存,不调用构造函数。
new 不仅分配内存,还会调用对象的构造函数。
free 只释放内存,不调用析构函数。
delete 不仅释放内存,还会调用对象的析构函数。
错误处理:
malloc 在内存分配失败时返回
#include <boost/beast/http.hpp>
#include <boost/beast.hpp>
#include <boost/asio.hpp>
#include <memory>
#include <shared_mutex>
#include <iostream>
// 简化作用域声明
namespace beast = boost::beast; // from <boost/beast.hpp>
namespace http = beast::http; // from <boost/beast/http.hpp>
namespace net = boost::asio; // from <boost/asio.hpp>
using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>NULL。
new 在内存分配失败时抛出 std::bad_alloc 异常。
2. 引用与指针作用以及区别
指针更灵活,可以指向nullptr,可以修改指向,
指针通过某个指针变量指向一个变量,对它所指的变量进行简介的操作
指针是对象,指针有地址,可以定义指针的指针(二级指针)
引用更安全,必须在定义时初始化,且与原类型保持一致,且不分配内存。声明关系,一经声明,不可变更。
可对引用,再次引用。多次引用的结果,是某一变量具有多个别名,多个别名间是平行关系。
对引用操作就是直接对目标对象的操作
引用不是对象,没有实际的地址,不能定义引用指针,也不能定义引用的引用(二级引用:没有这种说法)
作用:
引用 : 用在传参时候,避免内存分配,以及对象数据的复制 ; 用在函数返回值,避免对象数据的复制,提高效率
指针 : 用在传参时候,避免对象数据的复制
基类指针可以指向基类对象,也可以指向派生类对象。这种灵活性使得可以通过同一个接口操作不同类型的对象。
通过基类指针调用虚函数时,实际调用的函数是在运行时根据指针所指向的对象类型决定的,这就是动态绑定(dynamic binding)。通过指针调用虚函数比直接调用函数稍微慢一些
代码复用
3. const 关键字的作用
一. 定义变量 :
1.c语言里 : 局部的const (分配到了栈去) 可以使用指针修改 全局的const (分配到了全局区去) 不能修改 (段错误)
2.c++里 : 都不能修改,和符号表有关 (局部const变量在符号表中通常不会占用实际的内存地址,编译器会尽可能将其优化为立即数。全局const变量在符号表中会有一个固定的内存地址,但这个地址指向的是只读数据段。)
作用:1. 避免修改 2. 避免次的内存分配 3. 类型检查 ,作用域检查
二. 修饰指针 : (前定值,后定向) const在*前定值 在*后定向
1. char * const p;
const修饰指针p,表示指针p本身是常量,不能修改指针的指向。
这意味着一旦p被初始化指向某个地址,就不能再指向其他地址。
但是,指针p指向的地址的内容是可以修改的。
2. const char * p;
const修饰char,表示指针p指向的地址的内容是常量,不能修改。
这意味着不能通过指针p修改它所指向的地址的内容。
但是,指针p本身是可以修改的,可以指向其他地址。
3. char const * p;
这种写法与const char * p;是等价的,const修饰char,表示指针p指向的地址的内容是常量,不能修改。
这意味着不能通过指针p修改它所指向的地址的内容。
但是,指针p本身是可以修改的,可以指向其他地址。
4. const char * const p;
const修饰指针p和char,表示指针p本身和指针p指向的地址的内容都是常量,不能修改。
这意味着指针p不能修改指向,也不能通过指针p修改它所指向的地址的内容。
三. 修饰函数参数
可以防止函数内部修改传入的参数。
四. 修饰函数返回值
1. 当函数返回值为基本数据类型(如int、char等)时,使用const修饰返回值通常没有实际意义,
因为基本数据类型的返回值是按值传递的,函数返回后,返回值的副本可以被随意修改。
2. 当函数返回值为指针或引用时,使用const修饰返回值可以防止返回值被修改。
(c++运算符+重载时,const修饰返回值可以防止返回值被修改,避免返回的值是左值,禁止 const a + b = c 这种操作)
四. 修饰类成员函数
1. 常量对象只能调用其const常成员函数。 普通对象可以调用所有成员函数。
2. const修饰类成员函数,表示该成员函数不能修改类成员变量的值。
3. const常成员函数只能调用const常成员函数,不能调用普通成员函数。
(const用来函数重载,const修饰了函数,就视为重载那个函数,形成const版本)
五. 修饰类成员变量
1. 常量成员变量必须在声明时 或 在构造函数的初始化列表中进行初始化(常用),之后不能被修改。 (不能在构造函数体中初始化常量成员变量)
2. 如果常量成员变量是静态的,即属于类而不是对象,那么它的声明和定义方式略有不同。静态常量成员变量需要在类外部进行定义和初始化。
class MyClass {
public:
static const int staticConstValue; // 静态常量成员变量声明
};
// 静态常量成员变量定义和初始化
const int MyClass::staticConstValue = 10;
4. c++什么时候生成构造函数?
1. 空的类定义不会生成构造函数
2. 如果一个类没有显式定义任何构造函数,编译器会自动生成一个默认构造函数。
3. 如果一个类定义了一个带有默认参数的构造函数,编译器不会自动生成默认构造函数。但是,如果该构造函数的所有参数都有默认值,那么它可以被视为默认构造函数。
1. 类a内数据成员是对象b ,而b提供了默认构造函数,为了让b的构造函数
2. 类A的基类提供了默认构造函数,A必须生成构造函数
3. 类内定义了虚函数 为了实现多态机制,需要为类维护虚函数表 ,类所有对象保存一个指向虚函数表的指针,这将在构造函数初始化;
5. extern 关键字作用
extern关键字主要用于声明变量或函数是定义在另一个文件中,或者在同一个文件的其他位置。它告诉编译器该变量或函数在其他地方有定义。
extern的主要作用是管理跨文件的符号可见性,是在多文件程序中引用全局变量和函数的关键工具。
extern常用于在一个源文件中引用另一个源文件中定义的全局变量。
对于函数,extern通常是隐式的,因为默认情况下,函数的声明和定义都具有extern链接特性。因此,我们一般不需要显式地使用extern,但是在某些情况下,可以使用它来强调函数的外部链接。
c++调用 c
// C++文件
extern "C" {
void cFunction(); // 声明一个C风格的函数
}
6. c_c++中强制类型转换使用场景
staic_cast : 用于基本数据类型之间的转换,如int转float,double转int等
空指针转换为目标类型的空指针
将非const转换为const
不安全的向下转型
const_cast : 用于去除常量性,如将const int转为int 去掉指针引用的const;目的用于修改指针引用的权限
reinterpret_cast : 用于指针之间的转换,如将int*转为char*等
改变引用,指针的类型 转换为整形 , 将整形转换引用或指针
(指针,整形,引用,函数指针,成员指针)
无安全检查
dynamic_cast : 用于类之间的转换,如基类转派生类等
向下转型,运行时进行检测的类型转换, 引用 转换失败会抛出bad_cast异常
作用于指针引用
基类指针 指向派生类对象
7. 如何避免野指针?
1. 初始化指针:在声明指针变量时,尽量立即对其进行初始化。如果暂时没有合适的初始值,可以将其初始化为NULL或nullptr(在C++11及以后)。
2. 使用指针操作对象之前,检查是否为指针对象分配内存
3. 及时释放内存:在使用动态内存分配函数(如malloc、calloc、realloc、new等)分配内存后,如果不再需要这些内存,应及时使用free或delete释放内存,并将指针设置为NULL或nullptr。
4. 在C种需要对空间数据置空 memset
5. 避免重复释放:确保每个动态分配的内存只被释放一次,重复释放同一块内存会导致未定义行为。
6. 使用智能指针:在C++中,可以使用智能指针(如std::unique_ptr、std::shared_ptr)来自动管理内存,避免手动管理内存带来的风险。
7. 避免返回局部变量的地址:函数内部声明的局部变量在函数返回后会被销毁,因此不要返回这些变量的地址。
8. static关键字的作用
static关键字修饰的东西 : 变量 函数
1. static 修饰的东西在函数体中时,其作用范围只存在此函数体中,其他函数不能访问到
2. static 修饰的东西在模块内(cpp/h) ,
在cpp源文件声明,作用范围是此源文件,其他模块源文件声明相同名称的static不冲突;
声明在头文件(.h),其他包含 此头文件的都可以访问statc修饰的东西
3. static在类中 :
以下都为整个类所有:(属于类而不是类的实例)
(1),修饰成员变量 所有对象共享同一个静态成员变量。
(2),修饰成员函数 (不接收this指针) 静态成员函数不能访问非静态成员变量和非静态成员函数。
9. c++ 什么是深拷贝?什么是浅拷贝?
浅拷贝:
浅拷贝在复制对象时,只复制对象中的基本数据类型成员和指针值,而不复制指针指向的内存内容。这意味着复制后的对象中的指针将与原对象共享同一块内存。
如果某个对象被析构,而该对象的指针指向的内存也被释放,那么其他共享同一内存的对象可能会访问已释放的内存,导致未定义行为甚至程序崩溃。这种情况称为“双重释放”(double free)。
在C++中,如果没有为类定义自定义的拷贝构造函数,编译器提供的默认拷贝构造函数就是浅拷贝。
深拷贝:
深拷贝不仅复制对象中的基本数据类型成员,还会为指针指向的内存区域分配新内存,并复制内存中的实际内容。这样,复制后的对象拥有独立的内存,不与原对象共享。
需要自定义拷贝构造函数和赋值操作符,以实现深拷贝逻辑,对每个指针成员做内存分配和内容复制。
避免了浅拷贝中的重复释放问题,因为每个对象拥有自己的内存副本。
10. 简述strcpy、sprintf与memcpy的区别?
他们都能实现字符串拷贝功能
strcpy 将源字符串复制到目标字符串中,只适用于以\0结尾的字符串,复制时会自动添加终止符\0。
目标字符串必须有足够的空间来容纳源字符串及其终止符。
sprintf 将格式化的数据写入字符串中。类似于printf,但输出到字符串而不是标准输出。
支持多种格式化选项,如整数、浮点数、字符串等。 目标字符串必须有足够的空间来容纳格式化后的数据及其终止符。
memcpy 复制源内存块到目标内存块中。适用于任意类型的数据,不仅仅是字符串。
不会自动添加终止符\0。 目标内存块必须有足够的空间来容纳源内存块。
原文地址:https://blog.csdn.net/gopher9511/article/details/142353346
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!