C++基础13:C++输入输出

此专栏为移动机器人知识体系下的编程语言中的 C {\rm C} C++从入门到深入的专栏,参考书籍:《深入浅出 C {\rm C} C++》(马晓锐)和《从 C {\rm C} C C {\rm C} C++精通面向对象编程》(曾凡锋等)。



12.C++输入/输出
12.1 C++流类
  • 计算机的输入和输出是数据传送的过程, C {\rm C} C++将数据的传送过程称为流 ( s t r e a m ) ({\rm stream}) (stream)

  • C {\rm C} C++的 I / O {\rm I/O} I/O流是由若干字节组成的字节序列,称为字节流,字节流中的数据可以是多种形式的,包括:二进制数据、 A S C I I {\rm ASCII} ASCII字符、数字化视频和音频、数字图像信息等;

  • 在进行数据传输时,数据会被从一个对象传送到另一个对象中,这些对象包括:内存、输出设备、输入设备,当进行输入操作时,字节流是从输入设备流向内存,当进行输出操作时,字节流是从内存输出到输出设备;

  • 内存缓冲区:是系统为数据流开辟的一个内存空间,用于存放流中的数据;如果利用输入/输出操作对流进行传送,系统先将数据存入缓冲区中,当缓冲区满或遇到特定的输出指令时,才将这些数据进行传送;

  • c o u t {\rm cout} cout向屏幕输出时,系统将输出的内容先保存在为其开辟的缓冲区内,当此缓冲区满或遇到 e n d l {\rm endl} endl时,才将数据传送到屏幕上显示;利用 c i n {\rm cin} cin进行输入操作时,数据先保存在键盘输入缓冲区,遇到回车时将数据传送到程序输入缓冲区,当程序遇到 < < {\rm <<} <<操作符时,输入缓冲区的数据会被赋予相关的变量;

  • 系统提供缓冲区机制的目的:为了减少数据传送频度,以提高 I / O {\rm I/O} I/O效率;

  • C {\rm C} C++中,输入/输出流被定义为一系列的类,这些类称为流类 ( s t r e a m c l a s s ) ({\rm stream\ class}) (stream class),这些类被包含在 I / O {\rm I/O} I/O类库中,其输入输出包括如下方面的内容:

    • 标准 I / O {\rm I/O} I/O:对系统指定的标准设备,如:显示器、打印机等的输入和输出;
    • 文件 I / O {\rm I/O} I/O:对外存磁盘或外存储设备文件进行输入和输出;
    • 内存 I / O {\rm I/O} I/O(串 I / O {\rm I/O} I/O):对内存中的空间进行输入和输出;
  • 常用的 I / O {\rm I/O} I/O操作类如下表:

    类名 类名 类名 作用 作用 作用 头文件 头文件 头文件
    i o s {\rm ios} ios 输入 / 输出抽象基类 输入/输出抽象基类 输入/输出抽象基类 i o s t r e a m {\rm iostream} iostream
    i s t r e a m {\rm istream} istream 通用输入流和其他输入流基类 通用输入流和其他输入流基类 通用输入流和其他输入流基类 i o s t r e a m {\rm iostream} iostream
    o s t r e a m {\rm ostream} ostream 通用输出流和其他输出流基类 通用输出流和其他输出流基类 通用输出流和其他输出流基类 i o s t r e a m {\rm iostream} iostream
    i o s t r e a m {\rm iostream} iostream 通用输入 / 输出流和其他输入 / 输出流基类 通用输入/输出流和其他输入/输出流基类 通用输入/输出流和其他输入/输出流基类 i o s t r e a m {\rm iostream} iostream
    i f s t r e a m {\rm ifstream} ifstream 输入文件流类 输入文件流类 输入文件流类 f s t r e a m {\rm fstream} fstream
    o f s t r e a m {\rm ofstream} ofstream 输出文件流类 输出文件流类 输出文件流类 f s t r e a m {\rm fstream} fstream
    f s t r e a m {\rm fstream} fstream 输入 / 输出文件流类 输入/输出文件流类 输入/输出文件流类 f s t r e a m {\rm fstream} fstream
    i s t r s t r e a m {\rm istrstream} istrstream 输入字符串流 输入字符串流 输入字符串流 s t r s t r e a m {\rm strstream} strstream
    o s t r s t r e a m {\rm ostrstream} ostrstream 输出字符串流 输出字符串流 输出字符串流 s t r s t r e a m {\rm strstream} strstream
    s t r s t r e a m {\rm strstream} strstream 输入 / 输出字符串流 输入/输出字符串流 输入/输出字符串流 s t r s t r e a m {\rm strstream} strstream
  • 常用的 I / O {\rm I/O} I/O操作流类之间的关系图:

    17

  • 几个常用的流类:

    • i o s t r e a m {\rm iostream} iostream:基本输入/输出流操作;
    • s t r e a m {\rm stream} stream:用于文件的 I / O {\rm I/O} I/O操作;
    • s t r s t r e a m {\rm strstream} strstream:用于字符串流输入/输出;
    • i o m a n i p {\rm iomanip} iomanip:用于对流中的数据进行格式化输入/输出;
12.2 流对象和格式化输出
  • i o s t r e a m {\rm iostream} iostream头文件中,定义了许多相关的类,如: i o s 、 i s t r e a m 、 o s t r e a m 、 i o s t r e a m {\rm ios、istream、ostream、iostream} iosistreamostreamiostream等,还定义了 4 4 4种常用的流对象,如下表所示:

    对象 对象 对象 含义 含义 含义 对应设备 对应设备 对应设备 对应的类 对应的类 对应的类
    c i n {\rm cin} cin 标准输入流 标准输入流 标准输入流 键盘 键盘 键盘 i s t r e a m _ w i t h a s s i g n {\rm istream\_withassign} istream_withassign
    c o u t {\rm cout} cout 标准输出流 标准输出流 标准输出流 显示器 显示器 显示器 o s t r e a m _ w i t h a s s i g n {\rm ostream\_withassign} ostream_withassign
    c e r r {\rm cerr} cerr 标准错误流 标准错误流 标准错误流 显示器 显示器 显示器 o s t r e a m _ w i t h a s s i g n {\rm ostream\_withassign} ostream_withassign
    c l o g {\rm clog} clog 标准输出流 标准输出流 标准输出流 显示器 显示器 显示器 o s t r e a m _ w i t h a s s i g n {\rm ostream\_withassign} ostream_withassign
    • c i n {\rm cin} cin:标准输入流,是类 i s t r e a m _ w i t h a s s i g n {\rm istream\_withassign} istream_withassign的对象,作用为从系统指定的标准输入设备输入数据到程序变量中;
    • c o u t {\rm cout} cout:标准输出流,是类 o s t r e a m _ w i t h a s s i g n {\rm ostream\_withassign} ostream_withassign的对象,作用是将内存数据输出到系统指定的输出设备上;
    • c e r r {\rm cerr} cerr:标准错误流,是类 o s t r e a m {\rm ostream} ostream的对象,作用为向系统指定的标准输出设备输出错误信息;
    • c l o g {\rm clog} clog:标准输出流,是类 o s t r e a m {\rm ostream} ostream的对象,作用为向系统指定的标准输出设备输出日志信息, c e r r {\rm cerr} cerr没有缓冲区, c l o g {\rm clog} clog具有缓冲区,即 c e r r {\rm cerr} cerr结果会立即被显示到输出设备上, c l o g {\rm clog} clog在缓冲区满或遇到 e n d l {\rm endl} endl时才显示;
  • 对输出数据进行格式化称为流格式化输出,如果需要控制流输出的格式,一是使用流格式控制符,二是利用流类的相关成员函数进行控制;

  • 流格式控制符在头文件 i o m a n i p {\rm iomanip} iomanip中定义,使用控制符时需要包含头文件 i o m a n i p {\rm iomanip} iomanip,常用的输入/输出流控制符如下表:

    控制符 控制符 控制符 控制符作用 控制符作用 控制符作用
    d e c {\rm dec} dec 置基数为 10 , 相当 于 ′ % d ′ 置基数为10,相当于'\%{\rm d}' 置基数为10,相当%d
    h e x {\rm hex} hex 置基数为 16 , 相当 于 ′ % X ′ 置基数为16,相当于'\%{\rm X}' 置基数为16,相当%X
    o c t {\rm oct} oct 置基数为 8 , 相当 于 ′ % o ′ 置基数为8,相当于'\%{\rm o}' 置基数为8,相当%o
    s e t b a s e ( n ) {\rm setbase(n)} setbase(n) 置基数为 n 置基数为{\rm n} 置基数为n
    s e t f i l l ( c ) {\rm setfill(c)} setfill(c) 设置填充字符为 c 设置填充字符为{\rm c} 设置填充字符为c
    s e t p r e c i s i o n ( n ) {\rm setprecision(n)} setprecision(n) 设置显示小数精度为 n 位 设置显示小数精度为{\rm n}位 设置显示小数精度为n
    s e t w ( n ) {\rm setw(n)} setw(n) 设置域宽为 n 个字符 设置域宽为{\rm n}个字符 设置域宽为n个字符
    s e t i o s f l a g s ( i o s : : f i x e d ) {\rm setiosflags(ios::fixed)} setiosflags(ios::fixed) 固定的浮点显示 固定的浮点显示 固定的浮点显示
    s e t i o s f l a g s ( i o s : : s c i e n t i f i c ) {\rm setiosflags(ios::scientific)} setiosflags(ios::scientific) 指数表示 指数表示 指数表示
    s e t i o s f l a g s ( i o s : : l e f t ) {\rm setiosflags(ios::left)} setiosflags(ios::left) 左对齐 左对齐 左对齐
    s e t i o s f l a g s ( i o s : : r i g h t ) {\rm setiosflags(ios::right)} setiosflags(ios::right) 右对齐 右对齐 右对齐
    s e t i o s f l a g s ( i o s : : s k i p w s ) {\rm setiosflags(ios::skipws)} setiosflags(ios::skipws) 忽略前导空白 忽略前导空白 忽略前导空白
    s e t i o s f l a g s ( i o s : : u p p e r c a s e ) {\rm setiosflags(ios::uppercase)} setiosflags(ios::uppercase) 十六进制大写输出 十六进制大写输出 十六进制大写输出
    s e t i o s f l a g s ( i o s : : l o w e r c a s e ) {\rm setiosflags(ios::lowercase)} setiosflags(ios::lowercase) 十六进制小写输出 十六进制小写输出 十六进制小写输出
    s e t i o s f l a g s ( i o s : : s h o w p o i n t ) {\rm setiosflags(ios::showpoint)} setiosflags(ios::showpoint) 强制显示小数点 强制显示小数点 强制显示小数点
    s e t i o s f l a g s ( i o s : : s h o w p o s ) {\rm setiosflags(ios::showpos)} setiosflags(ios::showpos) 强制显示符号 强制显示符号 强制显示符号
  • 控制符实例:用控制符控制数据输出格式 ( e x a m p l e 12 _ 1. c p p ) ({\rm example12\_1.cpp}) (example12_1.cpp)

    /*** 作者:罗思维* 时间:2024/03/31* 描述:用控制符控制数据输出格式。 */
    #include <iostream>
    #include <iomanip>using namespace std;int main() {int iNumber;cout << "请输入一个数字:";cin >> iNumber;cout << "iNumber十进制:" << dec << iNumber << endl;cout << "iNumber十六进制:" << hex << iNumber << endl;cout << "iNumber八进制:" << setbase(8) << iNumber << endl;char *pStr = (char*)"Welcome";		// pStr指向字符串"Welcome"; cout << setw(20) << pStr << endl;	// 设置域宽为20,输出字符串; cout << setfill('-') << setw(20) << pStr << endl;	// 设置域宽为20,输出字符串,空白处用-填充; double dNumber = 5.845201314;cout << setiosflags(ios::scientific) << setprecision(8);cout << "dNumber = " << dNumber << endl;cout << "dNumber = " << setprecision(4) << dNumber << endl;			cout << "dNumber = " << setiosflags(ios::fixed) << dNumber << endl;	// 小数形式输出; return 0;
    }
    
  • 流对象 c o u t {\rm cout} cout常用的控制输出格式的成员函数如下:

    成员函数 成员函数 成员函数 对应的控制符 对应的控制符 对应的控制符 作用 作用 作用
    p r e c i s i o n ( n ) {\rm precision(n)} precision(n) s e t p r e c i s i o n ( n ) {\rm setprecision(n)} setprecision(n) 设置显示小数精度为 n 位 设置显示小数精度为{\rm n}位 设置显示小数精度为n
    w i d t h ( n ) {\rm width(n)} width(n) s e t w ( n ) {\rm setw(n)} setw(n) 设置输出宽度为 n 位 设置输出宽度为{\rm n}位 设置输出宽度为n
    f i l l ( c ) {\rm fill(c)} fill(c) s e t f i l l ( c ) {\rm setfill(c)} setfill(c) 当输出长度不足输出长度时 , 设置填充字符 c 当输出长度不足输出长度时,设置填充字符{\rm c} 当输出长度不足输出长度时,设置填充字符c
    s e t f ( f l a g ) {\rm setf(flag)} setf(flag) s e t i o s f l a g s ( f l a g ) {\rm setiosflags(flag)} setiosflags(flag) 设置输出格式状况 设置输出格式状况 设置输出格式状况
    u n s e t f ( ) {\rm unsetf()} unsetf() r e s e t i o s f l a g s ( ) {\rm resetiosflags()} resetiosflags() 终止已设置的输出格式状态 终止已设置的输出格式状态 终止已设置的输出格式状态

    设置格式状态的格式标志:

    • 对齐方式:
      • i o s : : l e f t {\rm ios::left} ios::left:输出数据左对齐;
      • i o s : : r i g h t {\rm ios::right} ios::right:输出数据右对齐;
      • i o s : : i n t e r n a l {\rm ios::internal} ios::internal:数值的符号位左对齐,数值右对齐,中间由填充字符填充,如:输出的数值为 − 10 -10 10,输出长度为 5 5 5,填充字符位为 ∗ * ,则: − ∗ ∗ 10 -**10 10
    • 数值基数设定:
      • i o s : : d e c {\rm ios::dec} ios::dec:设置整数的基数为 10 10 10
      • i o s : : o c t {\rm ios::oct} ios::oct:设置整数的基数为 8 8 8
      • i o s : : h e x {\rm ios::hex} ios::hex:设置整数的基数为 16 16 16
    • 整数格式控制:
      • i o s : : s h o w b a s e {\rm ios::showbase} ios::showbase:强制输出整数的基数;
      • i o s : : s h o w p o i n t {\rm ios::showpoint} ios::showpoint:强制输出浮点数的小数点和尾数 0 0 0
      • i o s : : u p p e r c a s e {\rm ios::uppercase} ios::uppercase:以科学记数法格式 E {\rm E} E和以十六进制输出字母时以大写表示;
      • i o s : : s h o w p o s {\rm ios::showpos} ios::showpos:对整数显示 + + +号;
    • 浮点数格式控制:
      • i o s : : s c i e n t i f i c {\rm ios::scientific} ios::scientific:浮点数以科学记数法格式输出;
      • i o s : : f i x e d {\rm ios::fixed} ios::fixed:浮点数以定点格式(小数形式)输出;
    • 流控制:
      • i o s : : u n i t b u f {\rm ios::unitbuf} ios::unitbuf:每次输出后刷新所有的流;
      • i o s : : s t d i o {\rm ios::stdio} ios::stdio:每次输出后清除 s t d o u t 、 s t d e r r {\rm stdout、stderr} stdoutstderr
  • 流控制成员函数实例:用流控制成员函数控制数据输出格式 ( e x a m p l e 12 _ 2. c p p ) ({\rm example12\_2.cpp}) (example12_2.cpp)

    /*** 作者:罗思维* 时间:2024/03/31* 描述:用流控制成员函数控制数据输出格式。 */
    #include <iostream>using namespace std;int main() {int nNumber = 80;// 进制的设置与取消设置;cout.setf(ios::showbase);cout << "nNumber十进制:" << nNumber << endl;cout.unsetf(ios::dec);cout.setf(ios::hex);cout << "nNumber十六进制:" << nNumber << endl;cout.unsetf(ios::hex);cout.setf(ios::oct);cout << "nNumber八进制:" << nNumber << endl;cout.unsetf(ios::oct);// 域宽与填充的设置与取消设置;char *pStr = (char*)"Welcome";cout.width(20);cout << pStr << endl;cout.width(20);cout.fill('-');cout << pStr << endl;// 小数输出形式设置;double dNumber = 5.845201314;cout.setf(ios::scientific);cout << "dNumber = ";cout.width(15);cout << dNumber << endl;cout.unsetf(ios::scientific);cout.setf(ios::fixed);cout.width(14);cout.setf(ios::showpos);cout.setf(ios::internal);cout.precision(5);cout << dNumber << endl;return 0;
    }
    
12.3 重载流运算符
  • 运算符重载的两种形式:重载为成员函数或重载为友元函数,重载插入运算符和提取运算符时,左边的参数是流,右边的参数是类的对象,因此,只能用友元函数的方式去重载插入运算符和提取运算符;

  • 插入运算符重载的语法格式:

    ostream& operator<<(ostream& os,const T& t)
    {...;	// 函数体;return os;
    }
    
    • 第一个参数:是对 o s t r e a m {\rm ostream} ostream对象的引用,函数返回值必须是这个引用对象;
    • 第二个参数:为输出的对象, T {\rm T} T是用户自定义的类, t {\rm t} t为该类的对象名;
  • 插入运算符重载实例:复数类的输出 ( C o m p l e x 1 ) ({\rm Complex1}) (Complex1)

    • C C o m p l e x {\rm CComplex} CComplex类定义头文件 ( C C o m p l e x . h ) ({\rm CComplex.h}) (CComplex.h)

      /*** 作者:罗思维* 时间:2024/03/31* 描述:复数类定义头文件。*/
      #include <iostream>using namespace std;class CComplex {protected:double real;				// 复数的实部;double imag;				// 复数的虚部;public:CComplex(double pr = 0.0, double pi = 0.0) {real = pr;imag = pi;};virtual ~CComplex();// 重载插入运算符; friend ostream& operator<<(ostream&, const CComplex&);
      };
      
    • C C o m p l e x {\rm CComplex} CComplex类实现文件 ( C C o m p l e x . c p p ) ({\rm CComplex.cpp}) (CComplex.cpp)

      /*** 作者:罗思维* 时间:2024/03/31* 描述:复数类实现文件。*/#include "CComplex.h"CComplex::~CComplex() {
      }// 重载插入运算符实现; 
      ostream& operator<<(ostream& os, const CComplex& c) {os << "(" << c.real << "," << c.imag << "i" << ")" << endl;return os;
      }
      
    • 程序主文件 ( m a i n . c p p ) ({\rm main.cpp}) (main.cpp)

      /*** 作者:罗思维* 时间:2024/03/31* 描述:程序主文件。*/
      #include "CComplex.h"int main() {CComplex a(1, 2);cout << a;return 0;
      }
      
  • 提取运算符重载的语法格式:

    istream& operator>>(istream& is,const T& t)
    {...;	// 函数体;return is;
    }
    
    • 第一个参数:为输入流 i s t r e a m {\rm istream} istream对象的引用,函数返回值必须是这个引用对象;
    • 第二个参数:为提取的对象, T {\rm T} T是用户自定义的类, t {\rm t} t为该类的对象名;
  • 提取运算符重载实例:复数类的输入 ( C o m p l e x 2 ) ({\rm Complex2}) (Complex2)

    • C C o m p l e x {\rm CComplex} CComplex类定义头文件 ( C C o m p l e x . h ) ({\rm CComplex.h}) (CComplex.h)

      /*** 作者:罗思维* 时间:2024/03/31* 描述:复数类定义头文件。*/
      #include <iostream>using namespace std;class CComplex {protected:double real;				// 复数的实部;double imag;				// 复数的虚部;public:CComplex(double pr = 0.0, double pi = 0.0) {real = pr;imag = pi;};virtual ~CComplex();// 重载插入运算符;friend ostream& operator<<(ostream&, const CComplex&);// 重载提取运算符;friend istream& operator>>(istream&, CComplex&);
      };
      
    • C C o m p l e x {\rm CComplex} CComplex类实现文件 ( C C o m p l e x . c p p ) ({\rm CComplex.cpp}) (CComplex.cpp)

      /*** 作者:罗思维* 时间:2024/03/31* 描述:复数类实现文件。*/#include "CComplex.h"CComplex::~CComplex() {
      }// 重载插入运算符实现;
      ostream& operator<<(ostream& os, const CComplex& c) {os << "(" << c.real << "," << c.imag << "i" << ")" << endl;return os;
      }// 重载提取运算符实现;
      istream& operator>>(istream& is, CComplex& c) {cout << "请输入一个复数:";is >> c.real >> c.imag;return is;
      }
      
    • 程序主文件 ( m a i n . c p p ) ({\rm main.cpp}) (main.cpp)

      /*** 作者:罗思维* 时间:2024/03/31* 描述:程序主文件。*/
      #include "CComplex.h"int main() {CComplex a;cin >> a;cout << a;return 0;
      }
      
12.4 文件操作
  • C {\rm C} C++中对文件的读/写是通过流来操作的,操作文件的流称为文件流;

  • 文件是一组由有限且相关的数据组成的有序集合,"有限"指文件中的数据有最大限度,"相关"指这些数据有关联性;

  • 文件通常存储在外部存储设备上,当程序需要使用文件时,才将其中的数据读入内存;

  • 文件可以分为:普通文件和设备文件;

    • 普通文件:指存储在外部设备上的文件;
    • 设备文件:指与计算机主机相关联的各种外部设备,如:显示器、打印机、鼠标、键盘等;
  • 按照文件存储时的编码方式分为:文本文件( A S C I I {\rm ASCII} ASCII码文件)和二进制文件。

    • 文本文件:此类文件在存储时,以 A S C I I {\rm ASCII} ASCII码作为内容来存储,每一个字符对应文件中的一个字节,这些字节按照顺序被存储在磁盘上;
    • 二进制文件:将其内容按照二进制编码的方式来存放的文件;
  • 文本文件和二进制文件存储举例:

    18

  • 在对文本文件进行 I / O {\rm I/O} I/O操作时,需要进行格式转换,二进制文件不需要进行转换;

  • 对文件进行 I / O {\rm I/O} I/O操作的步骤:

    • 打开文件:在读写文件前,需要定义一个文件流类的对象,并用该对象打开文件,得到文件的一个句柄;
    • 读写文件:打开文件后,文件对象中会有一个指向文件中当前位置的指针,该指针的初始位置取决于打开文件时开发者设置的参数,默认情况为 0 0 0;每次从文件读出数据或向文件写入信息后,文件指针自动向后移动相应的字节,对于文本文件,文件指针移动一个字节,对于二进制文件,由数据类型决定;读文件时,如果文件指针移到文件的末尾,则读出的内容是文件结束符;
    • 关闭文件:完成文件的所有操作,需要关闭文件;
  • 常用的文件流对象有: i f s t r e a m 、 o f s t r e a m 、 f s t r e a m {\rm ifstream、ofstream、fstream} ifstreamofstreamfstream

    • i f s t r e a m {\rm ifstream} ifstream:输入文件流对象;
    • o f s t r e a m {\rm ofstream} ofstream:输出文件流对象;
    • f s t r e a m {\rm fstream} fstream:输入/输出文件流对象;
  • 打开文件前,先根据需要进行的操作声明流对象:

    ifstream file_in;			// 建立输入文件流对象;
    ofstream file_out;			// 建立输出文件流对象;
    fstream file_io;			// 建立输入/输出文件流对象;
    
  • 打开文件的两种方式:一是通过文件流的构造函数,二是利用成员函数 o p e n ( ) {\rm open()} open()

    // 1.利用文件流对象构造函数打开文件;
    ofstream file_out("C:\\a_out.dat",ios::out|ios::binary);	// 以二进制方式打开输出文件;
    ifstream file_in("C:\\a_in.dat",ios::in|ios::binary);		// 以二进制方式打开输入文件;// 2.常用文件流对象构造函数:
    ifstream::ifstream(const char*,int=ios::in,int=filebuf::openprot);
    ofstream::ofstream(const char*,int=ios::out,int=filebuf::openprot);
    fstream::fstream(const char*,int,int=filebuf::openprot);// 3.文件流类的成员函数open()原型:
    void open(const char *,int);// 4.三个常用的文件流的默认成员函数原型:
    void ifstream::open(const char*,int=ios::in);
    void ofstream::open(const char*,int=ios::out);
    void fstream::open(const char*,int);// 4.1 参数说明:
    // 参数1:代表文件名的字符串,一般需要完整的路径名,若文件在与exe相同的目录,则可以使用相对路径;
    // 参数2:文件的打开方式;
    

    文件的打开方式:

    常用 常用 常用 作用 作用 作用
    i o s : : i n {\rm ios::in} ios::in 打开文件用于数据输入 , 即从文件中读数据 打开文件用于数据输入,即从文件中读数据 打开文件用于数据输入,即从文件中读数据
    i o s : : o u t {\rm ios::out} ios::out 打开文件用于数据输出 , 即向文件中写数据 打开文件用于数据输出,即向文件中写数据 打开文件用于数据输出,即向文件中写数据
    i o s : : a t e {\rm ios::ate} ios::ate 打开文件后将文件指针置在文件尾部 打开文件后将文件指针置在文件尾部 打开文件后将文件指针置在文件尾部
    i o s : : a p p {\rm ios::app} ios::app 打开文件用于追加数据 , 文件指针始终指向文件尾部 打开文件用于追加数据,文件指针始终指向文件尾部 打开文件用于追加数据,文件指针始终指向文件尾部
    i o s : : t r u n c {\rm ios::trunc} ios::trunc 当打开文件已存在时 , 则清除其内容 , 即擦除以前所有数据 , 使之成为空文件 当打开文件已存在时,则清除其内容,即擦除以前所有数据,使之成为空文件 当打开文件已存在时,则清除其内容,即擦除以前所有数据,使之成为空文件
    i o s : : n o c r e a t e {\rm ios::nocreate} ios::nocreate 如果打开文件不存在 , 则不建立任何文件 , 返回打开失败信息 如果打开文件不存在,则不建立任何文件,返回打开失败信息 如果打开文件不存在,则不建立任何文件,返回打开失败信息
    i o s : : n o r e p l a c e {\rm ios::noreplace} ios::noreplace 如果打开文件已存在 , 不进行覆盖 , 当文件存在时 , 返回错误信息 如果打开文件已存在,不进行覆盖,当文件存在时,返回错误信息 如果打开文件已存在,不进行覆盖,当文件存在时,返回错误信息
    i o s : : b i n a r y {\rm ios::binary} ios::binary 以二进制方式打开文件 , 在不指定的情况下默认以文本文件方式打开文件 以二进制方式打开文件,在不指定的情况下默认以文本文件方式打开文件 以二进制方式打开文件,在不指定的情况下默认以文本文件方式打开文件

    使用符号"|"将常量组合,控制打开文件的多种属性,如下:

    ios::in|ios::nocreate;		// 文件打开用于数据输入,若打开文件不存在,则返回打开失败信息;
    ios::out|ios::noreplace;	// 文件打开用于数据输出,若打开文件存在,则返回打开失败信息;
    ios::in|ios::out;			// 文件打开既用于数据输入,又用于数据输出;
    ios::app|ios::nocreate;		// 文件打开后指针在文件尾,用于追加数据,若打开文件不存在,返回打开失败信息;
    ios::in|ios::out|ios::binary;	// 文件以二进制方式打开,既用于数据输入,又用于输出输出;
    
  • 检查文件是否打开成功,使用 f a i l ( ) {\rm fail()} fail()成员函数判定,原型如下:

    bool fail();	// 打开失败,返回true;打开成功,返回false;
    
  • 文件操作实例:打开一个文件并向其中写入文本数据,如果文件不存在,则新建一个文件,如果文件存在,则以追加方式写入数据 ( e x a m p l e 12 _ 3. c p p ) ({\rm example12\_3.cpp}) (example12_3.cpp)

    /*** 作者:罗思维* 时间:2024/04/01* 描述:打开一个文件并向其中写入文本数据。*/
    #include <iostream>
    #include <fstream>using namespace std;int main() {ofstream file_out;file_out.open("./data.txt", ios::out | ios::app);if (file_out.fail()) {cerr << "file data.txt open fail!" << endl;return 1;}file_out.close();		// 关闭文件;return 0;
    }
    
  • 向文本文件输出数据的两种方法:一是使用插入操作符"<<",二是调用成员函数 ( p u t ) ({\rm put}) (put)

  • 文本文件数据输出实例 ( e x a m p l e 12 _ 4. c p p ) ({\rm example12\_4.cpp}) (example12_4.cpp)

    /*** 作者:罗思维* 时间:2024/04/01* 描述:文本文件的输出。 */
    #include <iostream>
    #include <fstream>using namespace std;int main() {ofstream file_out("./data2.txt");// 利用插入操作符进行数据输出; file_out << "A B C D E F G" << endl;file_out << "H I J K L M N" << endl;file_out << "O P Q R S T" << endl;file_out << "U V W X Y Z" << endl;// 利用put()成员函数进行数据输出。 for (int i = 65; i <= 90; i++) {file_out.put(i);			// 输出单个字母; file_out.put(32);			// 输出一个空格; switch (i) {case 71:file_out.put(10);	// 输出换行; break;case 78:file_out.put(10);break;case 84:file_out.put(10);break;case 90:file_out.put(10);break;default:break;}}file_out.close();return 0;
    }
    
  • 将文本文件中的数据读入内存的三种方法:一是利用提取操作符">>",二是调用成员函数 g e t ( ) {\rm get()} get(),三是调用成员函数 g e t l i n e ( ) {\rm getline()} getline()

    // 1.利用提取操作符">>",原型如下:
    istream& operator >>(C++标准类型 &);// 2.调用成员函数get();
    int get();					// 读取字符;
    istream& get(char& c);		// 读取一个字符并存储到c中;// 3.调用成员函数getline();
    istream& getline(char * buffer,int len,char="\n");// 参数说明:
    // getline()用于读入文本文件中的一块文本;
    // 参数1:读入数据转存到的字符串,即将读入的字符存储到buffer;
    // 参数2:读入字符块的长度;
    // 参数3:默认为换行,当遇到换行时,则停止本次读取;
    
  • 利用提取操作符读取文本数据 ( e x a m p l e 12 _ 5. c p p ) ({\rm example12\_5.cpp}) (example12_5.cpp)

    /*** 作者:罗思维* 时间:2024/04/01* 描述:利用提取操作符读取文本数据。 */
    #include <iostream>
    #include <fstream>using namespace std;int main() {ifstream file_in("./data3.txt", ios::in);			// 打开文件; if (file_in.fail()) {			// 判断文件打开是否成功; cerr << "File data3.txt open fail!" << endl;}char cRead;while (file_in >> cRead) {		// 读取单个字符; cout << cRead << " ";		// 输出单个字符; }file_in.close();				// 关闭文件; return 0;
    }
    
  • 利用 g e t ( ) {\rm get()} get()成员函数读取文本数据 ( e x a m p l e 12 _ 6. c p p ) ({\rm example12\_6.cpp}) (example12_6.cpp)

    /*** 作者:罗思维* 时间:2024/04/01* 描述:利用get()成员函数读取文本数据。 */
    #include <iostream>
    #include <fstream>using namespace std;int main() {ifstream file_in("./data3.txt", ios::in);			// 打开文件; if (file_in.fail()) {			// 判断文件是否成功打开; cerr << "File data3.txt open fail!" << endl;}char cRead;while (!file_in.eof()) {		// 判断文件内容是否结束,读取单个字符并输出到屏幕上; cRead = file_in.get();cout << cRead;}file_in.close();				// 关闭文件; return 0;
    }
    
  • 利用提取操作符读取数据时,忽略空格、换行符,利用 g e t ( ) {\rm get()} get()成员函数读取数据时,会将空格、换行符全部读出;

  • 利用 g e t ( c h a r & c ) {\rm get(char\&\ c)} get(char& c)成员函数读取文本数据 ( e x a m p l e 12 _ 7. c p p ) ({\rm example12\_7.cpp}) (example12_7.cpp)

    /*** 作者:罗思维* 时间:2024/04/01* 描述:利用get(char& c)成员函数读取文本数据。 */
    #include <iostream>
    #include <fstream>using namespace std;int main() {ifstream file_in("./data3.txt", ios::in);			// 打开文件; if (file_in.fail()) {								// 判断文件打开是否成功; cerr << "File data3.txt open fail!" << endl;}char c;while (!file_in.eof()) {		// 当没有读到文件尾部时,读取单个字符并输出到屏幕上; file_in.get(c);cout << c;}file_in.close();				// 关闭文件; return 0;
    }
    
  • 利用 g e t l i n e ( ) {\rm getline()} getline()成员函数读取文本数据 ( e x a m p l e 12 _ 8. c p p ) ({\rm example12\_8.cpp}) (example12_8.cpp)

    /*** 作者:罗思维* 时间:2024/04/01* 描述:利用getline()成员函数读取文本数据。*/
    #include <iostream>
    #include <fstream>
    #include <string.h>using namespace std;int main() {ifstream file_in("./data3.txt", ios::in);		// 打开文件;if (file_in.fail()) {			// 判断文件打开是否成功;cerr << "File data3.txt open fail!" << endl;}char* buf = new char[128];memset(buf, 0, 128);			// 清空buf内容;while (!file_in.eof()) {file_in.getline(buf, 128);	// 逐行读取数据到buf中;cout << buf << endl;memset(buf, 0x00, 128);		// 清空buf内容;}delete[] buf;					// 释放动态内存;file_in.close();				// 关闭文件;return 0;
    }
    
  • 向二进制文件写入数据是利用流类 o s t r e a m {\rm ostream} ostream w r i t e ( ) {\rm write()} write()函数实现,原型如下:

    ostream& write(const char * buffer,int len);// 参数说明:
    // 参数1:buffer用于存储需要写入文件的内容;
    // 参数2:len是设定写入数据的长度;
    
  • 向二进制文件写入数据实例 ( e x a m p l e 12 _ 9. c p p ) ({\rm example12\_9.cpp}) (example12_9.cpp)

    /*** 作者:罗思维* 时间:2024/04/02* 描述:向二进制写入数据。* 数据:1 2 3 4 5 6 7 8 9*  	A B C D E F G*/
    #include <iostream>
    #include <fstream>using namespace std;int main() {// 打开二进制文件; ofstream file_out("./data.dat", ios::out | ios::binary | ios::trunc);// 如果文件打开失败,则显示错误信息; if (!file_out) {cerr << "File data.dat open fail!" << endl;exit(1);}// 写入1,2,3,4,5,6,7,8,9; for (int i = 49; i <= 57; i++) {file_out.write((char*)&i, sizeof(int));}// 写入A,B,C,D,E,F,G for (int i = 65; i <= 70; i++) {file_out.write((char*)&i, sizeof(int));}file_out.close();return 0;
    }
    
  • 将二进制文件作为输入文件,则读取其数据时使用流类 i s t r e a m {\rm istream} istream的成员函数 r e a d ( ) {\rm read()} read(),函数原型为:

    istream& read(char * buffer,int len);// 参数说明:
    // 参数1:buffer用于存储需要读取的内容;
    // 参数2:len是设定读取数据的长度;
    
  • 读取二进制文件数据实例,每次只读一个数值 ( e x a m p l e 12 _ 10. c p p ) ({\rm example12\_10.cpp}) (example12_10.cpp)

    /*** 作者:罗思维* 时间:2024/04/02* 描述:从二进制读入数据。* 数据:1 2 3 4 5 6 7 8 9*  	 A B C D E F G*/
    #include <iostream>
    #include <fstream>using namespace std;int main() {ifstream file_in("./data.dat", ios::in | ios::binary);if (!file_in) {cerr << "File data.dat open fail!" << endl;exit(1);}int n;while (!file_in.eof()) {file_in.read((char*)&n, sizeof(n));cout << (char)n << " ";}file_in.close();return 0;
    }
    
  • 读取二进制文件数据实例,一次性从文件中读出多个字节 ( e x a m p l e 12 _ 11. c p p ) ({\rm example12\_11.cpp}) (example12_11.cpp)

    /*** 作者:罗思维* 时间:2024/04/02* 描述:从二进制读入数据。* 数据:1 2 3 4 5 6 7 8 9*  	 A B C D E F*/
    #include <iostream>
    #include <fstream>
    #include <string.h>using namespace std;// 定义函数,输出字符串; 
    void print(char* &str, int len) {for (int i = 0; i < len; i++) {cout << str[i];}
    }int main() {ifstream file_in("./data.dat", ios::in | ios::binary);if (!file_in) {cerr << "File data.dat open fail!" << endl;exit(1);}char* buf = new char[11];		// 开辟空间; memset(buf, 0x00, 11);			// 清空空间内容; while (!file_in.eof()) {file_in.read(buf, 10);		// 一次性读取10个字节; print(buf, 10);memset(buf, 0x00, 10);		// 清空空间内容; }delete[] buf;					// 释放内存; file_in.close();				// 关闭文件; return 0;
    }
    
  • 与文件相关联的指针:读取指针和写入指针。

    • 读取指针:指向文件当前要读取的数据的位置;
    • 写入指针:指向现在正要写入数据的位置;
  • 控制文件指针的两个函数:

    • 流类 i s t r e a m {\rm istream} istream的成员函数 s e e k g ( ) {\rm seekg()} seekg()用于把读文件指针移动到指定位置,函数原型:

      istream& seekg(long dis,seek_dir ref=ios::beg);
      
    • 流类 o s t r e a m {\rm ostream} ostream的成员函数 s e e k p ( ) {\rm seekp()} seekp()用于把写文件指针移动到指定位置,函数原型:

      ostream& seekp(long dis,seek_dir ref=ios::beg);
      
    • 参数 d i s {\rm dis} dis:文件指针需要移动的字节数,当其为正数时,表示向后移,向文件末尾,当其为负数时,表示向前移,向文件开头;

    • 参数 s e e k _ d i r {\rm seek\_dir} seek_dir i o s {\rm ios} ios根基类中定义的枚举类型;

      enum seek_dir {beg = 0,cur = 1,end =2};// ios::beg:文件的开始位置;
      // ios::cur:当前位置;
      // ios::end:结束位置;
      
  • 通过文件指针移动把二进制文件数据显示到屏幕上 ( e x a m p l e 12 _ 12. c p p ) ({\rm example12\_12.cpp}) (example12_12.cpp)

    /*** 作者:罗思维* 时间:2024/04/02* 描述:从二进制读入数据。* 数据:1 2 3 4 5 6 7 8 9*  	 A B C D E F*/
    #include <iostream>
    #include <fstream>using namespace std;int main() {// 打开二进制文件; ifstream file_in("./data.dat", ios::in | ios::binary);// 判断文件是否打开成功; if (!file_in) {cerr << "File data.dat open fail!" << endl;exit(1);}int n;// 移动指针,9x4个字节; file_in.seekg(9 * 4, ios::beg);while (!file_in.eof()) {file_in.read((char*)&n, sizeof(n));		// 读取二进制文件数据; cout << (char)n << " ";}file_in.close();							// 关闭文件; return 0;
    }
    
12.5 实战

项目需求 :编写一个学生信息管理系统,要求将学生数据保存在文件中,提供查询、修改、删除学生信息的功能。

代码实现 ( S t u M a n a g e I n f o S y s t e m ) {\rm (StuManageInfoSystem)} (StuManageInfoSystem)

  • S t u d e n t . h {\rm Student.h} Student.h

    /*** 作者:罗思维* 时间:2024/04/03* 描述:定义存储学生信息结构体。 */
    #pragma once
    #include <iostream>
    #include <iomanip>
    #include <fstream>
    #include <vector>using namespace std;#define NULL 0
    int const MAX_NUM = 20;
    #define LEN sizeof(struct student)// 定义一个学生考试信息的结构体;
    /* 	参数说明:* 	name:	姓名;*  sex:	性别;*  id:	准考证号;*  score:	分数;*  total:	总分数;
    */
    struct student {char name[MAX_NUM];char sex[MAX_NUM];long int id;int score[4];int total;struct student *next;
    };
    
  • I n f o r m a t i o n . h {\rm Information.h} Information.h

    /*** 作者:罗思维* 时间:2024/04/03* 描述:学生信息类定义头文件。 */
    #pragma once
    #include "Student.h"static int n = 0;
    class CInformation {private:student *p1, *p2, *p3, *head, st;public:CInformation();virtual ~CInformation();student* create();					// 建立链表函数; void output(student* head);			// 输出链表; int count(student* head);			// 函数count统计考生总数; student* insert(student* head);		// 指针函数insert添加考生信息; student* cancel(student* head, long int num);	// 指针函数cancel删除考生信息; student* find(student* head, long int num);		// 指针函数find查找考生信息; void sort(student* head);			// 考生总分从大到小排列输出; void average(student* head);		// 考生成绩平均分; void save(student* head);			// 保存信息函数; student* Read();					// 读取信息函数; 
    };
    
  • I n f o r m a t i o n . c p p {\rm Information.cpp} Information.cpp

    /*** 作者:罗思维* 时间:2024/04/03* 描述:学生信息各种接口函数实现。 */
    #include "Information.h"
    #include "Student.h"
    #include <string.h>CInformation::CInformation() {
    }CInformation::~CInformation() {
    }// 新建学生信息成员函数;
    student *CInformation::create(void) {char ch[MAX_NUM];n = 0;p1 = p2 = (student *) malloc(LEN);cout << "------<<请建立学生考试信息表>>------" << endl;cout << "姓名:";cin >> ch;head = NULL;while (strcmp(ch, "!") != 0) {p1 = (student *)malloc(LEN);strcpy(p1->name, ch);cout << "性别:";cin >> p1->sex;cout << "准考证号(8位):";cin >> p1->id;cout << "数学成绩:";cin >> p1->score[0];cout << "物理成绩:";cin >> p1->score[1];cout << "英语成绩:";cin >> p1->score[2];cout << "C语言成绩:";cin >> p1->score[3];p1->total = p1->score[0] + p1->score[1] + p1->score[2] + p1->score[3];if (n == 0) {head = p1;} else {p2->next = p1;}p2 = p1;n++;cout << "姓名:";cin >> ch;}p2->next = NULL;return (head);
    }// 输出学生信息成员函数;
    void CInformation::output(student *head) {if (head == NULL) {cout << "这是一个空表,请先输入考生成绩.\n";} else {cout << "-------------------------\n";cout << " *学生考试成绩信息表*\n";cout << "-------------------------\n";cout << "准考证号 姓名 性别 数学 物理 英语 C语言 平均分 总分\n";p1 = head;do {cout << setw(8) << p1->id<< setw(9) << p1->name<< setw(8) << p1->sex<< setw(8) << p1->score[0]<< setw(9) << p1->score[1]<< setw(9) << p1->score[2]<< setw(9) << p1->score[3]<< setw(9) << p1->total / 4.0<< setw(9) << p1->total << endl;cout << "-------------------------\n";p1 = p1->next;} while (p1 != NULL);}
    }// 获得存储的学生数成员函数;
    int CInformation::count(struct student *head) {if (head == NULL) {return (0);} else {return (1 + count(head->next));}
    }// 插入存储的学生信息成员函数;
    student  *CInformation::insert(student *head) {cout << "\t---------------<<请输入新增学生成绩信息>>---------------\n" << endl;p1 = (student *)malloc(LEN);cout << "准考证号(8位):";cin >> p1->id;cout << "姓名:";cin >> p1->name;cout << "性别:";cin >> p1->sex;cout << "数学成绩:";cin >> p1->score[0];cout << "物理成绩:";cin >> p1->score[1];cout << "英语成绩:";cin >> p1->score[2];cout << "C语言成绩:";cin >> p1->score[3];p1->total = p1->score[0] + p1->score[1] + p1->score[2] + p1->score[3];p2 = head;if (head == NULL) {head = p1;p1->next = NULL;} else {while ((p1->id > p2->id) && (p2->next != NULL)) {p3 = p2;p2 = p2->next;}if (p1->id <= p2->id) {if (head == p2) {p1->next = head;head = p1;} else {p3->next = p1;p1->next = p2;}} else {p2->next = p1;p1->next = NULL;}}n++;cout << "\t---------------<<你输入的学生信息已经成功插入>>---------------\n" << endl;return head;
    }// 删除某学生信息成员函数;
    student *CInformation::cancel(student *head, long int num) {if (head == NULL) {return (head);} else {p1 = head;while (num != p1->id && p1->next != NULL) {p2 = p1;p1 = p1->next;}if (num == p1->id) {if (p1 == head) {head = p1->next;} else {p2->next = p1->next;}cout << "删除准考证号为" << num << "的学生\n";n--;}return (head);}
    }// 查找某学生信息成员函数;
    student *CInformation::find(student *head, long int num) {if (head == NULL) {cout << "这是一个空表,请先输入考生成绩.\n";return (head);} else {p1 = head;while (num != p1->id && p1->next != NULL) {p1 = p1->next;}if (num == p1->id) {cout << setw(8) << p1->id<< setw(9) << p1->name<< setw(8) << p1->sex<< setw(8) << p1->score[0]<< setw(9) << p1->score[1]<< setw(9) << p1->score[2]<< setw(9) << p1->score[3]<< setw(9) << p1->total / 4.0<< setw(9) << p1->total << endl;cout << "-------------------------\n";} else {cout << "没找到准考证号为" << num << "的学生.\n";}return (head);}
    }// 信息排序成员函数;
    void CInformation::sort(student *head) {int i, k, m = 0, j;student *p[MAX_NUM];if (head != NULL) {m = count(head);cout << "-------------------------\n";cout << "*学生考试成绩统计表*\n";cout << "-------------------------\n";cout << "准考证号 姓名 性别 数学 物理 英语 C语言 平均分 总分 名次\n";cout << "-------------------------\n";p1 = head;for (k = 0; k < m; k++) {p[k] = p1;p1 = p1->next;}for (k = 0; k < m - 1; k++) {for (j = k + 1; j < m; j++) {if (p[k]->total < p[j]->total) {p2 = p[k];p[k] = p[j];p[j] = p2;}}}for (i = 0; i < m; i++) {cout << setw(8) << p[i]->id<< setw(9) << p[i]->name<< setw(6) << p[i]->sex<< setw(7) << p[i]->score[0]<< setw(7) << p[i]->score[1]<< setw(7) << p[i]->score[2]<< setw(7) << p[i]->score[3]<< setw(8) << p[i]->total / 4.0<< setw(7) << p[i]->total<< setw(9) << i + 1 << endl;cout << "-------------------------\n";}}
    }// 计算学生各科平均成绩成员函数;
    void CInformation::average(student *head) {int k, m;float arg1 = 0, arg2 = 0, arg3 = 0, arg4 = 0;if (head == NULL) {cout << "这是一个空表,请先输入考生成绩.\n";} else {m = count(head);p1 = head;for (k = 0; k < m; k++) {arg1 += p1->score[0];arg2 += p1->score[1];arg3 += p1->score[2];arg4 += p1->score[3];p1 = p1->next;}arg1 /= m;arg2 /= m;arg3 /= m;arg4 /= m;cout << "*全班单科成绩平均分*\n";cout << "-------------------------\n";cout << "数学平均分:" << setw(7) << arg1<< "物理平均分:" << setw(7) << arg2<< "英语平均分:" << setw(7) << arg3<< "C语言平均分:" << setw(7) << arg4 << endl;cout << "-------------------------\n";}
    }// 信息保存成员函数;
    void CInformation::save(student *head) {ofstream out("data.txt", ios::out);out << count(head) << endl;while (head != NULL) {out << head->name << "\t"<< head->id << "\t" << "\t"<< head->sex << "\t"<< head->score[0] << "\t"<< head->score[1] << "\t"<< head->score[2] << "\t"<< head->score[3] << "\t"<< head->total << endl;head = head->next;}
    }// 学生信息读取成员函数;
    student *CInformation::Read() {int i = 0;p1 = p2 = (student *) malloc(LEN);head = NULL;ifstream in("data.txt", ios::out);in >> i;if (i == 0) {cout << "data.txt文件中的数据为空,请先输入数据." << endl;return 0;} else {cout << "-------------------------\n";for (; i > 0; i--) {p1 = (student *)malloc(LEN);in >> st.name >> st.id >> st.sex>> st.score[0] >> st.score[1]>> st.score[2] >> st.score[3]>> st.total;strcpy(p1->name, st.name);p1->id = st.id;strcpy(p1->sex, st.sex);p1->score[0] = st.score[0];p1->score[1] = st.score[1];p1->score[2] = st.score[2];p1->score[3] = st.score[3];p1->total = st.total;if (n == 0) {head = p1;} else {p2->next = p1;}p2 = p1;n++;cout << " " << p1->name << "\t"<< p1->id << "\t" << "\t"<< p1->sex << "\t"<< p1->score[0] << "\t"<< p1->score[1] << "\t"<< p1->score[2] << "\t"<< p1->score[3] << "\t"<< p1->total << endl;cout << "-------------------------\n";}cout << "数据已经成功读取完毕." << endl;p2->next = NULL;return (head);}
    }
    
  • m a i n . c p p {\rm main.cpp} main.cpp

    /*** 作者:罗思维* 时间:2024/04/03* 描述:程序主文件。 */
    #include "Student.h"
    #include "Information.h"vector<student> stu;int main() {CInformation person;student *head = NULL;int choice;long int i;do {cout << " 1.输入学生成绩" << endl;cout << " 2.显示学生成绩" << endl;cout << " 3.排序统计成绩" << endl;cout << " 4.查找学生成绩" << endl;cout << " 5.增加学生成绩" << endl;cout << " 6.删除学生成绩" << endl;cout << " 7.安全退出系统" << endl;cout << " 请输入您的选择(0-7):";cin >> choice;switch (choice) {case 0:head = person.Read();break;case 1:head = person.create();break;case 2:person.output(head);break;case 3:person.sort(head);person.average(head);cout << "参加考试的学生人数为:" << person.count(head) << "人\n";break;case 4:cout << "请输入要查找的准考证号(8位):";cin >> i;person.find(head, i);break;case 5:head = person.insert(head);person.output(head);break;case 6:cout << "请输入要删除的准考证号(8位):";cin >> i;head = person.cancel(head, i);person.output(head);break;case 7:person.save(head);break;default:cout << "输入有误,请重新输入.\n";break;}} while (choice != 7);
    }
    

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

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

相关文章

Vue.js---------Vue基础

能够说出Vue的概念和作用能够使用vue/cli脚手架工程化开发能够熟练Vue指令 一.vue基本概念 1.学习vue Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。 渐进…

间接调制和带通采样!!(非奈奎斯特采样定理)

1. 直接变频 前面讲解数字调制原理时&#xff0c;直接利用IQ调制将基带信号变换为频带信号&#xff0c;这种频率变换一般被称为直接上变频&#xff1b;解调时&#xff0c;直接利用IQ解调&#xff0c;将频带信号变换回基带信号&#xff0c;这种频率变换一般被称为直接下变频。直…

vue 使用自定义标签URL Protocol 调用本地exe 并传参

创建注册表文件reg&#xff0c;并运行 里面的路径需要替换成实际exe的绝对路径 Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\App] "URL:App Protocol Handler" "URL Protocol""" [HKEY_CLASSES_ROOT\App\DefaultIcon] &qu…

pycharm调试(步过(Step Over)、单步执行(Step Into)、步入(Step Into)、步出(Step Out))

pycharm调试 pycharm调试 pycharm调试为什么要学会调试&#xff1f;1. 步过 (Step Over)2. 单步执行 (Step Into)3. 步入&#xff08;Step Into&#xff09;4. 步出&#xff08;Step Out&#xff09; 为什么要学会调试&#xff1f; 调试可以帮助初学者更深入地理解编程基础&am…

【Android、 kotlin】kotlin学习笔记

基本语法 fun main(){val a2var b "Hello"println("$ (a - 1} $b Kotlin!")} Variables 只赋值一次用val read-only variables with val 赋值多次用var mutable variables with var Standard output printin() and print() functions String templ…

NKCTF2024 re VM?VM!WP

逻辑似乎很简单&#xff08;个鬼啊&#xff09; 这个函数是把输入的字符转化为二进制并倒序存储 sub_1570太大了加载不出来&#xff0c;应该是加密的主逻辑&#xff0c;目的是需要输出1 可以通过删除栈的方法强行转化伪代码 首先删掉这部分 9A0改小点 这个也是 栈这里U一下再…

DFS:深搜+回溯+剪枝解决组合问题

创作不易&#xff0c;感谢支持!!! 一、电话号码的组合 . - 力扣&#xff08;LeetCode&#xff09; class Solution { public:string hash[10]{"","","abc","def","ghi","jkl","mno","pqrs"…

爬虫部署平台crawlab使用说明

Crawlab 是一个基于 Go 语言的分布式网络爬虫管理平台&#xff0c;它支持 Python、Node.js、Jar、EXE 等多种类型的爬虫。 Crawlab 提供了一个可视化的界面&#xff0c;并且可以通过简单的配置来管理和监控爬虫程序。 以下是 Crawlab 的一些主要优点&#xff1a; 集中管理&am…

【C】leetcode力扣—— 141. 环形链表Ⅰ

目录 141. 环形链表 Ⅰ题目解题思路分析暴力求解&#xff1f;&#xff1f;快慢指针 代码 141. 环形链表 Ⅰ 题目链接: https://leetcode.cn/problems/linked-list-cycle/description/ 题目 题目 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某…

E-魔法猫咪(遇到过的题,做个笔记)

题解&#xff1a; 来自学长们思路&#xff1a; 其中一种正解是写单调队列。限制队列内的数单调递增&#xff0c;方法为每当新来的数据比当前队尾数据小时队 尾出列&#xff0c;直到能够插入当前值&#xff0c;这保证了队头永远是最小值。因此总体思路是队尾不断插入新值的同时 …

openlayers 入门教程(九):overlay 篇

还是大剑师兰特&#xff1a;曾是美国某知名大学计算机专业研究生&#xff0c;现为航空航海领域高级前端工程师&#xff1b;CSDN知名博主&#xff0c;GIS领域优质创作者&#xff0c;深耕openlayers、leaflet、mapbox、cesium&#xff0c;canvas&#xff0c;webgl&#xff0c;ech…

vue-cli打包 nodejs内存溢出 vue2.x Last few GCs

遇到这种情况百度各种博客&#xff0c;什么改package.json里的配置&#xff0c;什么安装increase-memory-limit &#xff0c;都尝试了并没什么用处&#xff0c;最后解决方案为执行下方名单&#xff0c;再次打包就成功了&#xff1a; export NODE_OPTIONS--max_old_space_size4…

单元测试 mockito(二)

1.返回指定值 2.void返回值指定插桩 3.插桩的两种方式 when(obj.someMethod()).thenXxx():其中obj可以是mock对象 doXxx().wien(obj).someMethod():其中obj可以是mock/spy对象 spy对象在没有插桩时是调用真实方法的,写在when中会导致先执行一次原方法,达不到mock的目的&#x…

好物视频素材在哪找?视频素材大全app下载

创作优质视频内容不仅仅是一种艺术&#xff0c;也是一种科学&#xff0c;需要对素材的深刻理解和精心挑选。掌握了这些高清无水印视频素材&#xff0c;您就拥有了创作引人入胜视频内容的强大工具。以下是更多精选的视频素材网站&#xff0c;旨在为您的视频项目提供更广阔的视野…

Python | Leetcode Python题解之第10题正则表达式匹配

题目&#xff1a; 题解&#xff1a; class Solution:def isMatch(self, s: str, p: str) -> bool:m, n len(s), len(p)dp [False] * (n1)# 初始化dp[0] Truefor j in range(1, n1):if p[j-1] *:dp[j] dp[j-2]# 状态更新for i in range(1, m1):dp2 [False] * (n1) …

专升本--python运算符总结

运算优先级 同一个等级是没有先后顺序的&#xff0c;此外&#xff0c;赋值语言的先后问题&#xff1a; 赋值的顺序从上往下&#xff0c;同一行一般都是代表同时进行赋值&#xff0c;如图所示&#xff1a; 一.and A and B&#xff0c;若A,B有任意一个为假&#xff08;0&#x…

希尔排序和快排里的小区间优化

希尔排序 希尔排序是插入排序的优化。 当一串数是逆序时&#xff0c;那么每插入一个数&#xff0c;前面的数都会向后面挪动。 那么这是插入排序的时间复杂度&#xff0c;就会达到O(n^2) 希尔排序是对数组里的数进行预排序。 防止插入排序出现最坏的情况。 预排序&#xf…

ABC318 F - Octopus

解题思路 对于每个宝藏维护个区间&#xff0c;答案一定在这些区间中对于每个区间的端点由小到大排序对于每个点进行判断&#xff0c;若当前位置合法&#xff0c;则该点一定为一个右端点则该点到前一个端点之间均为合法点若前一个点不合法&#xff0c;则一定是某一个区间限制的…

Xen Server 8 Install

Xen Sevrer 前言 XenServer&#xff08;以前称为 Citrix Hypervisor&#xff09;是业界领先的平台&#xff0c;实现了经济高效的桌面、服务器和云虚拟化基础结构。XenServer 支持任意规模或类型的组织整合计算资源&#xff0c;以及将计算资源转换为虚拟工作负载&#xff0c;从…

c++协程详解(二)

前言 这是c协程实现第二篇&#xff0c;这里开始我们将开始真正意义上开始实现协程。对协程基础流程不清楚的&#xff0c;可以看我的第一篇。 后续可能需要一定的模板知识&#xff0c;可以看下我的模板的文章&#xff0c;那些知识就完全够用了。本篇将实现一个协程封装的异步任…