c++基础第二版(复习、面试使用)

本文详细介绍了C++中的指针和引用的区别,以及内存的堆、栈和静态存储区。讨论了C++中的new和delete操作,以及它们与malloc和free的区别。此外,还涵盖了堆和栈的特性、C++的面向对象特性如封装、继承和多态,以及STL中的容器如vector和list。文章还深入讨论了内存泄漏、智能指针、多态的实现、虚函数表和析构函数为何为虚函数等主题。
摘要由CSDN通过智能技术生成

1. 指针和引用的区别

(1)指针是新的变量,保存的是变量的地址,引用时变量的别名,对引用的操作就是对指针的操作。

(2)指针可以有多级的,引用只有一级的。

(3)指针一般是四个字节,引用一般取决于参数的类型

(4)指针可以是空,而引用不可以是空的

2. c++的存储方式

(1)堆:存放new和malloc创建的变量,程序员手动管理。因为频繁的释放申请,会产生内存碎片。

(2)栈:函数调用时存放变量函数名,操作系统进行管理

(3)静态存储区:存放静态变量,全局变量等变量

(4)代码区:存放代码

3. 堆和栈的区别

(1)堆会有内存碎片,栈没有

(2)堆的地址越来越大,栈的地址越来越小

(3)栈相对于堆比较快。栈的地址用相应的寄存器存储,寻址比较快,栈的入栈出栈操作有专门的指令执行,效率高,堆的操作是通过库函数实现的,并且分配的时候需要找的大小合适的空间,在查找时候必须先找到地址才能找堆的内容。

4. new和delect

new和delect类封装好的,new是使用malloc为对象分配内存空间,然后调用构造函数。delect是使用析构函数,然后调用free回收内存。

5. new和malloc的区别

(1)new是运算符,malloc是库函数。

(2)new不需要强制类型转换,malloc需要强制类型转换。

(3)new可以没有申请多大空间,但malloc必须给出申请多大的内存空间。

6. 为什么有malloc还要有new

因为对于非基本类型的对象的空间申请释放是自动执行构造函数和析构函数,而malloc和free是已经编译好的库函数,并不具有自动执行的功能,不能将构造函数和析构函数的功能强加给malloc/free。

7. c++和c的区别

包括但不限于:

  • C是面向过程的语言,C++是面向对象的语言,C++有“封装,继承和多态”的特性。封装隐藏了实现细节,使得代码模块化。继承通过子类继承父类的方法和属性,实现了代码重用。多态则是“一个接口,多个实现”,通过子类重写父类的虚函数,实现了接口重用。
  • C和C++内存管理的方法不一样,C使用malloc/free,C++除此之外还用new/delete
  • C++中还有函数重载和引用等概念,C中没有。

8. delect和delect[]区别

(1)delect会调用一次析构函数,而delect[]可以调用每个成员的析构函数

(2)new申请的内存new释放,new[]申请的内存,delect[]释放

9. c++和java的联系和区别

相同点:

(1)都是面向对象的语言,都有stl库

不同点:

(1)c++是通过编译成可执行文件直接运行,java是编译之后在虚拟机上运行,java先把源码编译成和机器无关的字节码(.class)文件,然后在虚拟机上执行时会将字节码转换成机器码。也就是是说c++是编译型语言,java是解释和编译共存的语言。

(2)内存管理方面不同,c++的内存管理是程序员进行手动管理,比如说构造函数和析构函数的配套使用,malloc\free的配套使用,new\delect的配套使用。而java的内存管理是虚拟机的垃圾回收机制完成的。

(3)c++有指针,而java没有指针只有引用。

(4)java没有析构函数,他是通过内部的垃圾回收机制完成内存回收的。

10. struct和class的区别

(1)struct默认访问权限和继承方式为public,class默认访问权限和继承方式为pravite。

(2)class可以使用模版,而struct不能使用模版。

11.define和const的区别(都能定义常量)

(1)define只是做了简单的替换,没有规定类型,可能有多个拷贝,占用空间很大。而const具有类型,存放在静态存储区,占用内存很小。

(2)define是在预编译时候进行处理的,而const是在编译阶段进行确定的。

(3)define不会进行安全检查,仅仅是简单的替换,而const会进行安全检查。

(4)define直接进行替换,不单独分配内存、存储和程序段;const需要内存分配、存储和程序段

Ps:根据1、4,define就是规定一个常量,当有数值等于常量时就赋值,而const仅仅就存在一个常量在内存里面,需要时直接使用

12. c++中const的用法和意义

(1)cosnt修饰变量时候表示常量,表示不能被修改。

(2)const修饰类的成员函数,表示类不会修改类中的·数据成员,不会调用非const的成员函数。

13. c++的static的用法和意义

static表示静态,可以用来修饰变量、函数、和类成员。

(1)变量:被static修饰的变量为静态变量,会被放在静态存储区。用static修饰的变量会在程序中一直存在,并且仅仅在作用域里面有效。

(2)函数:被static修饰的函数就是静态函数,静态函数仅仅只能在本文件内中使用,其作用范围仅仅是本文件,并且函数存储在静态存储区,仅仅有一份。静态函数不会和其他文件的同名函数冲突。

(3)类:在类的内部修饰成员变量或者成员函数,在构造函数执行之前就会申请内存空间,并且无论对象存在多少份,静态成员变量和静态成员函数都仅仅有一份。

14.迭代器失效的情况

(1)使用erase()和insert()会导致当前位置之后的所有迭代器失效。

(2)如果容器扩容,在其他地方又重新开辟了内存,会导致所有的迭代器失效。

15.c++里面STL

Hashtable:采用开链法解决哈希冲突,当桶的大小超过8时转换成红黑树进行组织。

Unoredered_map使用的就是hashtable

16. 解决hash冲突的方式

(1)线性探查:当冲突的时候就向后进行探查,如果找到了就存放在那里。

(2)二次探查:当冲突了就找 1 2 , 2 2 . . . i 2 1^2,2^2...i^2 12,22...i2的位置。

(3)双散列函数法:当冲突那就用第二个散列函数进行映射。

(4)开链法:当冲突时候就将这个元素插入到对应的链表中。

(5)建立公共溢出区:当发生冲突是将所有冲突的数据放在公共溢出区。

17. STL中的vector的实现

STL库中封装了动态数组的顺序容器,vector支持自动扩大容器的大小。具体策略是如果内存不够的话就申请一个原来大小两倍的空间,然后拷贝至新的容器,并释放原来的空间,然后返回新空间的地址。

18. vector调用push_back()对性能的影响和原因

因为push_back每次内存不够的时候都会进行申请内存空间,频繁地申请内存空间会耗费巨大的时间,对性能造成严重的浪费。

Emplace_back():会在尾部创建元素,省去了拷贝或移动的过程

19.c++中的vector和list

vector和数组类似,拥有一段连续的内存空间,当空间不够需要扩容时,会申请2倍于现在的空间,然后把数据拷贝过去。当进行插入和删除操作时也必须将后面元素前移或者后移才行。

list和链表类似,拥有离散的内存空间,不存在空间不够的情况,当插入和删除时候不需要移动其他元素,但是查找时候不能根据位置进行查找,比较费时。

二者的迭代器都重载了++运算符。

20.c++的重载和重写区别

(1)重载指的是同一函数体内,函数名相同参数不同的函数。

(2)重写是子类继承父类以后,函数名相同,参数列表相同,方法体不相同的实现方法。

(3)重定义是指子类继承父类以后,函数名相同,参数列表不同的函数。

21.面向对象的三大特性

三大特性:封装、继承、多态

(1)封装是指将成员变量和成员函数封装在对象里面,实现了代码模块化

(2)继承使子类可以复用父类的成员和方法,实现了代码重用。

(3)多态是指一个接口多个实现,多态通过继承来实现,子类继承父类函数以后,可以对函数进行重写。

22. 多态的实现

c++的多态主要是通过函数重写和模版实现,由此分为动态和静态的多态。

函数重写:依托虚函数实现,基类中定义虚函数,子类中复写虚函数,从而实现不同的功能,每个子类都可以进行函数重写,从而实现多态。

模版:模版实现静态的多态,通过定义一类的函数或者变量作为模版。后面通过对模版实例化实现多态。

23. 函数模板

template<typename T>
void print(T a){
  cout<<a<<endl;
}

函数模版和普通函数的区别:

(1)函数模板不允许自动类型转化,而普通函数可以进行自动类型转化。

(2)函数模版和普通函数同时存在时,会优先调用普通函数。

(3)如果函数模板能够有更好的匹配,会优先选择普通函数。

模版函数的重载:优先看匹配度,匹配度高的会优先选择

函数模板的二义性报错:指的是模板具有相同的优先级,当进行调用时出现二义性,既不知道调用哪个更好。

template<typename T,typename T1>
    void print(T a,T1 b)
    {
        cout<<"this is 4: "<<a<<"  "<<b<<endl;
    }
template<typename T,typename T1>
     void print(const T&  a,const T1&  b)
     {
         cout<<"this is 2: "<<a<<"  "<<b<<endl;
     }
int main(){
    int a=1;
    int b=2;
    print(&a,&b);//两个模板的优先级相同,会出现二义性报错
    return 1;
}
template<typename T,typename T1>
template<typename T,typename T1>
     void print(T&  a,T1&  b)
     {
         cout<<"this is 2: "<<a<<"  "<<b<<endl;
     }
int main(){
    int a=1;
    int b=2;
    print(10,&b);//报错,T&只能传进来左值,不能传进来右值
    return 1;
}

对于const T &和T&&可以传进来右值

下例会优先调用指针:因为T a可以为任何参数,T只能是指针。T=const T&<T;T=T&<const T&;注意的是即使T和T&也会出现冲突。

规则

(1)根据参数个数选择

(2)优先普通函数

(3)其次根据特例化程度选择

(4)若存在两个参数一样,特例化程度一样则出现二义性,报错

函数模版会进行两次编译,第一次编译是对模版本身的编译,这次编译仅仅进行语法检查,而不会生成具体的代码,而运行时对代码进行参数替换时会再次进行编译,生成具体的代码。

24. 虚函数相关

c++的虚函数是实现多态的机制,虚函数的实现是通过虚函数表实现的。每个类都有自己对应的虚函数的表,父类的虚函数表指向其实现,子类的虚函数表当没有重写函数是指向父类的函数地址,既和父类的虚函数表有相同的类型。当子类重写父类函数时,会指向重写的函数。相同类的实例共享同一张虚函数表。

25. 编译器处理虚函数

编译器处理虚函数的方法是为每个类创建虚函数表,然后为每个相同类创建的实例创建虚函数表指针,每个相同类型创建的实例共享同一张虚函数表。

26. 析构函数为什么能写成虚函数

如果析构函数不被定义成虚函数,当删除子类指向父类的指针时,只会调用父类的析构函数,而不会调用子类的析构函数,这样就会造成子类对象不能完全析构。例如有父类A,子类B,当实例化B的对象B *b,如果将b指向A类进行类型转换,那么在进行析构时如果析构函数不是虚构函数就会出现内存泄漏。

27. 构造函数为什么不能是虚函数

因为在进行实例化时,执行构造函数之前,对象不具有空间,而自然也没有虚函数表指针,如果构造函数是虚函数,那么将无法调用构造函数。因此构造函数必须是非虚函数,那么调用完构造函数以后申请虚函数指针,之后调用虚函数。

28. 纯虚函数

纯虚函数是只有声明而没有实现的函数,仅仅起接口的作用。

29. 深拷贝和浅拷贝

浅拷贝仅仅是进行简单的复制,相当于链接。

深拷贝重新开辟了一块空间,然后将原对象复制到新的空间里面,并返回该空间的地址。

深拷贝占用内存,但可以避免重复释放和写冲突,如果释放浅拷贝的对象可能会导致内存泄露或者内存崩。

30. 对象复用和零拷贝

对象复用指的是将对象池中实现的对象进行重复利用。并且使用完以后会放进对象池中,以避免相同对象反复申请造成资源浪费。

零拷贝指的是尽量避免cpu将数据冲一块存储从一个地方复制到另外一个地方,减少数据拷贝的次数。比如在c++中push_back就是构造完对象以后,调用拷贝构造函数和转移构造函数来实现插入操作。而有一种更好的方式是使用emplace_back()进行原地构造,而不触发拷贝构造函数和转移构造函数。emplace_back使用的就是零拷贝构造技术。

31.构造函数的类型

(1)默认构造函数:直接构造

(2)拷贝构造函数:根据其他对象进行构造,完全复制。

(3)转移构造函数:使用其他对象执行构造,并将其他对象的数据设置成nullptr,将大小设置成0。

class A{
  public:
  A(int a,int b)a(a),b(b){//默认构造函数
	}
  A(A & myA)a(myA.a),b(myA.b){//拷贝构造函数
	}
  A(A && myA)a(myA.a),b(myA.b){//转移构造函数
    A.a=null;
    A.b=null;
	}
}

拷贝构造函数的使用情况

(1)传入函数时

(2)作为函数返回值时

(3)使用一个对象对另一个对象初始化时

转移构造函数的作用

使用转移构造函数可以将原有的内存资源复用,因为转移构造函数申请资源时会直接使用原函数的资源,而原函数的内存资源为设为空,而不是被释放,从而达到资源复用的目的,避免资源的频繁分配。

32.NULL和nullptr的区别

NULL是替换的整型,nullptr指的是空指针。

33. 结构体的内存对齐方式为什么要进行内存对齐

内存对齐:结构体中的所有数据的地址必须是某一个整数的整数倍

答:为了使cpu把数据一次性读取出来,而不是因为不同数据类型还要分辨读取多少字节。

对齐数:和哪个数的整数倍对齐。

对齐规则:

(1)第一个成员在与结构体变量偏移量为0的地址

(2)其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

(3)对齐数=编译器默认的一个对齐数与该成员大小的较小值。

(4)linux 中默认为4

(5)vs 中的默认值为8
结构体总大小为最大对齐数的整数倍(每个成员变量除了第一个成员都有一个对齐数)。

34. 内存泄露和如何检测和避免

内存泄露是指动态分配内存开辟空间以后使用完没有释放,导致内存一直被占用,这就是内存泄露。

内存泄漏的原因:

(1)new\delect和malloc\free没有配套使用。

(2)释放对象数组时没有使用delect[],使用了delete。

(3)析构函数没有使用虚函数,导致基类指针指向子类时,执行析构函数是执行的是基类的虚构函数从而导致内存泄漏。

(4)没有正确嵌套对象指针。

35.c++强制类型装换相关

c++强制类型转换后,例如基类指针指向父类,会调用子类成员变量和虚函数,会执行父类的成员函数。

36. 强制类型转换的种类

(1)static_cast():转换时不会进行类型检查,可以把基类转化为派生类

(2)const_cast():一般进行const相关的转换

(3)dynamic_cast():转换时会进行动态类型检查,转换的类型必须是指针

(4)reinterpret_cast():可以把一个指针转化为另外一个指针,也可以进行指针和整数之间的转换。

static_cast::对象=static_cast(对象),进行基本类型转换和类转换,进行类转换时会在编译时判断合法,如果合法就转换(所谓合法就是判断两个对象的类型是否是父子关系,既是否能够进行隐式转换)

A *bb=new A(1);
AA *temp2=static_cast<AA*>(bb);//可以进行转换 
AA *aa=new AA(1);
A *temp1=static_cast<A*>(aa);//可以进行转换 
AA *temp3=static_cast<AA*>(temp1);//可以进行转换 

dymamic_cast:对象=dymamic_cast(对象),只能进行指针或者引用类型的转换,编译时不会进行合法判断,即使两种类型不能隐式转换,编译依旧会通过,在运行时会进行合法检查,判断被转换对象的实际类型是否和要转化的对象类型相同,如果不同,返回null

要求:必须有虚函数,因为会检查虚函数表

A *bb=new A(1);
AA *temp2=dynamic_cast<AA*>(bb);//不能转化
AA *aa=new AA(1);
A *temp1=dynamic_cast<A*>(aa);//可以进行转换 
AA *temp3=dynamic_cast<AA*>(temp1);//可以进行转换 

reinterpret_cast:极其不安全的操作,进行可以进行不同类型的指针转换,转换形式为比特流的形式进行转换,程序员要注意比特对应,自己对自己的程序负责

const_cast:仅仅用于去除常属性

37.智能指针

(1)auto_ptr:进行拷贝时候新指针接管旧指针资源,并把旧指针资源释放,类似于转移构造函数(转移构造函数目的是为了实现资源复用)。auto指针对于拷贝和赋值操作是不安全的。

(2)unique_ptr:改进了auto_ptr,直接不允许复制和赋值操作。

(3)shared_ptr:一个对象可以有多个之智能指针,shared_ptr内部有计数器对指针进行计数,以此维护智能指针,当计数器数量大于0时,释放智能指针后计数器减一。当计数器为0时,真正释放空间。但是当出现环引用时会导致永远无法释放资源的情况。

(4)weak_ptr:用于解决循环引用的情况。

Shared_ptr造成的无法释放的情况

struct Father
{
    shared_ptr<Son> son_;
};

struct Son
{
    shared_ptr<Father> father_;
};

int main()
{
    auto father = make_shared<Father>();
    auto son = make_shared<Son>();
    father->son_ = son;
    son->father_ = father;
    return 0;
}

Weak_ptr

struct Father
{
    shared_ptr<Son> son_;
};
struct Son
{
    weak_ptr<Father> father_;
};
int main()
{
    auto father = make_shared<Father>();
    auto son = make_shared<Son>();
    father->son_ = son;
    son->father_ = father;
    return 0;
}

38. 程序调试的方法

(1)设置断点进行debug。

(2)打印log进行调试。

(3)打印中间结果进行调试。

lldb进行调试

g++ -g -main.cpp -o main -> lldb main -> break main(或break 行号) -> run

lldb命令包括 next/print/continue/frame variable/step/break

39.inline关键字,其和宏定义的区别

(1)内联函数在编译时候展开,宏在预编译时候展开。

(2)内联函数会进行安全检查,而宏定义不会进行安全检查,宏的安全检查在编译时进行处理。

(3)内敛函数是函数,而宏不是函数

40. c++11新特性

(1)auto自动类型推导

(2)nullptr

(3)lambda表达式,[p1,p2,p3…]{函数体}

(4)thread类和mutex类

(5)新的智能指针 unique_ptr和shared_ptr

41. string的底层实现

string继承自basic_string,是对char *的封装,可以进行动态扩展,每次扩展时会申请两倍大的空间,然后将原字符串拷贝过去。

42. 可执行文件的生成和编译过程

(1)预处理

(2)编译

(3)汇编

(4)链接

(5)装入

(6)执行

43. Set、map、vector的插入查找复杂度

set和map的插入复杂度都是log(N),其实现都是根据平衡二叉树。

Unorder_map和unorder_set插入时间复杂度是常数级别的,有时达到O(N)级别,其实现是根据hash实现。

Vector插入时间是O(N)。

44. 定义和声明的区别

声明不会分配空间,还未实现,为了通过编译

定义是实现函数,有函数体,会分配内存空间

一个函数可以被声明多次,但只能被定义一次

45.typedef和define

define是预编译时候处理的,只是简单的替换,而不进行正确检查

typedef编译时候处理的,给作用域已存在的变量一个别名

46. 被free以后是立即归还给系统吗

不是,被free以后会存放在双链表里面,当下次申请内存时候,会先尝试从这些内存里面申请内存,避免频繁地系统调用占用系统资源。

47. 引用作为函数参数和返回值的好处

传参:函数内部就可以对变量进行修改,避免形参拷贝

返回值:避免返回值的拷贝和副本

局限:不能返回局部变量的引用(会被销毁,静态?),不能返回new分配的内存(返回值是临时存在的,无法进行free)

48. 友元函数和友元类

友元函数:使非成员函数访问类的私有成员

外部友元函数

#include<iostream>
using namespace std;
class A{
public:
A(int n){
this->n=n;
}
friend void print(A a);
private:
int n;
};
void print(A a){
cout<<a.n;
}

类友元函数:在设置友元函数之前,友元函数应该已经被声明。

class A;
class B{
public:
int b;
void print(A a);
};
class A{
public:
A(int n){
this->n=n;
} 
friend void B::print(A a);
private:
int n;
};
void B::print(A a){
cout<<a.n;
}

友元类:友元类的所有函数都能访问私有变量

class A;
class B{
public:
int b;
void print(A a);
};
class A{
public:
A(int n){
this->n=n;
} 
friend class B;
private:
int n;
};
void B::print(A a){
cout<<a.n;
}

声明:若A是B的友元,既A可以访问B的私有成员

(1)不具有对称性,B不能访问A

(2)不具有传递性,若B是C的友元则不能说明A是C的友元

(3)不能被继承,若C继承了A,则C不是B的友元。但是如果BB继承了B,那A也是BB的友元。A是B的朋友,A也是B孩子的朋友,但A得孩子不是B的朋友

继承构造函数: AA继承A

using AA:A或AA(int a):A(a){};

49. 说一下volatile关键字的作用

volatile的意思是“脆弱的”,表明它修饰的变量的值十分容易被改变,所以编译器就不会对这个变量进行优化(CPU的优化是让该变量存放到CPU寄存器而不是内存),进而提供稳定的访问。每次读取volatile的变量时,系统总是会从内存中读取这个变量,并且将它的值立刻保存。而不是缓存在寄存器上进行读。

50. 虚基类

虚基类是用关键字virtual声明继承的父类,即便该基类在多条链路上被一个子类继承,但是该子类中只包含一个该虚基类的备份,虚基类主要用来解决继承中的二义性问题,这就是是虚基类的作用所在。

正是由于虚基类的这个作用,所以在每个子类的构造函数中必须显示的调用该虚基类的构造函数,不管该虚基类是不是直接的父类。

class Cbase{};
class CBase1 : virtual public Cbase{};
class CBase2 : virtual public Cbase{};
class CObj : public CBase1, public CBase2{};

CObj继承了CBase1和CBase2,而CBase1和CBase2都继承了Cbase,可能会产生二义性,而使用虚基类,该CObj中就只包含一个Cbase的备份。从而解决了二义性的问题。

51. 左值引用和右值引用

左值与右值:在C++11中可以取地址的、有名字的就是左值,反之,不能取地址的、没有名字的就是右值。举个例子,int a = b+c, a 就是左值,其有变量名为a,通过&a可以获取该变量的地址;表达式b+c、函数int func()的返回值是右值,在其被赋值给某一变量前,我们不能通过变量名找到它,&(b+c)这样的操作则不会通过编译。左值一定在内存中,右值有可能在内存中也有可能在寄存器中。

引用:就是取别名 ,引用不可以重定义。

左值引用与右值引用:左值引用就是对一个左值进行引用的类型。右值引用就是对一个右值进行引用的类型。右值引用和左值引用都是属于引用类型。无论是声明一个左值引用还是右值引用,都必须立即进行初始化。而其原因可以理解为是引用类型本身自己并不拥有所绑定对象的内存,只是该对象的一个别名。左值引用是具名变量值的别名,而右值引用则是不具名(匿名)变量的别名。

左值引用不能绑定右值。但常量左值引用是个“万能”的引用类型。它可以接受非常量左值、常量左值、右值对其进行初始化。不过常量左值所引用的右值在它的“余生”中只能是只读的。相对地,非常量左值只能接受非常量左值对其进行初始化。

int &a = 2;       # 左值引用绑定到右值,编译失败
int b = 2;        # 非常量左值
const int &c = b; # 常量左值引用绑定到非常量左值,编译通过
const int d = 2;  # 常量左值
const int &e = c; # 常量左值引用绑定到常量左值,编译通过
const int &b =2;  # 常量左值引用绑定到右值,编程通过

右值引用不能绑定左值。右值值引用通常不能绑定到任何的左值,要想绑定一个左值到右值引用,通常需要std::move()将左值强制转换为右值,例如:

int a;
int &&r1 = c;             # 编译失败
int &&r2 = std::move(a);  # 编译通过
右值引用的方法就是int * &&rnum = &num1;  。

为什么要右值引用,右值引用在你需要使用寄存器中的值的时候可以进行右值引用。寄存器的刷新速度很快,没有右值引用的话就需要将寄存器中的值拷贝到内存中,在进行使用,这是很浪费时间的。

int getdata(int &&num)
{
    cout << num;
    num += 10;
    return num;
}
void main()
{
    int a = 5;
    cout << getdata(a + 1) << endl;
}

如上int getdata(int &&num)就是对右值进行引用。 getdata(a + 1) 中a+1是右值在寄存器中,我们是不可以直接对他进行操作的,如果要操作得将其拷贝到内存中,如果是一个非常大的数据这种拷贝就会很占用内存,如果直接用右值引用就可以直接对其进行操作。从而节约内存。将右值转化为左值 直接新建变量然后赋值就可以了.

52. C++的输入输出流

C++之输入输出流

(1)iostream 包含对输入输出流进行操作所需的基本信息

(2)fstream 用于用户管理的文件的I/O操作

(3)strstream 用于字符串流I/O操作

(4)stdiostream 用于混合使用C和C++的I/O机制时,例如将C程序转变为C++

(5)iomanip 使用格式化I/O时包含此头文件

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

�Wang Chien Po

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值