C++核心编程 day09 类型转换、异常、输入输出流

C++核心编程 day09 类型转换、异常、输入输出流

  • 1. 类型转换
  • 2. 异常
    • 2.1 异常语法
    • 2.2 C++标准异常库
  • 3. 输入输出流
    • 3.1 输入输出流概念以及流类库
    • 3.2 标准输入流
    • 3.3 标准输出流
    • 3.4 文件读写

1. 类型转换

C++中的类型转换有四类,分别是静态转换、动态转换、常量转换、重新解释转换。

静态转换使用static_cast<typename>进行转换。主要用于类层次中的父类和子类之间指针或引用的转换。向上类型转换的时候是安全的,但是向下类型转换的时候由于没有动态类型检查,所有是不安全的。静态转换也支持内置基本的数据类型之间的转换。

动态类型转换是使用dynamic_cast<typename>进行转换。动态类型转换用于类层次之间的向上类型转换和向下类型转换。向上类型转换的时候效果和静态类型转换的效果是一样的。在使用向下类型转换的时候,会比static_cast更加安全。动态类型转换不支持内置基本数据类型转换。

常量转换是用于修改类型的const属性,使用const_cast<typename>来进行转换。需要注意的是常量转换不能直接对非指针和非引用的变量去移除他们的const属性。

重新解释转换是使用reinterpret_cast<typename>来进行转换。这是C++中最不安全的一种转换机制,最有可能出问题。主要用于将一种数据类型转换为另一种数据类型,比如指针可以转换为一个整数,一个整数也可以转换为一个指针。

关于四种类型转换的示例代码如下所示。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;//静态类型转换
void test01()
{//允许内置数据类型之间转换char a = 'a';double d = static_cast<double>(a);cout << d << endl;
}class Base{ virtual void func(){} };
class Son : public Base { virtual void func(){} };
class Other {};void test02()
{Base *base = NULL;Son *son = NULL;//语法:static_cast<目标数据类型>(原对象)//父子之间的指针或者引用可以转换//将base转为Son * 父转子 向下类型转换 不安全Son *son2 = static_cast<Son *>(base);//son转为Base * 子转父 向上类型转换 安全Base *base2 = static_cast<Base *>(son);//base转为Other *//Other *other = static_cast<Other *>(base); //转换无效
}// 动态类型转换 dynamic_cast
void test03()
{//不允许内置数据类型之间转换//char c = 'c';//double d = dynamic_cast<double>(c);
}void test04()
{Base *base = new Base;Son *son = NULL;//将base转为Son * 父转子 不安全 如果发生了多态,那么转换总是安全的Son *son2 = dynamic_cast<Son *>(base);//son转为Base * 子转父 安全Base *base2 = dynamic_cast<Base *>(son);//base转Other *//Other *other = dynamic_cast<Other *>(base); //无法转换
}//常量转换 const_cast
void test05()
{//不可以将非指针或者费引用做const_cast转换const int *p = NULL;int *pp = const_cast<int *>(p);const int *ppp = const_cast<const int *>(pp);//const int a = 10;//int b = const_cast<int>(a);int num = 10;int &numRef = num;const int &num2 = const_cast<const int &>(numRef);
}//重新解释转换 reinterpret_cast 最不安全一种转换,不建议使用
void test06()
{int a = 10;int *p = reinterpret_cast<int *>(a);Base *base = NULL;//base转Other *Other *other = reinterpret_cast<Other *>(base);
}int main()
{test01();system("pause");return 0;
}

2. 异常

2.1 异常语法

异常处理就是处理程序中出现的错误,所谓的错误就是程序运行过程中发生的一些异常事件。比如除0移除、数组下标越界、空指针等错误。在C语言中我们对错误的处理主要是两个方法,第一种是使用整型的返回值标识错误,二是使用errno宏去记录错误。在C++中仍然可以使用这两种方法。

上述的两种处理方法虽然说可以处理错误,但是最大的缺陷就会出现不一致的错误。比如有些函数返回1表示成功,返回0表示错误;而有些函数返回0表示成功,返回非0表示错误。除此之外,还有一个缺陷就是函数的返回值只有一个,当你通过函数的返回值代表错误代码的时候,那么函数就不能返回其他的值。比如下面的函数你就不能分清该函数返回的-1究竟是程序出错还是程序的执行结果。也就是函数的返回值有多重语义。

int myDivision(int a, int b)
{if(b == 0){return -1;}return a / b;
}

而我们使用C++的异常处理就不会出现这种情况。在C语言中处理异常的时候可能函数的调用者会忘记处理异常,而C++中如果你没有处理异常程序就会中断。异常的处理也可以在处理跳级,也就是有多个函数在调用栈中出现了某个错误,而C++中只需要在其中的某一处进行处理即可,不需要每一级的函数都进行处理。C++中如果有异常,我们使用throw操作创建一个异常对象并抛出。我们将可能抛出异常的程序段放在try代码块中,如果在try程序段执行期间没有引起异常,那么跟在try代码段后的catch字句就不会执行。catch子句会根据出现的先后顺序被检查,匹配的catch语句捕获并处理异常,或者也可以继续抛出异常。如果匹配的处理未找到,则会自动调用terminate函数,其缺省功能调用abort终止程序。对于处理不了的异常,也可以在最后一个catch分支使用throw继续上抛。下面给出一段关于异常的基本语法的示例代码。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <string>class MyException
{
public:void printError(){cout << "我自己的异常" << endl;}
};class Person
{
public:Person(){cout << "Person的默认构造函数调用" << endl;}~Person(){cout << "Person的析构函数调用" << endl;}
};int myDivision(int a, int b)
{if (b == 0){//return -1;//throw 1; //抛出int类型异常//throw 'a'; //抛出char类型异常//throw 3.14; //抛出double类型异常//string str = "abc";//throw str;//从try代码开始,到throw抛出异常之前,所有栈上的数据都会被释放掉//释放的顺序和创建的顺序相反,这个过程我们称为栈解旋Person p1;Person p2;throw MyException(); //抛出MyException的匿名对象}return a / b;
}void test01()
{int a = 10;int b = 0;//C语言处理异常有缺陷,返回值不统一,返回值只有一个,无法区分是结果还是异常//int ret = myDivision(a, b);//if (ret == -1)//{//	cout << "异常" << endl;//}try{myDivision(a, b);}catch (int){cout << "int类型异常捕获" << endl;}catch (char){cout << "char类型异常捕获" << endl;}catch (double){//捕获到了异常,但是不想处理,继续向上抛出这个异常//异常必须有函数进行处理,如果没有任何处理,程序自动调用terminate函数,让程序中断throw;cout << "double类型异常捕获" << endl;}catch (MyException e){e.printError();}catch (...){cout << "其他类型异常捕获" << endl;}}int main()
{try{test01();}catch (double){cout << "main函数中double类型异常捕获" << endl;}catch (...){cout << "main函数中其它类型异常捕获" << endl;}system("pause");return 0;
}

C++中异常机制和函数机制并不互相干涉,但是捕获方式是通过严格的类型匹配。

异常被抛出后,从进入try代码块开始,到异常被抛掷之前,这期间在栈上构造的所有对象都会被自动析构。析构的顺序与构造的顺序相反,这一过程被称为栈的解旋。

为了加强程序的可读性,我们也可以在函数申明中列出可能抛出的异常的所有类型,例如void func() throw(A, B, C);这个函数func只能抛出类型为A、B、C以及其子类类型的异常。如果throw后的括号为空,则这个函数不能够抛出任何异常。如果函数的声明中没有包含结构声明,则函数可以抛出任意类型的异常。如果一个声明了接口的函数抛出了不允许抛出的异常,则会调用unexpected函数,该函数的默认行为是调用terminate函数中断程序。异常变量也是有声明周期的,声明周期和之前将的普通变量是类似的。异常变量也是有生命周期的,示例代码如下。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <string>class MyException
{
public:MyException(){cout << "MyException默认构造函数调用" << endl;}MyException(const MyException &e){cout << "MyException拷贝构造函数调用" << endl;}~MyException(){cout << "MyException析构函数调用" << endl;}
};void doWork()
{throw new MyException();
}int main()
{try{doWork();}//抛出的是throw MyException(); catch(MyException e) 调用拷贝构造函数,效率低//抛出的是throw MyException(); catch(MyException &e) 只调用默认构造,效率高推荐//抛出的是 throw &MyException(); catch(MyException *e) 对象会提前释放掉,不能在非法操作//抛出的是 new MyException(); catch(MyException *e) 只调用默认构造函数 自己要管理释放catch (MyException *e){cout << "自定义异常捕获" << endl;delete e;}system("pause");return 0;
}

异常也是有多态的,父类的引用或者指针指向子类的对象。使用的方法和前面类中的多态是一样的,在异常捕获的时候,我们常用这个,示例代码如下。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;//异常的基类
class BaseException
{
public:virtual void printError() = 0;
};//空指针异常
class NULLPointerException :public BaseException
{
public:virtual void printError(){cout << "空指针异常" << endl;}
};//越界异常
class OutOfRangeException :public BaseException
{
public:virtual void printError(){cout << "越界异常" << endl;}
};void doWork()
{//throw NULLPointerException();throw OutOfRangeException();
}int main()
{try{doWork();}catch (BaseException &e){e.printError();}system("pause");return 0;
}

2.2 C++标准异常库

除了前面的自己编写的异常之外,标准库中也为我们提供了很多的异常类,他们是通过类的继承组织起来的。

在这里插入图片描述
所有的异常都继承一个公共的基类exception。每个类都有提供的了构造函数、拷贝构造函数和赋值操作。其中在logic_error类与runtime_error类以及它们的子类都有一个构造函数接收一个string类型参数用于描述异常的信息。所有的异常都有一个what()函数,该函数是一个常函数,返回的是const char *类型的值用于描述异常的信息。所有我们要输出异常的信息可以通过打印异常类中的what()函数的返回值即可。下面给出一些标准异常类的描述:

异常名称描述
exception所有标准异常类的基类
bad_alloc在堆区开辟内存失败的时候,比如使用new或者new[]申请空间
bad_exception当函数的接口声明了抛出bad_exception异常,而函数中抛出了接口没有声明的异常,调用unexpected函数若抛出异常,则无论什么异常都会被自动替换被bad_exception类型异常
bad_cast使用动态类型转换引用失败的时候抛出的异常
ios_base::failureIO操作过程中出现错误
logic_error逻辑错误,也在运行前检测的错误
length_error试图生成一个操作该类型最大长度的对象抛出的异常
domain_error参数的值域错误,主要出现在数学函数中
out_of_range超出有效范围
invalid_argument参数不合适
runtime_error运行时错误,在运行时才能检测到的错误
range_error计算结果超出了有意义的值域范围
overflow_error算术计算上溢
underflow_error算术计算结果下溢

例如下面代码就是用了系统标准库提供的异常类。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;class Person
{
public:Person(int age){if (age < 0 || age > 150){//throw out_of_range("年龄必须在 0 ~ 150 之间");throw length_error("年龄必须在 0 ~ 150 之间");}else{this->age = age;}}int age;
};int main()
{try{Person p(151);}catch (out_of_range &e){cout << e.what() << endl;}catch (length_error &e){cout << e.what() << endl;}system("pause");return 0;
}

标准库中的异常类是有限的,有时候我们也需要自己的异常类。在自己写异常类的时候,最好自己写的类要继承标准库中的异常类,同时也应该重载父类中的what函数,示例代码如下。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <string>class MyOutOfRangeException :public exception
{
public:MyOutOfRangeException(const char *str){//const char * 可以隐式类型转换为string, 反之不可以this->errorInfo = str;}MyOutOfRangeException(string str){this->errorInfo = str;}virtual const char * what() const{//将string转为const char *return this->errorInfo.c_str();}string errorInfo;
};class Person
{
public:Person(int age){if (age < 0 || age > 150){throw MyOutOfRangeException("年龄必须在0到150之间");}else{this->age = age;}}int age;
};int main()
{try{Person p(1000);}catch (exception &e){cout << e.what() << endl;}system("pause");return 0;
}

3. 输入输出流

3.1 输入输出流概念以及流类库

程序的输入是指从文件将数据输入给程序,而程序的输出是将数据从程序输出给文件。C++中的输入分为三类,分别是标准I/O、文件I/O、串I/O。标准I/O是对系统指定的标准设备的输入与输出,比如鼠标键盘显示器等。文件I/O是以外存磁盘文件为对象进行输入输出。串I/O是对内存中指定的空间进行输入和输出,通常以字符数组作为空间的形式。

C++中提供了用于标准输入输出的iostream类库,也提供了用于文件输入输出的fstream类库以及串输入输出的strstream类库。

在这里插入图片描述
在这里插入图片描述

我们来详细看一下其中的常见类名。

类名 |作用 | 头文件
ios | 抽象基类 | iostream
istream | 通用输入流和其它输入流的基类 | iostream
ostream | 通用输出流和其它输出流的基类 | iostream
iostream | 通用输入输出流和其它输入输出流的基类 | iostream
ifstream | 输入文件流类 | fstream
ofstream | 输出文件流类 | fstream
fstream | 输入输出文件流类 | fstream
istrstream | 输入字符串流类 | strstream
ostrstream | 输出字符串流类 | strstream
strstream | 输入输出字符串流类 | strstream

iostream类库中的不同的类声明放在不同的头文件中,用户在自己的程序中#include相关的头文件就相当于声明了所需要用到的类。常用的头文件有以下:

  • iostream:包含了对输入输出流进行操作的所需基本信息。
  • fstream:用于用户管理的文件的I/O操作。
  • strstream:用于字符串流I/O。
  • stdiostream:用于混合使用C和C++的I/O机制。
  • iomanip:在使用格式化I/O时应该包含此头文件。

iostream中有四种流对象,分别如下:

对象含义设备对应的类C语言中对应的标准文件
cin标准输入流键盘istream_withassignstdin
cout标准输出流屏幕ostream_withassignstdout
cerr标准错误流屏幕ostream_withassignstderr
clog标准错误流屏幕ostream_withassignstderr

cout是console output的缩写,意思是在控制台输出。cout不是关键字,而是ostream的一个对象,在iostream中有定义。在cout中重载了左移运算符用于输出。使用<<的时候用户可以不必考虑是什么类型,系统自动判断数据的类型并且根据其类型调用与之匹配的运算符重载函数。而在C语言中输出是非常麻烦的,因为需要记住很多格式字符。cout流在内存中对一个开辟了一个缓冲区,用于存放流中的数据,当cout流插入一个endl时,无论缓冲区是否满,都会立即输出流中的所有数据,然后插入一个换行符并清空缓冲区。

cerr流对象是标准错误流,cerr流被指定为与显示器相关联。作用是在标准错误设备上输出相关出错信息。cerr与标准输出流cout的作用和用法差不多,但是有一点不同。cout通常是传送到显示屏输出,也可以被重定向输出到磁盘文件,而cerr流中的信息只能在显示器上输出。

clog流对象也是标准错误流,是console log的缩写。它的作用和cerr的作用相同,都是在显示器终端上输出出错信息。但是不同的是cerr是不经过缓冲区直接向显示器输出有关信息,而clog中的信息放在缓冲区中,缓冲区满后或者遇到endl时向显示器输出。

3.2 标准输入流

标准输入流对象是cin,在里面有几个比较重点的函数。

  • cin.get() :一次从输入缓冲区内读取一个字符。
  • cin.get(n):一次从输入缓冲区内读取n个字符。
  • cin.get(buf, n):一次从输入缓冲区内读取长度为n个字符存入buf中。
  • cin.getline(buf, n):一次从输入缓冲区内读取一行的数据将最多n个存入buf中。
  • cin.ignore():忽略一个字符,如果括号有参数就是忽略n个字符。
  • cin.peek():偷窥输入缓冲区的第一个字符。
  • cin.putback(ch):将字符ch放回输入缓冲区。
  • cin.clear():清空缓冲区。
  • cin.sync():重置标志位,标志位为1表示异常,为0表示正常。
  • cin.fail():获取缓冲区标志位,返回的结果为0或者1

上述标准输入流对象的函数示例如下。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;/*
cin.get() //一次只能读取一个字符
cin.get(一个参数) //读取一个字符
cin.get(两个参数) //可以读字符串
cin.getline()
cin.ignore()
cin.peek()
cin.putback()
*/void test01()
{char c = cin.get();cout << "c = " << c << endl;c = cin.get();cout << "c = " << c << endl;c = cin.get();cout << "c = " << c << endl;c = cin.get();cout << "c = " << c << endl;
}void test02()
{char buf[1024] = { 0 };cin.get(buf, 1024);char c = cin.get();//利用cin.get获取字符串的时候,换行符遗留在缓冲区中if (c == '\n'){cout << "换行符遗留在缓冲区" << endl;}else{cout << "换行符不在缓冲区" << endl;}cout << buf << endl;
}void test03()
{char buf[1024] = { 0 };//利用cin.getline获取字符串时候,换行符不会被取走,也不再缓冲区中,而是直接扔掉cin.getline(buf, 1024);char c = cin.get();if (c == '\n'){cout << "换行符遗留在缓冲区" << endl;}else{cout << "换行符不在缓冲区" << endl;}cout << buf << endl;
}//cin.ignore忽略 默认忽略一个字符,如果填入参数X,代表忽略X个字符
void test04()
{cin.ignore(2);char c = cin.get();cout << "c = " << c << endl;
}//cin.peek 偷窥
void test05()
{char c = cin.peek();cout << "c = " << c << endl;c = cin.get();cout << "c = " << c << endl;c = cin.get();cout << "c = " << c << endl;
}//cin.putback() 返回
void test06()
{char c = cin.get();cin.putback(c);char buf[1024] = { 0 };cin.getline(buf, 1024);cout << buf << endl;
}//案例1. 判断用户输入的内容是字符串还是数字
void test07()
{cout << "请输入一个字符串或者数字" << endl;char c = cin.peek();if (c >= '0' && c <= '9'){int num;cin >> num;cout << "您输入的是数字 为: " << num << endl;}else{char buf[1024] = { 0 };cin >> buf;cout << "您输入的是字符串 : " << buf << endl;}
}// 案例2 用户输入0~1之间的数字,如果输入有误重新输入
void test08()
{cout << "请输入0 ~ 10之间的数字" << endl;int num;while (true){cin >> num;if (num >= 0 && num <= 10){cout << "输入正确, 输入的值为: " << num << endl;break;}// 清空缓冲区,重置标志位cin.clear();//cin.sync();//cin.ignore(); //vs2013以上版本加入// 如果标志位为0,代表缓冲区正常 如果标志位为1,缓冲区异常cout << "cin.fail() = " << cin.fail() << endl;cout << "输入有误,请重新输入:" << endl;}
}int main()
{//test01();//test02();//test03();//test04();//test05();//test06();//test07();test08();system("pause");return 0;
}

3.3 标准输出流

C++中的输出是通过标准输出流cout完成的。以下是关于标准输出流的函数。

  • cout.flush():刷新缓冲区。
  • cout.put(ch):向缓冲区中写入字符ch
  • cout.write(str, n):向缓冲区中输出str字符串的前n个字符。

在C语言中我们使用格式字符通过printf去控制输出的格式,在C++中我们通过流对象cout中用于控制输出格式的成员函数来控制输出格式。常见控制输出格式的成员函数如下:

流成员函数与之相同作用的控制符作用
precision(n)setprecision(n)设置实数的精度为n位
width(n)setw(n)设置字段宽度为n位
fill(c)setfill(c)设置填充字符c
setf()setiosflags()设置输出格式状态,括号中应给出格式状态,内容与控制符setiosflags括号中的内容相同
unsetf()resetiosflags()终止已设置的输出格式状态,在括号中应指定内容

流成员函数setf和控制符setiosflags库昊中的参数表示格式状态,它是通过格式标志来指定的。格式标志在类ios中被定义为枚举值,因此在引用这些的时候需要加上类名ios以及作用域运算符::,下面是格式标志。

格式标志作用
ios::left输出数据在本域宽范围内向左对齐
ios::right输出数据在本域宽范围内向右对齐
ios::internal数值的符号为应在域宽内左对齐,数值右对齐,中间由填充字符填充
ios::dec设置整数的基数为10
ios::oct设置整数的基数为8
ios::hex设置整数的基数为16
ios::showbase强制输出整数的基数(八进制数以0开头,十六进制数以0x开头)
ios::showpoint强制输出浮点数的小数和尾数0
ios::uppercase在以科学计数法格式E和以十六进制输出字母时以大写表示
ios::showpos对正数显示+号
ios::scientific浮点数以科学计数法格式输出
ios::fixed浮点数以定点格式(小数形式)输出
ios::unitbuf每次输出之后刷新所有的流
ios::stdio每次输出之后清除stdoutstderr

关于控制符如下:

控制符作用
dec设置数值的基数为10
hex设置数值的基数为16
oct设置数值的基数为8
setfill(c)设置填充字符c,c可以是字符常量或者字符变量
setprecision(n)设置浮点数的精度为n位。在以十进制小数形式输出时,n代表有效数字。在以fixed(固定小数位数)形式和scientific(指数)形式输出时,n为小数位数
setw(n)设置字段宽度为n位
setiosflags(ios::fixed)设置浮点数以固定的小数位显示
setiosflags(ios::scientific)设置浮点数以科学计数法(即指数形式) 显示
setiosflags(ios::left)输出数据左对齐
setiosflags(ios::right)输出数据右对齐
setiosflags(ios::skipws)忽略前导的空格
setiosflags(ios::uppercase)数据以十六进制形式输出时字母以大写表示
setiosflags(ios::lowercase)数据以十六进制形式输出时字母以小写表示
setiosflags(ios::showpos)输出正数时给出+号

需要注意的是如果使用了控制符,在程序开头还需要添加iomanip.h头文件。成员函数width(n)和控制符setw(n)只对其后面的第一个输出项有效。 在上面设置数值基数的只能选择其中一种来使用,它们是相互排斥的。对于成员函数setf和控制符setiosflags设置的输出格式状态,如果想要改变使用另一个状态,应该调用成员函数unsetf或者控制符resetiosflags终止原来设置的状态。在使用setf函数设置格式状态时,可以包含两个甚至多个状态,这些格式标志在ios类中被定义为枚举值,每一个格式标志都是以一个二进制位表示的,因此可以使用位运算符|组合多个格式标志。

关于输出流对象的示例代码如下。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <iomanip> // 控制符格式化输出 头文件/*
cout.put() //想缓冲区写入字符
cout.write() //从buffer中写num个字节到当前输出流中
*/
void test01()
{//cout.put('h').put('e');char buf[] = "hello world";cout.write(buf, strlen(buf));cout << "hello world" << endl;
}// 1.通过流成员函数格式化输出
void test02()
{int number = 99;cout.width(20); // 指定宽度为20cout.fill('*'); // 填充cout.setf(ios::left); // 左对齐cout.unsetf(ios::dec); // 卸载十进制cout.setf(ios::hex); // 安装十六进制cout.setf(ios::showbase); // 显示基数cout << number << endl;
}// 2. 使用控制符格式化输出
void test03()
{int number = 99;cout << setw(20)	// 设置宽度<< setfill('~') // 设置填充<< hex // 显示16进制<< setiosflags(ios::showbase) // 显示基数<< setiosflags(ios::left) // 左对齐<< number << endl;
}int main()
{//test01();//test02();test03();system("pause");return 0;
}

3.4 文件读写

文件读写主要在fstream.h头文件中被定义,这里面定义了三个类,分别是ifstreamofstreamfstream,它们之间的继承关系如下。

在这里插入图片描述
进行文件读写的第一步就是要先打开文件,打开文件有两种方法。

第一种是调用文件流对象的open成员函数,该函数的第一个参数文件路径,第二个参数是打开的方式。第二种方式使用文件流定义的参数构造函数,如下。

// 第一种方法
ofstream ofs;
ofs.open("./demo1.txt", ios::out);// 第二种方法
ofstream ofs("./demo1.txt", ios::out);

文件输入输出的方式设置值如下。

方式作用
ios::in以输入方式打开文件
ios::out以输出方式打开文件(这是默认方式),如果已经有此名字的文件,则将其原有内容直接全部清空
ios::app以输出方式打开文件,写入的数据添加在文件末尾
ios::ate打开一个已有的文件,文件指针指向文件末尾
ios::trunc打开一个文件,如果文件已存在,则删除其中全部数据,若文件不存在,则建立新文件。如已经使用ios::out方式打开,而未指定ios::appios::ateios::in,则同时默认此方式
ios::binary以二进制方式打开一个文件,如不指定此方式默认为ASCII方式
ios::nocreate打开一个已有的文件,如文件不存在,则打开失败。
ios::noreplace如果文件不存在则简历新文件,如果文件已存在则操作失败
ios::in | ios::out以输入和输出方式打开文件,文件可读可写
ios::out | ios::binary以二进制方式打开一个输出文件
ios::in | ios::binary以二进制方式打开一个输入文件

上面的输入输出方式设置可以使用位运算符中的或|进行组合。如果打开操作失败,open函数的返回值为假,如果是调用构造函数的方式打开文件,则流对象的值为0。

对文件读写操作完成后,应该关闭相关的文件。关闭用成员函数close完成。关闭就是解除改文件与文件流的关联,同样原来设置的工作方式也会失效,这样就不能再通过文件流对该文件进行输入和输出。

C++中对ASCII文件读写操作也可以使用左移或者右移运算符。<<表示刘插入运算符,而>>表示流提取运算符。这两用法和cin以及cout是一样的。在文件流中,常使用putgetgetline等成员函数进行字符的输入输出。put()输出单个字符,get()读取一个字符,getline()读取一行字符。

关于文件读写的示例代码如下。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <fstream>
#include <string>void test01()
{// 写文件 输出ofstream ofs("./test.txt", ios::out | ios::trunc);//ofs.open("./test.txt", ios::out | ios::trunc); 设置打开方式 以及路径if (!ofs.is_open()){cout << "文件打开失败" << endl;return;}ofs << "姓名:孙悟空" << endl;ofs << "年龄:999" << endl;ofs << "性别:女" << endl;// 关闭文件ofs.close();
}void test02()
{// 读文件ifstream ifs;ifs.open("./test.txt", ios::in);if (!ifs.is_open()){cout << "文件打开失败" << endl;return;}// 第一种方式//char buf[1024] = { 0 };//while (ifs >> buf)//{//	cout << buf << endl;//}// 第二种方式//char buf[1024] = { 0 };//while (ifs.getline(buf, 1024))//{//	cout << buf << endl;//}// 第三种方式//string buf;//while (getline(ifs, buf))//{//	cout << buf << endl;//}// 第四种方式char c;while ((c = ifs.get()) != EOF){cout << c;}
}int main()
{test01();test02();system("pause");return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/145586.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

图像分类系列(二) VGGNet学习详细记录

经典神经网络论文超详细解读&#xff08;二&#xff09;——VGGNet学习笔记&#xff08;翻译&#xff0b;精读&#xff09; 前言 上一篇我们介绍了经典神经网络的开山力作——AlexNet&#xff1a;经典神经网络论文超详细解读&#xff08;一&#xff09;——AlexNet学习笔记&a…

C生万物 | 从浅入深理解指针【最后部分】

C生万物 | 从浅入深理解指针【最后部分】 文章目录 C生万物 | 从浅入深理解指针【最后部分】前言sizeof和strlen的对比sizeofstrlen 数组和指针笔试题解析一维数组字符数组二维数组 前言 我们前面学了四个部分了&#xff0c;如果没有看前面的建议可以看一下前面的~~ C生万物 |…

java架构师禁止在项目中使用继承,合理吗?

java架构师禁止在项目中使用继承&#xff0c;合理吗&#xff1f; 如果建议用组合替代继承&#xff0c;非必要不用继承&#xff0c;这个很合理的建议的。 在非必要的情况下不用继承&#xff0c;用组合替代有几个优势&#xff1a;最近很多小伙伴找我&#xff0c;说想要一些 Jav…

元宇宙3D云展厅应用到汽车销售的方案及特点

为了紧紧抓住年轻消费者的需求&#xff0c;汽车销售行业也正在经历一场深刻的变革。在这个变革的前沿&#xff0c;元宇宙3D汽车展厅作为一项全新技术闪亮登场&#xff0c;打破了传统汽车销售模式的限制&#xff0c;为消费者带来了前所未有的购车体验。 元宇宙3D汽车展厅采用了尖…

C语言调用【Python3】

一、搭建编译环境 终端查询系统及软件版本dpkg -l 列出所有已安装的软件包 二、C语言中调用Python 使用 GCC编译并链接 Python 3.10 的共享库如何在C中获取和修改 sys.path 三、C语言调用无参python函数 四、C语言调用有参python函数 一、搭建编译环境 通过C语言调用Pyth…

关于FreeRTOS函数xSemaphoreGiveFromISR卡死的问题

0. 概述 关于FreeRTOS函数xSemaphoreGiveFromISR卡死的问题 1. 遇到的问题 在使用FreeRTOS调试激光雷达检测面积的项目的时候&#xff0c;遇到一个现象&#xff1a;在新加了一个线程之后&#xff0c;把程序下载到板子之后程序不会运行&#xff08;实际上已经运行了&#xff…

【C语法学习】26 - strcat()函数

文章目录 1 函数原型2 参数3 返回值4 使用说明5 示例5.1 示例1 1 函数原型 strcat()&#xff1a;将src指向的字符串拼接在dest指向的字符串末尾&#xff0c;函数原型如下&#xff1a; char *strcat(char *dest, const char *src);2 参数 strcat()函数有两个参数src和dest&am…

uniapp插件开发

安装android studio&#xff1a;安装目录下bin下的此文件&#xff0c;是用来修改分配给android studio的占用内存。 Android 11足够用。 创建新项目&#xff1a; 目录结构介绍&#xff1a; UI组件介绍&#xff1a;在设计程序界面时可以使用可视化拖拽的方式&#xff0c;没有必要…

被 Next.js 的环境变量给坑了一把...

最近在使用 Next.js 时遇到了一个问题&#xff0c;最后原因竟是 .env 取值问题&#xff0c;为这个问题花费了数小时的时间&#xff0c;希望看到这篇文章的朋友&#xff0c;如果遇到类似问题&#xff0c;不要重蹈覆辙吧。 起初报错内容如下所示&#xff1a; 一开始关注点在下面…

ubuntu提高 github下载速度

Github一般用于Git的远程仓库&#xff0c;由于服务器位于国外&#xff0c;国内访问速度比较慢&#xff0c;为了提高访问速度&#xff0c;决定绕过DNS域名解析。 获取Github的IP地址 按下ctrl&#xff0b;alt&#xff0b;T打开命令终端&#xff0c;输入&#xff1a; nslookup gi…

玩具、儿童用品、儿童服装上亚马逊TEMU平台CPC认证办理

CPC认证是Childrens Product Certificate的简称&#xff0c;即儿童产品证书。它是美国强制性法规CPSIA要求的一部分&#xff0c;该法规主要针对12岁及以下儿童使用的产品&#xff0c;如玩具、儿童用品、儿童服装等。 一、儿童小汽车CPC测试项目可能会因产品标准和法规的不同而…

android初集成flutter,遇到的问题

环境 studio版本&#xff1a;2022.1.1 flutter版本&#xff1a;2.8.0 电脑&#xff1a;mac flutter项目总是报错&#xff0c;编译不过 以 Resources Root 加载 记得设置dart&#xff1a;主工程和flutter项目都需要设置&#xff0c;否则不出现手机链接 下面这个样子就是好了&…

窗口管理工具 Mosaic mac中文版功能特点

MosAIc mac是一种窗口管理工具&#xff0c;可帮助您在计算机屏幕上有效地组织和管理多个应用程序窗口。它提供了一种直观的方式来调整和排列窗口&#xff0c;以最大化工作效率。 MosAIc mac窗口管理软件功能和特点 窗口布局&#xff1a;MosAIc允许您选择不同的窗口布局&#x…

抠某区域地图方法

1.打开阿里云数据可视化平台DataV.GeoAtlas地理小工具系列 2. 选择要抠出来的区域&#xff0c;右侧选择要下载的json文件&#xff0c;如红框所示 3. 打开下载的文件&#xff0c;内容全部复制。 4. 打开百度地图示例Examples - Apache ECharts 5. 如下图所示&#xff0c;将下…

数字化转型时代,商业智能BI到底是什么?

据国际数据公司&#xff08;IDC&#xff09;预测&#xff0c;2025年时中国产生的数据量预计将达48.6ZB&#xff0c;在全球中的比例为27.8%。商业智能BI这一专为企业提供服务的数据类解决方案&#xff0c;仅2021年上半年在中国商业智能BI市场规模就达到了3.2亿美元&#xff0c;商…

(二)什么是Vite——Vite 和 Webpack 区别(冷启动)

vite分享ppt&#xff0c;感兴趣的可以下载&#xff1a; ​​​​​​​Vite分享、原理介绍ppt 什么是vite系列目录&#xff1a; &#xff08;一&#xff09;什么是Vite——vite介绍与使用-CSDN博客 &#xff08;二&#xff09;什么是Vite——Vite 和 Webpack 区别&#xff0…

电源线虚接,导致信号线发烫

音频板的信号是经过隔直电容接到音频板的。

【ES6标准入门】JavaScript中的模块Module的加载实现:循环加载和Node加载,非常详细,建议收藏!!!

&#x1f601; 作者简介&#xff1a;一名大四的学生&#xff0c;致力学习前端开发技术 ⭐️个人主页&#xff1a;夜宵饽饽的主页 ❔ 系列专栏&#xff1a;JavaScript进阶指南 &#x1f450;学习格言&#xff1a;成功不是终点&#xff0c;失败也并非末日&#xff0c;最重要的是继…

IDEA写mybatis程序,java.io.IOException:Could not find resource mybatis-config.xml

找不到mybatis-config.xml 尝试maven idea:module&#xff0c;不是模块构造问题 尝试检验pom.xml&#xff0c;在编译模块添加了解析resources内容依旧不行 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.or…

chrome 浏览器个别字体模糊不清

特别是在虚拟机里&#xff0c;有些字体看不清&#xff0c;但是有些就可以&#xff0c;设置办法&#xff1a; chrome://settings/fonts 这里明显可以看到有些字体就是模糊的状态&#xff1a; 把这种模糊的字体换掉即可解决一部分问题。 另外&#xff0c;经过观察&#xff0c;…