笨蛋学C++【C++基础第八弹】

embedded/2024/9/24 21:15:43/

C++基础第八弹

    • 1.C++文件和流
      • 打开文件
      • 关闭文件
      • 写入文件
      • 读取文件
      • 读取 & 写入实例
      • 文件位置指针
    • 2.C++异常处理
      • 抛出异常
      • 捕获异常
        • 处理try抛出的任何类型的异常
      • C++标准的异常
      • 定义新的异常
    • 3.C++动态内存
      • new和delete运算符
        • new和delete & malloc和free
      • 数组的动态内存分配
        • 一维数组
        • 二维数组
        • 三维数组
      • 对象的动态内存分配
    • 4.C++命名空间
      • 定义命名空间
      • using指令
      • 不连续的命名空间
      • 嵌套的命名空间

1.C++文件和流

数据类型描述
ofstream该数据类型表示输出文件流,用于创建文件并向文件写入信息。
ifstream该数据类型表示输入文件流,用于从文件读取信息。
fstream该数据类型通常表示文件流,且同时具有 ofstream 和 ifstream 两种功能,这意味着它可以创建文件,向文件写入信息,从文件读取信息。

打开文件

  • ofstreamfstream 对象都可以用来打开文件进行写操作,如果只需要打开文件进行读操作,则使用 ifstream 对象。

  • 语法:第一个参数指定要打开的文件的名称或位置第二个参数定义文件被打开的模式

    void  open(const char * filename, ios::openmode mode);
    
    模式标志描述
    ios::app追加模式。所有写入都追加到文件末尾。
    ios::ate文件打开后定位到文件末尾。
    ios::in打开文件用于读取。
    ios::out打开文件用于写入。
    ios::trunc如果该文件已经存在,就先删除再创建

可以把以上两种或两种以上的模式结合使用。例如,如果想要以写入模式打开文件,并希望重新创建文件,以防文件已存在,那么可以使用下面的语法:

ofstream outfile;
outfile.open("file.dat", ios::out | ios::trunc );

类似地,您如果想要打开一个文件用于读写,可以使用下面的语法:

ifstream  afile;
afile.open("file.dat", ios::out | ios::in );

关闭文件

  • 当 C++ 程序终止时,它会自动关闭刷新所有流,释放所有分配的内存,并关闭所有打开的文件。

  • 下面是 close() 函数的标准语法,close() 函数是 fstream、ifstream 和 ofstream 对象的一个成员。

void close();

写入文件

  • 在 C++ 编程中,使用流插入运算符( << )向文件写入信息,就像使用该运算符输出信息到屏幕上一样。

  • 唯一不同的是,在这里使用的是 ofstreamfstream 对象,而不是 cout 对象。

读取文件

  • 在 C++ 编程中,使用流提取运算符( >> )从文件读取信息,就像使用该运算符从键盘输入信息一样。

  • 唯一不同的是,在这里使用的是 ifstreamfstream 对象,而不是 cin 对象。

读取 & 写入实例

  • 写入文件,需要刷新缓冲区 outfile.flush()
  • 检查文件是否被打开
//
// Created by 16690 on 2024/4/22.
//
#include <iostream>
#include <fstream>
using namespace std;int main(void) {char data[1024];ofstream outfile;ifstream infile;string filename = "D:\\c++\\test.txt";// 写模式打开文件,并检查文件是否成功打开// outfile.open(filename);//追加模式打开outfile.open(filename,ios::app);if (!outfile) {cerr << "Unable to open file for writing." << endl;return 1;}cout << "Writing to the file" << endl;cout << "Enter your name: ";cin.getline(data, 1024);// 向文件写入用户输入的数据,并刷新缓冲区outfile << data << endl;outfile.flush(); // 确保数据写入文件cout << "Enter your age: ";cin >> data;cin.ignore(); // 忽略之前输入的换行符// 再次向文件写入用户输入的数据outfile << data << endl;outfile.flush(); // 确保数据写入文件// 关闭写模式打开的文件outfile.close();// 以读模式打开文件,并检查文件是否成功打开infile.open(filename);if (!infile) {cerr << "Unable to open file for reading." << endl;return 1;}cout << "Reading from the file" << endl;infile.getline(data, sizeof(data)); // 读取字符串cout << "Name: " << data << endl;// 读取数据并打印infile >> data; // 读取数值cout << "Age: " << data << endl;// 关闭读模式打开的文件infile.close();return 0;
}

文件位置指针

  • istreamostream 都提供了用于重新定位文件位置指针的成员函数。这些成员函数包括关于 istream 的 seekg(“seek get”)和关于 ostream 的 seekp(“seek put”)。

  • seekg 和 seekp 的参数通常是一个长整型。

    • 第二个参数可以用于指定查找方向。
      • 查找方向可以是 ios::beg(默认的,从流的开头开始定位),
      • 查找方向可以是 ios::cur(从流的当前位置开始定位),
      • 查找方向可以是 ios::end(从流的末尾开始定位)。
  • 文件位置指针是一个整数值,指定了从文件的起始位置到指针所在位置的字节数

// 定位到 fileObject 的第 n 个字节(假设是 ios::beg)
fileObject.seekg( n );// 把文件的读指针从 fileObject 当前位置向后移 n 个字节
fileObject.seekg( n, ios::cur );// 把文件的读指针从 fileObject 末尾往回移 n 个字节
fileObject.seekg( n, ios::end );// 定位到 fileObject 的末尾
fileObject.seekg( 0, ios::end );

2.C++异常处理

异常是程序在执行期间产生的问题。C++ 异常是指在程序运行时发生的特殊情况,比如尝试除以零的操作。

异常提供了一种转移程序控制权的方式。C++ 异常处理涉及到三个关键字:try、catch、throw

  • throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。

  • catch: 在您想要处理问题的地方,通过异常处理程序捕获异常。catch 关键字用于捕获异常。

  • try: try 块中的代码标识将被激活的特定异常。它后面通常跟着一个或多个 catch

  • 语法:

    try
    {// 保护代码
    }catch( ExceptionName e1 )
    {// catch 块
    }catch( ExceptionName e2 )
    {// catch 块
    }catch( ExceptionName eN )
    {// catch 块
    }
    

抛出异常

可以使用throw语句在代码块中的任何地方抛出异常,throw语句的操作数可以是任意的表达式,表达式的结果的类型决定了抛出的异常的类型

double division(int a,int b){if(b == 0){cout << "Cannot divide by 0" << endl;throw "Division by zero condition!";}return (a/b);
}

捕获异常

try
{// 保护代码
}catch( ExceptionName e )
{// 处理 ExceptionName 异常的代码
}
处理try抛出的任何类型的异常
try
{// 保护代码
}catch(...)
{// 能处理任何异常的代码
}
//
// Created by 16690 on 2024/4/22.
//#include <iostream>
using namespace std;double division(int,int);int main(void){try{int result = division(10,0);cout << "result = " << result << endl;}catch (const char* msg){cerr << msg << endl;}try{int result = division(10,0);cout << "result = " << result << endl;}catch (...){cerr << "division函数报错" << endl;}return 0;
}double division(int a,int b){if(b == 0){cout << "Cannot divide by 0" << endl;throw "Division by zero condition!";}return (a/b);
}

C++标准的异常

Std : exception
std : bad_alloc
std : bad_cast
std : bad_typeid
std : bad_exception
std : logic_error
std : runtime_error
std : domain_error
std : invalid_argument
std : length_error
std : out_of_range
std : overflow_error
std : range_error
std : underflow_error
异常描述
std::exception该异常是所有标准 C++ 异常的父类。
std::bad_alloc该异常可以通过 new 抛出。
std::bad_cast该异常可以通过 dynamic_cast 抛出。
std::bad_typeid该异常可以通过 typeid 抛出。
std::bad_exception这在处理 C++ 程序中无法预期的异常时非常有用。
std::logic_error理论上可以通过读取代码来检测到的异常。
std::domain_error当使用了一个无效的数学域时,会抛出该异常。
std::invalid_argument当使用了无效的参数时,会抛出该异常。
std::length_error当创建了太长的 std::string 时,会抛出该异常。
std::out_of_range该异常可以通过方法抛出,例如 std::vector 和 std::bitset<>::operator
std::runtime_error理论上不可以通过读取代码来检测到的异常。
std::overflow_error当发生数学上溢时,会抛出该异常。
std::range_error当尝试存储超出范围的值时,会抛出该异常。
std::underflow_error当发生数学下溢时,会抛出该异常。

定义新的异常

  • 通过继承exception ,重写exception方法

  • 语法:

    const char * what () const throw ()
    {
    //函数体
    }
    
    1. const char * 表示返回值类型
    2. what 是函数名称
    3. () 是参数列表
    4. const 表示该成员函数不能修改成员变量
    5. throw() 是异常规格说明符。括号内写该函数可抛出的异常类型
  • const throw() 是异常规格说明,表示 what 函数可以抛出异常的类型,类型说明放到 () 里,这里面没有类型,就是声明这个函数不抛出异常,通常函数不写后面的 throw() 就表示函数可以抛出任何类型的异常

//
// Created by 16690 on 2024/4/22.
//
#include <iostream>using namespace std;struct MyException : public exception {//重写what方法const char *what() const throw() {return "C++ Exception";}
};int main(void) {try {throw MyException();} catch (MyException &e) {cout << "MyException caught" << endl;cout << e.what() << endl;} catch (exception &e) {cout << "Other exception" << endl;cout << e.what() << endl;}return 0;
}

3.C++动态内存

  • C++ 程序中的内存分为两个部分:

    • **栈:**在函数内部声明的所有变量都将占用栈内存。

    • **堆:**这是程序中未使用的内存,在程序运行时可用于动态分配内存。

  • 在 C++ 中,使用new运算符为给定类型的变量在运行时分配堆内的内存,这会返回所分配的空间地址

  • 如果不再需要动态分配的内存空间,可以使用 delete 运算符,删除之前由 new 运算符分配的内存

new和delete运算符

  • 语法

    new  数据类型;
    
    double* pvalue  = NULL; // 初始化为 null 的指针
    pvalue  = new double;   // 为变量请求内存
    
  • 若自由存储区已被用完,可能无法成功分配内存,所以检查new运算符是否返回NULL指针

    double* pvalue  = NULL;
    if( !(pvalue  = new double ))
    {cout << "Error: out of memory." <<endl;exit(1);}
    
  • malloc() 函数在 C 语言中就出现了,在 C++ 中仍然存在,但建议尽量不要使用 malloc() 函数。new 与 malloc() 函数相比,其主要的优点是,new 不只是分配了内存,它还创建了对象

    delete pvalue;        // 释放 pvalue 所指向的内存//基本数据类型,就直接使用delete pvalue,引用数据类型,就使用delete [] pvalue
    
    #include <iostream>
    using namespace std;int main ()
    {double* pvalue  = NULL; // 初始化为 null 的指针pvalue  = new double;   // 为变量请求内存*pvalue = 29494.99;     // 在分配的地址存储值cout << "Value of pvalue : " << *pvalue << endl;delete pvalue;         // 释放内存return 0;
    }
    
new和delete & malloc和free
  • new是在堆区新建一个对象,然后返回该对象的指针
  • malloc只是分配一块内存
  • delete是释放堆区的对象,然后调用该对象的析构函数
  • free是释放堆区的对象,不会调用析构函数

数组的动态内存分配

char* pvalue = NULL;
pvalue = new char[20];
delete[] pvalue;
一维数组
// 动态分配,数组长度为 m
int *array=new int [m];//释放内存
delete [] array;
二维数组
int **array;
// 假定数组第一维长度为 m, 第二维长度为 n
// 动态分配空间
array = new int *[m];
for( int i=0; i<m; i++ )
{array[i] = new int [n];
}
//释放
for( int i=0; i<m; i++ )
{delete [] array[i];
}
delete [] array;
#include <iostream>
using namespace std;int main()
{int **p;   int i,j;   //p[4][8] //开始分配4行8列的二维数据   p = new int *[4];for(i=0;i<4;i++){p[i]=new int [8];}//插入数据for(i=0; i<4; i++){for(j=0; j<8; j++){p[i][j] = j*i;}}   //打印数据   for(i=0; i<4; i++){for(j=0; j<8; j++)     {   if(j==0) cout<<endl;   cout<<p[i][j]<<"\t";   }}   //开始释放申请的堆   for(i=0; i<4; i++){delete [] p[i];   }delete [] p;   return 0;
}
三维数组
int ***array;
// 假定数组第一维为 m, 第二维为 n, 第三维为o
// 动态分配空间
array = new int **[m];
for( int i=0; i<m; i++ )
{array[i] = new int *[n];for( int j=0; j<n; j++ ){array[i][j] = new int [o];}
}
//释放
for( int i=0; i<m; i++ )
{for( int j=0; j<n; j++ ){delete[] array[i][j];}delete[] array[i];
}
delete[] array;
#include <iostream>
using namespace std;int main()
{   int i,j,k;   // p[2][3][4]int ***p;p = new int **[2]; for(i=0; i<2; i++) { p[i]=new int *[3]; for(j=0; j<3; j++) p[i][j]=new int[4]; }//输出 p[i][j][k] 三维数据for(i=0; i<2; i++)   {for(j=0; j<3; j++)   { for(k=0;k<4;k++){ p[i][j][k]=i+j+k;cout<<p[i][j][k]<<" ";}cout<<endl;}cout<<endl;}// 释放内存for(i=0; i<2; i++) {for(j=0; j<3; j++) {   delete [] p[i][j];   }   }       for(i=0; i<2; i++)   {       delete [] p[i];   }   delete [] p;  return 0;
}

对象的动态内存分配

#include <iostream>
using namespace std;class Box
{public:Box() { cout << "调用构造函数!" <<endl; }~Box() { cout << "调用析构函数!" <<endl; }
};int main( )
{//创建包含四个 Box 对象的数组Box* myBoxArray = new Box[4];delete [] myBoxArray; // 删除数组return 0;
}

4.C++命名空间

  • 为了区分各个组件库中的函数,然后通过命名空间来解决

定义命名空间

  • 命名空间的定义使用关键字 namespace,后跟命名空间的名称

  • 语法

    //创建语法
    namespace 命名空间名称{代码声明
    }//调用语法
    using namespace 命名空间名称::code;  // code 可以是变量或函数
    
    #include <iostream>
    using namespace std;// 第一个命名空间
    namespace first_space{void func(){cout << "Inside first_space" << endl;}
    }
    // 第二个命名空间
    namespace second_space{void func(){cout << "Inside second_space" << endl;}
    }
    int main ()
    {// 调用第一个命名空间中的函数first_space::func();// 调用第二个命名空间中的函数second_space::func(); return 0;
    }
    

using指令

  • 使用 using namespace 指令,这样在使用命名空间时就可以不用在前面加上命名空间的名称

  • using 指令引入的名称遵循正常的范围规则。名称从使用 using 指令开始是可见的,直到该范围结束。此时,在范围以外定义的同名实体是隐藏的。

    #include <iostream>
    using namespace std;// 第一个命名空间
    namespace first_space{void func(){cout << "Inside first_space" << endl;}
    }
    // 第二个命名空间
    namespace second_space{void func(){cout << "Inside second_space" << endl;}
    }
    using namespace first_space;
    int main ()
    {// 调用第一个命名空间中的函数func();return 0;
    }
    

不连续的命名空间

  • 命名空间可以定义在几个不同的部分中,因此命名空间是由几个单独定义的部分组成的。一个命名空间的各个组成部分可以分散在多个文件中。

  • 如果命名空间中的某个组成部分需要请求定义在另一个文件中的名称,则仍然需要声明该名称。

    //创建语法
    namespace 命名空间名称{代码声明
    }
    

嵌套的命名空间

  • 命名空间可以嵌套,可以在一个命名空间中定义另一个命名空间

    namespace 命名空间名称{代码声明namespace 命名空间名称{代码声明}
    }//调用语法
    using namespace第一个命名空间名称::第二个命名空间名称;  // code 可以是变量或函数
    
    #include <iostream>
    using namespace std;// 第一个命名空间
    namespace first_space{void func(){cout << "Inside first_space" << endl;}// 第二个命名空间namespace second_space{void func(){cout << "Inside second_space" << endl;}}
    }
    using namespace first_space::second_space;
    int main ()
    {// 调用第二个命名空间中的函数func();return 0;
    }
    


http://www.ppmy.cn/embedded/29740.html

相关文章

【webrtc】MessageHandler 4: 基于线程的消息处理:以Fake 收发包模拟为例

G:\CDN\rtcCli\m98\src\media\base\fake_network_interface.h// Fake NetworkInterface that sends/receives RTP/RTCP packets.虚假的网络接口,用于模拟发送包、接收包单纯仅是处理一个ST_RTP包 消息的id就是ST_RTP 类型,– 然后给到目的地:mediachannel处理: 最后消息消…

Java基础,每日两问(5.1.1)

Java三大特点&#xff1a; 跨平台性&#xff08;Platform Independence&#xff09;&#xff1a; Java通过“一次编写&#xff0c;到处运行”&#xff08;Write Once, Run Anywhere, WORA&#xff09;的理念实现了跨平台性。这主要归功于Java虚拟机&#xff08;JVM&#xff09;…

web安全---xss漏洞/beef-xss基本使用

what xss漏洞----跨站脚本攻击&#xff08;Cross Site Scripting&#xff09;&#xff0c;攻击者在网页中注入恶意脚本代码&#xff0c;使受害者在浏览器中运行该脚本&#xff0c;从而达到攻击目的。 分类 反射型---最常见&#xff0c;最广泛 用户将带有恶意代码的url打开&a…

hive表基本语法

hive表基本语法 青少年是一个美好而又是一去不可再得的时期 是将来一切光明和幸福的开端 目录 hive表基本语法 1.ROW FORMAT用法 2.LOCATION用法 3.EXTERNAL用法 &#xff08;外部表&#xff09; 4.STORED AS 用法&#xff1a;设置数据存储格式 5.TBLPROPERTIES 用法 6.P…

(十)Servlet教程——HttpServletRequest接口

1. 知识准备 HttpServletRequest对象 浏览器访问网页的时候通过HTTP协议访问服务器上的静态资源或者接口服务&#xff0c;Servlet可以充当接口服务。当Servlet接收到来自浏览器的请求后会生成HttpServletRequest和HttpServletResponse来处理该请求。 公共接口类HttpServletReq…

操作系统安全:安全审计,Windows系统日志详解,Windows事件ID汇总

「作者简介」&#xff1a;2022年北京冬奥会网络安全中国代表队&#xff0c;CSDN Top100&#xff0c;就职奇安信多年&#xff0c;以实战工作为基础对安全知识体系进行总结与归纳&#xff0c;著作适用于快速入门的 《网络安全自学教程》&#xff0c;内容涵盖系统安全、信息收集等…

Go语言的map并发读写如何保证安全?

文章目录 为什么map不是并发安全的&#xff1f;如何保证map的并发安全&#xff1f;1. 使用互斥锁&#xff08;Mutex&#xff09;示例代码&#xff1a;2. 使用并发安全的map实现示例代码&#xff1a; 总结 在Go语言中&#xff0c;map是一种内置的数据结构&#xff0c;用于存储键…

Web前端开发之CSS_2

关系选择器CSS盒子模型弹性盒子模型文档流浮动清除浮动定位 1. 关系选择器 1.1 后代选择器 E F{} 选择所有被 E 元素包含的 F 元素&#xff0c;中间用空格隔开 <ul> <li>后代列表1</li> <div> <ol> <li>后代列表2</li> </ol>…