网站如何做市场推广网页制作与网站开发从入门到精通
news/
2025/9/24 5:00:26/
文章来源:
网站如何做市场推广,网页制作与网站开发从入门到精通,广告推广平台代理,网络营销策略理论有哪些1. 写在前面
c在线编译工具#xff0c;可快速进行实验: https://www.bejson.com/runcode/cpp920/
这段时间打算重新把c捡起来#xff0c; 实习给我的一个体会就是算法工程师是去解决实际问题的#xff0c;所以呢#xff0c;不能被算法或者工程局限住#xff0c;应时刻提…1. 写在前面
c在线编译工具可快速进行实验: https://www.bejson.com/runcode/cpp920/
这段时间打算重新把c捡起来 实习给我的一个体会就是算法工程师是去解决实际问题的所以呢不能被算法或者工程局限住应时刻提高解决问题的能力在这个过程中我发现cpp很重要 正好这段时间也在接触些c开发相关的任务所有想借这个机会把c重新学习一遍。 在推荐领域 目前我接触到的算法模型方面主要是基于Python 而线上的服务全是c(算法侧 业务那边基本上用go)我们所谓的模型也一般是训练好部署上线然后提供接口而已。所以现在也终于知道为啥只单纯熟悉Python不太行了 cpp才是yyds。
和python一样 这个系列是重温依然不会整理太基础性的东西更像是查缺补漏 不过c对我来说 已经5年没有用过了 这个缺很大 也差不多相当重学了 所以接下来的时间 重温一遍啦
资料参考主要是C语言中文网和光城哥写的C教程然后再加自己的理解和编程实验作为辅助加深印象。 关于更多的细节还是建议看这两个教程。
今天这篇文章比较简单 主要是整理C的异常处理所谓异常就是程序运行时可能会发生一些错误比如除数为0 数组下标越界等 如果不事先处理可能导致程序崩溃无法运行 在写程序中其实这些异常情况也需要尽可能的想到然后用C的异常处理机制捕获处理这些错误。 C的异常处理机制主要包括try, catch, throw三个关键字 下面就来看看啦。
主要内容
C异常处理初识C异常类型以及多级catch匹配Cthrow关键字C的exception类: C标准异常的基类
Ok, let’s go!
2. C异常处理初识
程序错误大致上分为三种类型语法错误逻辑错误和运行时错误:
语法错误: 编译和链接阶段可以发现只有100%符合语法规则的代码才能生成可执行程序。语法错误是最容易发现最容易排除的错误逻辑错误: 编写代码思路有问题无法达到预期目标 可通过调试解决运行错误: 运行期间的错误比如除数为0内存分配失败数组越界文件不存在等C异常机制就是解决这哥们而引入的
运行时如果放任不管系统就会执行默认操作终止运行。 C的异常机制能捕获运行时错误给程序一次起死回生的机会
从一个例子开始
int main(){string str http://c.biancheng.net;char ch1 str[100]; //下标越界ch1为垃圾值coutch1endl;char ch2 str.at(100); //下标越界抛出异常coutch2endl;return 0;
}运行代码在控制台输出 ch1 的值后程序崩溃(我实验发现也不崩溃呀可能编译器不同)。 但至少ch1那里确实存在了越界。 at() 是 string 类的一个成员函数它会根据下标来返回字符串的一个字符。与[ ]不同at() 会检查下标是否越界如果越界就抛出一个异常而[ ]不做检查不管下标是多少都会照常访问。 ch1那里不会检查下标越界虽然逻辑错误但程序会正常运行。 而ch2那里 由于at函数会检查越界问题所以会抛出异常来 如果我们不处理这个异常程序就终止了。 这样的好处就是我们能立刻认识到我们的一些错误。
那么如何捕获异常避免程序崩溃呢 语法如下:
try{// 可能抛出异常的语句char ch2 str.at(100)
}catch(exceptionType variable){// 处理异常的语句cout 下标越界啦 endl;return;
}try 中包含可能会抛出异常的语句一旦有异常抛出就会被后面的 catch 捕获。从 try 的意思可以看出它只是“检测”语句块有没有异常如果没有发生异常它就“检测”不到。catch 是“抓住”的意思用来捕获并处理 try 检测到的异常如果 try 语句块没有检测到异常没有异常抛出那么就不会执行 catch 中的语句。
修改代码:
int main(){string str http://c.biancheng.net;try{char ch1 str[100];coutch1endl;}catch(exception e){cout[1]out of bound!endl;}try{char ch2 str.at(100);coutch2endl;}catch(exception e){ //exception类位于exception头文件中cout[2]out of bound!endl;}
}此时只会输出[2]这个数组越界 第一个try依然没有捕获到异常这是因为 []不会检查下标越界不会抛出异常即使有错误try也检测不到。所以发生异常的时候必须明确将其抛出try才能检测到如果不抛出即使异常try检测不到。所谓抛出异常就是告诉程序发生了什么错误。
第二个try检测到了异常交给catch处理但注意一旦异常抛出try检测到就不会在执行异常点后面的语句了直接跳到catch里面执行。
所以先明确异常的处理流程: 抛出(Throw) -- 检测(Try) -- 捕获(Catch)
看一个终极例子
void func_inner(){throw Unknown Exception; //抛出异常cout[1]This statement will not be executed.endl;
}
void func_outer(){func_inner();cout[2]This statement will not be executed.endl;
}
int main(){try{func_outer();cout[3]This statement will not be executed.endl;}catch(const char* e){couteendl; // Unknown Exception}return 0;
}异常可以发生在当前的 try 块中也可以发生在 try 块所调用的某个函数中或者是所调用的函数又调用了另外的一个函数这个另外的函数中发生了异常。这些异常都可以被 try 检测到。
发生异常后程序的执行流会沿着函数的调用链往前回退直到遇见 try 才停止。在这个回退过程中调用链中剩下的代码所有函数中未被执行的代码都会被跳过没有执行的机会了。
3. C异常类型及多级catch匹配
3.1 异常类型
try-catch语法里面catch捕获异常的时候:
try{// 可能抛出异常的语句
}catch(exceptionType variable){// 处理异常的语句
}这里有个exceptionType是异常类型指明了当前的catch可以处理什么类型的异常; variable是一个变量用来接收异常信息。 当程序抛出异常的时候会创建一份数据这份数据包含了错误信息我们可以根据这些信息判断到底出了什么问题怎么处理。 异常既然是一份数据就应该有数据类型。 C规定异常类型可以是int,char,float, bool等基本类型也可以是指针数组字符串结构体类等聚合类型。C 语言本身以及标准库中的函数抛出的异常都是 exception 类或其子类的异常。也就是说抛出异常时会创建一个 exception 类或其子类的对象 exceptionType variable和函数的形参非常类似异常发生后会将异常数据传递给variable这个变量 和函数传参很类似。 只有跟exceptionType类型匹配的异常数据才会被传递给variable否则catch不会接收这份异常数据也不会执行catch块中的语句。
可以将catch看做一个没有返回值的函数当异常发生后catch会被调用并且会接收实参 但是catch和真正的函数调用又有区别:
真正的函数调用形参和实参的类型必须要匹配或者可以自动转换否则编译阶段就报错catch异常是在运行阶段产生可以是任何类型所以没法提前预测 不能在编译阶段判断类型是否正确只有等程序运行后真抛出异常了再将异常类型和catch能处理的类型进行匹配如果匹配成功就调用当前catch否则忽略当前catch。catch和真正的函数调用相比多了一个运行阶段实参和形参匹配的过程。
如果不希望catch处理异常数据也可以把variable省略
try{// 可能抛出异常的语句
}catch(exceptionType){// 处理异常的语句
}3.2 多级catch
一个try后面可以跟多个catch:
try{//可能抛出异常的语句
}catch (exception_type_1 e){//处理异常的语句
}catch (exception_type_2 e){//处理异常的语句
}
//其他的catch
catch (exception_type_n e){//处理异常的语句
}当异常发生时程序按照从上到下的顺序 将异常类型和catch所能接收的类型逐个匹配。一旦找到类型匹配的catch就停止检索并将异常交给当前的catch处理。如果最终也没有找到匹配的catch就终止程序运行。
class Base{ };
class Derived: public Base{ };
int main(){try{throw Derived(); //抛出自己的异常类型实际上是创建一个Derived类型的匿名对象coutThis statement will not be executed.endl;}catch(int){coutException type: intendl;}catch(char *){coutException type: cahr *endl;}catch(Base){ //匹配成功向上转型coutException type: Baseendl;}catch(Derived){coutException type: Derivedendl;}return 0;
}在catch中只给出了异常类型没有给出接收异常信息的变量。这个最终输出, Exception type:Base。 异常类型是Derived的 但catch在匹配类型时发生了向上转型让catch(Base)捕获了。
3.3 catch匹配过程中的类型转换
C/C存在很多种类型转换普通函数的话如果实参和形参的类型不是严格匹配会将实参的类型进行适当转换以适应形参类型主要包括:
算数转换: int-float, char-int, double-int向上转型: 派生类向基类转换数组或函数指针转换: 如果函数形参不是引用类型那么数组名会转为数组指针函数名也会转为函数指针用户自定义转换等
catch匹配异常过程中也会进行类型转换但仅能向上转型const转换数组或函数指针转换其他都不能用于catch。 like this:
int main(){int nums[] {1, 2, 3};try{throw nums;coutThis statement will not be executed.endl;}catch(const int *){coutException type: const int *endl;}return 0;
}nums本来是int[3] 但catch中没有严格匹配类型所以先转成int*, 再转成const int *。
4. C的throw关键字
C异常处理的流程: 抛出(Throw) - 检测(Try) - 捕获(Catch) , 异常必须显式的抛出才能被检测和捕获。
C中 使用throw关键字显式抛出异常用法:
throw exceptionData;下面通过一个动态数组的典型异常应用场景来深入了解下详细细节参考第一个链接文档:
// 自定义的异常类型
class OutOfRange{
public:OutOfRange(): m_flag(1){};OutOfRange(int len, int index): m_len(len), m_index(index), m_flag(2){}void what() const; // 获取具体的错误信息
private:int m_flag; // 不同flag表示不同的错误int m_index; // 当前数组的长度int m_len; // 当前使用的数组下标
};
void OutOfRange::what() const{if (m_flag 1){cout Error: empty array, no elements to pop. endl;}else if(m_flag 2){cout Error: out of range( array length m_len , access index m_index ) endl;}else{cout Unkonwn exception. endl;}
}// 实现动态数组
class Array{
public:Array();~Array(){free(m_p);}int operator[](int i) const; // 获取数组元素int push(int ele); // 在末尾插入数组元素int pop(); // 末尾删除数组元素int length() const{return m_len;} // 获取数组长度
private:int m_len; // 获取数组长度int m_capacity; // 当前内存能容纳多少个元素int *m_p; // 内存指针static const int m_stepSize 50; // 每次扩容步长
};Array::Array(){m_p (int*)malloc(sizeof(int) * m_stepSize);m_capacity m_stepSize;m_len 0;
}int Array::operator[](int index) const{if (index 0 || index m_len){throw OutOfRange(m_len, index); // index不合法抛出异常2 }return *(m_p index);
}int Array::push(int ele){if (m_len m_capacity){ // 如果容量不足就扩容m_capacity m_stepSize;m_p (int*)realloc(m_p, sizeof(int) * m_capacity); // 扩容}*(m_pm_len) ele;m_len;return m_len - 1;
}int Array::pop(){if (m_len 0){throw OutOfRange(); // 抛出异常}m_len--;return *(m_p m_len);
}// 打印数组元素
void printArray(Array arr){int len arr.length();if (len 0){cout Empty array! No elements to print. endl;return;}for (int i0; ilen; i){if (i len-1){cout arr[i] endl;}else{cout arr[i] , ;}}
}int main()
{Array nums;// 向数组中加十个元素for (int i0; i10; i){nums.push(i);}printArray(nums); // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9// 尝试访问第20个元素try{cout nums[20] endl;}catch(OutOfRange e){e.what(); // Error: out of range( array length 10, access index 20 )}// 尝试弹出20个元素try{for (int i0; i20; i){nums.pop();}}catch(OutOfRange e){e.what(); // Error: empty array, no elements to pop. }printArray(nums); // Empty array! No elements to print. return 0;
}另外 throw 关键字除了可以用在函数体中抛出异常还可以用在函数头和函数体之间指明当前函数能够抛出的异常类型这称为异常规范Exception specification
double func (char param) throw (int);这条语句声明了一个名为 func 的函数它的返回值类型为 double有一个 char 类型的参数并且只能抛出 int 类型的异常。如果抛出其他类型的异常try 将无法捕获只能终止程序。
但由于C11不再建议使用了所以这里就不整理了关于异常规范的具体细节参考第一篇链接。
5. C的exception类
C语言本身或标准库抛出的异常都是exception子类称为标准异常可以通过下面语句捕获:
try{// 可能抛出异常的句子
}catch(exception e){ // 引用是为了提高效率如果不使用引用就要经历一次对象拷贝// 处理异常的语句
}exception类位于头文件
class exception{
public:exception () throw(); //构造函数exception (const exception) throw(); //拷贝构造函数exception operator (const exception) throw(); //运算符重载virtual ~exception() throw(); //虚析构函数virtual const char* what() const throw(); //虚函数
}what() 函数返回一个能识别异常的字符串正如它的名字“what”一样可以粗略地告诉你这是什么异常。
关于具体的exception继承体系参考这里叭 等具体用到再进行补充这块。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/914903.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!