1.new、delete、malloc、free关系.
2.delete与 delete []区别
3.对于子类来说,其父类、成员、自身的构造顺序和析构顺序?
4.介绍c++的多态
5.虚函数,纯虚函数
6.什么是“引用”?申明“引用”要注意哪些问题?
8.将“引用”作为函数参数有哪些特点?
9.在什么时候需要使用“常引用”?
10.将“引用”作为函数返回值类型需要遵守的规则?
11.结构与联合有和区别?
12.有哪几种情况只能用intialization list ?
13.引用和指针有什么区别 ?
14.请说出const与#define 相比,有何优点?
15.内存的分配方式有几种?
16.基本类型数据范围(32位机)
17.类里面static和const可以同时修饰成员函数吗?
18.解释早绑定和晚绑定
20.main 主函数执行完毕后,是否可能会再执行一段代码,给出说明?
21.如何判断一段程序是由c编译程序还是由c++编译程序编译的?
22.sizeof与strlen的区别?
23.野指针,空指针和悬垂指针的区别?
24.什么是智能指针?
25.如果虚函数是有效的,那为什么不把所有函数设为虚函数?
26.经常要操作的内存分哪几个类别?
27.举例说明static_cast如何使用?(会编译成cpu指令)
28.举例说明const_cast如何使用?(纯粹是编译器指令)
29.举例说明reinterpret_cast如何使用?(纯粹是编译器指令)
30.举例说明dynamic_cast如何使用?(唯一一个可能在允许时候转换失败)
31.typedef和#define联系和区别
32.内联函数和#define联系和区别
33. 链接指示:extern “C”的作用。
34.虚函数表放在什么地方?
35.模板特化的概念,为什么特化?
36.explicit的作用?
37.内存溢出有哪些因素?
38.举例加说明智能指针?
39.区别仿函数和函数指针
40.相关寄存器
41.相关函数调用约定
42.函数调用过程.(略)
43.静态成员函数为什么不能申明为虚函数
44.模板的实现和声明是否一定要在同一个头文件中,为什么?
45.构造函数和析构函数可以抛出异常吗?
46.STL是如何分配内存的?
47.STL是线程安全的吗?
48.数组和指针的区别?
49.Overload 重载,Override 重写 , Overwrite(Redefine)隐藏
50.请讲述堆和栈的区别
51.区别sprintf,strcpy,memcpy函数
52.面向对象设计SOLID五大原则
答案:
1.new、delete、malloc、free关系.
相同:
①都是在堆上申请内存
②申请的内存都是需要手动释放
区别:
①new/delete是运算符,malloc/free是库函数
②new要提供类型,返回的是指向该类型的指针,malloc只需要提供申请空间大小,返回的是
void*指针
③new/delete在分配空间之后会自动调用构造、析构函数。
2.delete与 delete []区别
①delete只会调用一次析构函数,delete[]会调用每个成员的析构函数。
②对于内置类型,没有析构函数,所以使用delete也不会造成内存泄漏。
③两者本质都是用过operator delete来释放内存。
3.对于子类来说,其父类、成员、自身的构造顺序和析构顺序?
①构造:先父类->再成员(按照申明顺序,如果有vptr,默认最先)->最后自身。
②析构:和上面相反。
4.介绍c++的多态
①多态是对于不同对象接收相同消息时产生不同的动作。
②C++的多态性具体体现在运行和编译两个方面。
③运行时的多态性:通过继承和虚函数来体现。
④编译时的多态性:通过函数和运算符的重载,模板上。
5.虚函数,纯虚函数
虚函数:
①在基类中冠以关键字 virtual 的成员函数。
②允许子类进行重写,是C++运行时多态的方法。
②通过多态调用(基类指针或者基类引用)虚函数,会根据实际类型来调用对应版本。
纯虚函数:
①纯虚函数是在基类通过virtual xxx() = 0保留一个函数名字。
②含有纯虚函数的类是抽象类,不能实例化,只能够被继承。
③继承抽象类的派生类必须实现抽象类的纯虚函数。
④在c++中纯虚函数可以用来实现Java,C#中的接口interface概念。
6.什么是“引用”?申明“引用”要注意哪些问题?
概念:
①引用就是某个目标变量的"别名",对应用的操作与对变量直接操作效果完全相同。
②引用的底层实现是指针。所占内存大小也就是一个指针的大小。
申明:
③引用在申明的时候必须进行初始化,且一旦初始化后就不能"绑定"到其他变量上。
④在类中成员存在引用,必须要在类的构造列表中进行初始化。
⑤不能申明、定义引用数组。//引用是别名,没有自己的内存,定义数组需要申请内存
8.将“引用”作为函数参数有哪些特点?
①传递引用跟传递指针效果一样,在函数中对引用做的改变会影响引用实体变量。
②当传递的变量是所占内存空间较大时候,实参到形参的拷贝是很费时间。如果传递对象还要
调用拷贝构造函数。因此,传递引用时间效率要高!(不适用于内置类型、指针、STL迭代器)
9.在什么时候需要使用“常引用”?
①如果传递引用的数据不希望在函数中改变,就应该使用常引用。
②如果传递实参可能是右值的时候,就必须要使用常引用。(否则会编译错误)
10.将“引用”作为函数返回值类型需要遵守的规则?
①不能返回函数局部非静态变量的引用:局部变量会在函数调用返回后被销毁,因此返回的引
用就是"无所指"的应用,这时未定义的行为。
②尽量不要返回函数内部new出来的空间引用:因为很容易造成内存泄漏(假如函数返回值被
当作临时对象,这个引用所指的内存就无法释放。
③可以返回类成员函数的引用,不过如果外界不改变其属性和状态的话尽量申明为const。
④对于某些无法拷贝的对象要将返回值申明为引用(重载流操作符的时候)。
11.结构与联合有和区别?
①结构和联合都是由不同的数据类型成员组成。
②联合在任何同一时刻都只有一个成员有效(所有成员共用一块内存地址)。结构所有成员都有
自己独有的存放地址。
③对于联合不同成员的赋值会对其他成员造成重写,而结构不同成员赋值是互不影响。
12.有哪几种情况只能用intialization list ?
①当成员含有const、reference时候。
②需要调用基类非默认构造函数时候。
13.引用和指针有什么区别 ?
①引用必须初始化,指针不必。
②引用初始化后不能够重新绑定其他变量,而指针可以重新指向其他变量。
③不存在指向空值的引用,但是存在NULL空指针。
④sizeof(引用)得到的是目标变量大小,sizeof(指针)得到的是指针大小。
⑤有的运算符作用的意义不一样(++,--)
⑥指针有多重指针的概念,而引用没有。
14.请说出const与#define 相比,有何优点?
①const 常量有数据类型,而宏常量是没有数据类型。编译器可以对前者进行类型安全检查,
而后者仅仅进行字符替换,没有类型安全检查,并且在字符替换过程中会产生一些意料不到的
错误。(边际效应)
②有些集成化调试工具可以对const常量进行调试,但是不能对宏常量进行调试。在C++程序
中一般只使用const常量而不是用#define。
15.内存的分配方式有几种?
①从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期
间都存在。例如全局变量。
②在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束
时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配
的内存容量有限。
③从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,
程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵
活,但问题也最多。
16.基本类型数据范围(32位机)
①void : 0byte 无值域
②bool: 1byte true,false
③short: 2byte -2^15~2^15-1
④unsigned short: 2byte 0~2^16-1
⑤int 4byte -2^31~2^31-1
⑥unsigned int: 4byte 0~2^32-1
⑦long long 8byte -2^63~2^63-1
⑧float 4byte -3.4E-38~3.4E+38
⑨double 8byte -1.7E-308~1.7E308
17.类里面static和const可以同时修饰成员函数吗?
C++编译器在实现const的成员函数的时候为了确保该函数不能修改类的实例的状态,会在函数中添加一个隐式的参数const this*。但当一个成员函数为static的时候,该函数是没有this指针的。也就是说此时const的用法和static是冲突的。
18.解释早绑定和晚绑定
多态与非多态的实质区别就是函数地址是早绑定还是晚绑定。如果函数的调用,在编译器编译期间就可以确定函数的调用地址,并生产代码,是静态的,就是说地址是早绑定的。而如果函数调用的地址不能在编译器期间确定,需要在运行时才确定,这就属于晚绑定。
19.STL容器比较
20.main 主函数执行完毕后,是否可能会再执行一段代码,给出说明?
atexit函数
注册终止函数(即main执行结束后调用的函数)
void atexit(void (*func)(void)); 参数为函数指针 当做参数的函数返回值和参数都为空
exit调用这些注册函数的顺序与它们 登记时候的顺序相反。同一个函数如若登记多次,则也会被调用多次。
21.如何判断一段程序是由c编译程序还是由c++编译程序编译的?
#ifdef __cplusplus
cout<<"c++";
#else
cout<<"c";
#endif
22.sizeof与strlen的区别?
①sizeof是运算符,而strlen是函数;
②sizeof可以用类型做参数,其参数可以是任意类型的或者是变量,而strlen只能用
char*做参数,且必须是以’\0’结尾;
③sizeof的结果是编译时的常量,而strlen要到运行时候才能计算出来。
④数组作为sizeof的参数不会被退化为指针,而传递给strlen会退化。
23.野指针,空指针和悬垂指针的区别?
①野指针是指未初始化的指针。
②空指针是指被赋值为NULL/nullptr的指针。
③悬垂指针是指指向了已经被删除的对象的指针。
④空指针可以反复delete,但是对野指针和悬垂指针进行delete会产生未定义行为。
⑤使用野指针、空指针和悬垂指针都会产生未定义行为。
24.什么是智能指针?
①智能指针是C++管理资源的(RAII,资源获取就是初始化)方法的一个体现。
②智能指针是对普通指针的封装;在构造时候获取指针地址,在析构时候释放指针所指资源。
③c++98提供了auto_ptr,c++11提供了shared_ptr,unique_ptr,weak_ptr,不推荐auto_ptr。
④总的说来,智能指针就是为了方便管理动态内存,防止内存泄漏的一个手段。
25.如果虚函数是有效的,那为什么不把所有函数设为虚函数?
①虚函数是有代价的,由于每个虚函数的对象都要维护一个虚函数表。
②虚函数在使用动态调用的时候会带来运行时性能负担(多一次寻址)。所以对于不需要多态的
函数来说这些负担是不必要的。
26.经常要操作的内存分哪几个类别?
①栈区:由编译器自动分配和释放,存放函数的参数值、局部变量的值等;
②堆:一般由程序员分配和释放,存放动态分配的变量;
③全局区(静态区):全局变量和静态变量存放在这一块,初始化的和未初始化的分开放;
④文字常量区:常量字符串就放在这里,程序结束自动释放;
⑤程序代码区:参访函数体的二进制代码。
27.举例说明static_cast如何使用?(会编译成cpu指令)
①static_cast大部分情况下用于对隐式转换的显示化,同时去掉相关warning警报。
②static_cast可以将左值转化为左值引用或者右值引用,将右值转化为有值引用,实现移动语
义
③static_cast可以用于子类与父类(非虚拟)指针、引用之间的转换,不过下行转换可能是不安
全的。
④static_cast可以用于内置类型的转换(非指针,引用),任何类型的point和void*互相转换。
⑤static_cast可以用于将nullptr或者std::nullptr_t类型的值转化为任意指针类型的空指针。
⑥static_cast不能转换掉expression_r_r的const、volitale、或者__unaligned属性
⑦区别:c型强制转换可以作用于没联系的指针之间的转换,而static_cast会有类型检查。
28.举例说明const_cast如何使用?(纯粹是编译器指令)
①"去掉"类型的const或者volatile属性。
②指向同一类型的二级或者多级指针相互转换,无论const volatile属性在哪一级。
③任意类型T的左值可以转化为一个同样类型的左值或者右值,无论const volatile属性有无。
④任意类型T的右值可以转化为一个同样类型的右值,无论const volatile属性有无。
⑤函数指针或者成员函数指针不能使用const_cast转换。
⑥如果通过const_cast来获取一个const obj的no-const权限或者volatile obj的no-volatile权
限来修改、影响源obj都是未定义的行为。
⑦一般推荐是no-const,no-volatile的对象但是通过某个接口得到的是其const引用,可以使
用const_cast来去掉const volatile后再来使用。
29.举例说明reinterpret_cast如何使用?(纯粹是编译器指令)
①将任意类型指针转化为整形(要求住足够大),可以把整形转化为任意类型指针。
②不同类型指针之间相互转换(包括函数指针)。
③类型为T1的表达式可以转化为类型T2的引用,但是只有在类型别名规则允许下安全访问。
④如果不同函数类型的指针相互转换,调用转换后的指针是未定义行为。
⑤在VC中,reinterpret_cast被用来辅助哈希函数。
⑥有的时候提供的数据类型和接口的参数类型不匹配(比如int to uint\double)等,如果使用
static_cast会有精度损失,这个时候就可以使用reinterpret_cast
⑦reinterpret_cast如果不正确的使用很容易导致程序的不安全。
30.举例说明dynamic_cast如何使用?(唯一一个可能在允许时候转换失败)
①下行转化的时候,源对象必须是多态类类型。
②如果目标类型为指针,转换失败会返回空指针。如果目标类型为引用,转换失败会抛出与
std::bad_cast类型得处理程序相匹配的异常。
③一般用于在多态的继承体系中,父类指针\引用安全的转换到子类的指针\引用。
④如果在构造\析构函数中使用,而表达式指向或者引用当前正在构造\析构的对象,那么目标
类型只能是当前自身类或者其基类。
⑤dynamic_cast会带来一定的运行成本(RTTI),所以在能够使用static_cast的时候尽量使用
static_cast。
⑥可以通过dynamic_cast的结果是否为空来确定父类指针指向的是继承体系中哪个子类。
31.typedef和#define联系和区别
联系:
①都可以实现用一个新标识符代替一个已知类型的名字。
区别:
①标识:#define是预编译指令,只在预编译阶段做文本替换;typedef是一个存储类的关键
字(auto,extern,mutable,static,register)一样,所以没法typedef static int sint;编译器会提
示指定了多个存储类。
②执行时间:#define是在预编译阶段通过文本替换完成,在编译期间新标识符完全不可见,
不做类型安全检查;typedef是在编译阶段给一个已知类型取一个别名。
③本质:#define只是文本替换,不是别名,typedef是以前类型的别名是完整的。所以,
typedef int* pint; 对于const pint实质是int*const而不是const int*。
④作用域:#define从定义到文件末尾(undef)有效,typedef有自己的作用域(类似于变量)。
⑤作用:#define可以做很多事情:别名,定义常量,编译开关。typedef只是用来定义别名。
32.内联函数和#define联系和区别
联系:
①都可以节省在函数调用方面所带来的时间和空间开销。二者都采用了空间换时间的方式,在
其调用处进行展开。
区别:
①本质:#define是预编译指令,只在预编译阶段做文本替换;内联函数是在编译阶段在调用
出展开。后者会进行参数类型安全检查,前者不会。
②重载:#define不能进行函数重载,内联函数可以进行函数重载。
③作用域:#define从定义到文件末尾(undef)有效,内联函数有自己的作用域(类,命名空
间,全局)。
④参数:#define的函数参数只是进行替换,不会占用内存,有陷阱(++,--),而内联会先对参
数求值,会占用内存。
33. 链接指示:extern “C”的作用。
①起因:因为C语言是不支持函数重载,而c++语言是支持函数重载,主要的一个原因是因为
C++语言对函数进行编译过程中会把函数名字加上其参数列表等标识,使得不同参数列表的
同名函数进行重载。所以说就究其本质是C和C++对函数的编译和链接方式不一样。
②作用:所以如果C++中如果想使用C的函数,就必须使用extern"C"来使得引入的(头文
件,DLL)按照C的编译、链接方式进行,否则在链接过程中会提示找不到目标函数。
34.虚函数表放在什么地方?
①gcc编译器将虚函数表放在了只读数据段(.rodata)
②msvc编译器将虚函数表放在了常量段。
35.模板特化的概念,为什么特化?
①C++中的模板特化不同于模板的实例化,模板参数在某种特定类型下的具体实现称为模板
的特化。模板特化有时也称之为模板的具体化,分别有函数模板特化和类模板特化。
②有时候通用的base template并不能适用于所有type,对于有的type,我们希望能够"多态"的
执行不一样的操作,这个时候就应该使用特化,这样编译器就会在使用模板的时候匹配最"具
体"的版本。
36.explicit的作用?
①类中如果有只有一个参数的构造函数,那么表示这个参数类型可以隐式转化为该类型。
②有的时候为了避免这种隐式转换带来的不容易察觉的错误,就可以在构造函数前用explicit
修饰,这样编译器就会阻止隐式转换。
37.内存溢出有哪些因素? 内存泄漏
①表达式结果超过存储类型的范围。
②数组访问越界,字符串拷贝容量不够等等。
③栈空间申请内存过大,递归层数过多,线程过多。
④内存泄漏,无法释放申请的内存。
⑤死循环
38.举例加说明智能指针?
①auto_ptr: 不能复制,复制之后原智能指针资源所有权会被剥夺,不能管理动态数组
②shared_ptr: 复制使用引用技术手段,当资源没有被引用时候自动删除,缺点:循环引用。
③intrusive_ptr : 比shared_ptr效率高,但是需要自己维护引用计数器。
④unique_ptr: 和auto_ptr,不过可以管理动态数组,c++11中明确取代了auto_ptr
⑤weak_ptr: 弱引用智能指针,不会增加计数,配合shared_ptr的工具。避免循环引用。
39.区别仿函数和函数指针
①函数指针不用解释了,仿函数就是重载了()的类,使得其行为可以跟函数调用一样。
②函数指针比较灵活可以随时指向不同的函数。
③仿函数可以保存状态,使得仿函数可能在不同的情况下表现不同的行为。
④仿函数可以使用内联,所以有的时候使用仿函数要比函数指针要快。
⑤仿函数一般是跟模板泛型编程搭配使用,再配合适配器(bind等)非常灵活。
40.相关寄存器
①eax : 累加及寄存器,常常用作函数返回值
②ebp : 基址指针寄存器,常常指向当前栈底部。 栈底指针
③esp : 堆栈(Stack)指针寄存器,指向堆栈顶部 栈顶指针
④ecx : 计数器(counter),常常用做字符串,循环操作的计数器,this指针。
⑤eip : 指令寄存器,指向下一条指令的地址 指令指针
⑥ebx: 基址寄存器
⑦esi: 源变址寄存器
⑧edi: 目的变址寄存器
41.相关函数调用约定
①_cdecl:按照从右到左压参数入栈,由调用者把参数弹出栈。是c/c++缺省调用方式。
②_fastcall: 通过寄存器ecx,edx传送前双个字或更小参数,剩下仍旧从右到左压栈,被调用的函数在返回前清理内存栈。
③__stdcall:按照从右到左压参数入栈,由函数自身把参数弹出栈。是win api的方式
④_thiscall:类成员函数调用方式,vc是将this指针放入ecx寄存器,gnu gcc把this当作第一个
参数。如果参数个数确定由函数返回前清理内存栈,否则由调用端清理。
42.函数调用过程.(略)
_cdecl:
1.从右向左压入参数
2.压入调用函数的下一条指令(为了返回)
3.压入被调用函数地址,跳转(EBP,ESP,EIP都会切换到子函数的栈区)
43.静态成员函数为什么不能申明为虚函数
①因为静态成员函数实质就是添加了一层命名空间的普通函数,调用不需要传入this指针。
②虚函数表现的多态主要是根据this指针的真实类型,而静态成员函数根本没有this指针。
44.模板的实现和声明是否一定要在同一个头文件中,为什么?
①是的,因为在模板实例化的时候,编译器会在模板头文件里去找所有函数的定义并且把模板
类型用真实类型替换,如果实现没有放在头文件,那么编译器就无法正确访问到。就会实例化
失败。
②可以提供分离申明的方式,就是将模板声明写在一个头文件里exm: tem.h,然后把所有实现
写在另一个文件exm:tem.tpp。然后在tem.h声明之后#include<tem.tpp>
③还有一种方法就是按照常规的将声明写在.h头文件,实现写在.cpp源文件,只不过值得注意
的是你必须在cpp源文件中将你需要的模板实例显示实例化。
45.构造函数和析构函数可以抛出异常吗?
①可以通过在构造函数里抛出异常来监测对象是否创建成功,但是需要注意的是在抛出异常之
前释放申请的资源。构造函数抛出异常是不会调用析构函数的。
②析构函数不可以抛出异常,通常异常发生时,c++的机制会调用已经构造对象的析构函数来
释放资源,此时若析构函数本身也抛出异常,则前一个异常尚未处理,又有新的异常,会造成
程序崩溃的问题。如果无法保证不抛出异常,可以使用catch语句在析构函数内将异常捕获。
46.STL是如何分配内存的?
在SGI STL中才用了双层级配置器,第一级配置器直接使用malloc()和free()向系统申请堆内
存。第二级配置器则采用不同的策略。
如果申请的内存大于128byte的时候就直接启动第一级分配器。如小于128byte就启动第二级
分配器。第二级别分配器是维护了一个长度为16的节点,每个节点表示大小为8,16,
24....128byte内存池。每次申请内存都是向上转为8的整数倍,然后到对应池子取相应大的内
存。每个池子也是一个链表,通过二级分配器分配的内存,在回收的时候并不直接交还给系统
而是放回池子,由池子最后自己释放。
47.STL是线程安全的吗?
STL不是线程安全的
线程安全的情况
- 多个读取者是安全的。多线程可能同时读取一个容器的内容,这将正确地执行。当然,在读取时不能 有任何写入者操作这个容器。
- 对不同容器的多个写入者是安全的。多线程可以同时写不同的容器。
线程不安全的情况
- 在对同一个容器进行多线程的读写、写操作时。
安全措施:
- 在每次调用容器的成员函数期间都要锁定该容器。
- 在每个容器返回的迭代器(例如通过调用begin或end)的生存期之内都要锁定该容器。
- 在每个在容器上调用的算法执行期间锁定该容器。(这事实上没有意义,因为,正如条款32所解释的,算法没有办法识别出它们正在操作的容器。不过,我们将在这里检验这个选项,因为它的教育意义在于看看为什么即使是可能的它也不能工作。)
48.数组和指针的区别?
①位置:数组要么在静态区被创建(全局或者static),要么在栈上面创建(局部)。而指针可以指
向任意类型内存块。
②sizeof():数组得到的是容量(字节数),而指针只能得到指针变量的字节数。
③数组在参数传递过程中会退化为指针。
49.Overload 重载,Override 重写 , Overwrite(Redefine)隐藏
①overload:
同一个作用域(同一个类中),函数名相同,不同参数列表,返回值可以不同。
编译时多态的体现,调用时根据实参类型匹配相应函数实体。
②override:
不同作用域(父类,子类),函数名相同,参数相同,必须是虚函数。返回值相同(协变)。
运行时多态体现,调用时根据实际类型选择对应的虚函数实体。
③overwrite(redefine):
不同作用域(父类,子类),函数名相同,参数不同(无论是否虚函数)或者参数相同(基类没
有virtual)。
父类同名函数被隐藏,通过子类无法调用基类的同名函数。
50.请讲述堆和栈的区别
①申请方式不同。栈上有系统自动分配和释放;堆上有程序员自己申请并指明大小。
②栈是向低地址扩展的数据结构,大小很有限;堆是向高地址扩展,是不连续的内存区域,空间相对大且灵活;
③栈由系统分配和释放速度快;堆由程序员控制,一般较慢,且容易产生碎片;
④栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示溢出;
堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
51.区别sprintf,strcpy,memcpy函数
①strcpy 函数操作的对象是字符串,完成从源字符串到目的字符串的拷贝功能。
②sprintf 函数操作的对象不限于字符串,虽然目的对象是字符串,但是源对象可以是字符
串、也可以是任意基本类型的数据。这个函数主要用来实现(字符串或基本数据类型)向字符串的转换功能。如果源对象是字符串,并且指定 %s 格式符,也可实现字符串拷贝功能。
③memcpy 函数顾名思义就是内存拷贝,实现将一个内存块的内容复制到另一个内存块这一
功能。内存块由其首地址以及长度确定。
S = 单一职责原则 Single Responsibility Principle
O = 开放闭合原则 Opened Closed Principle
L = Liscov替换原则 Liscov Substitution Principle
I = 接口隔离原则 Interface Segregation Principle
D = 依赖倒置原则 Dependency Inversion Principle