做封面网站,响应式英文网站建设,网站信息发布,景德镇网站开发前言#xff1a; 在C编程语言中#xff0c;异常处理是一种重要的机制#xff0c;它允许程序员在运行时捕获和处理错误或异常情况。本文将详细介绍C异常处理的相关知识点#xff0c;包括异常的定义、抛出与捕获、异常处理的原则、以及在实际编程中的应用。 目录 1. 异常处理…前言 在C编程语言中异常处理是一种重要的机制它允许程序员在运行时捕获和处理错误或异常情况。本文将详细介绍C异常处理的相关知识点包括异常的定义、抛出与捕获、异常处理的原则、以及在实际编程中的应用。 目录 1. 异常处理的基本概念
1.1 异常的定义
1.2 异常的抛出
1.3 异常的捕获
2. 异常的使用
2.1 异常抛出和匹配的原则
2.2 在函数调用链中异常栈的展开匹配原则
3. 异常的重新抛出
4. 异常安全
5. 异常规格
6. C异常处理的实践应用
6.1 文件操作异常
6.2 数学运算异常
7. 总结 1. 异常处理的基本概念 在C中异常处理是一种机制用于处理运行时发生的错误或异常情况。异常可以是程序执行过程中遇到的任何问题如除以零、文件读写错误、资源未正确释放等。 1.1 异常的定义 在C中异常是一个对象通常由std::exception或其派生类创建。异常对象包含了错误信息和状态程序员可以使用这些信息来诊断和处理错误。 1.2 异常的抛出 异常的抛出使用throw关键字。程序员在代码中使用throw语句来抛出异常这可以是显式抛出一个异常对象也可以是抛出一个特定类型的异常如std::runtime_error。 throw std::runtime_error(发生了一个错误);
1.3 异常的捕获 异常的捕获使用try...catch块。try块包含可能抛出异常的代码而catch块用于捕获并处理这些异常。 try {// 可能抛出异常的代码
} catch (const std::exception e) {// 处理异常std::cerr 捕获到异常: e.what() std::endl;
} 一个try后面可以跟着多个catch因为一段代码可能出现多种异常 try
{// 保护的标识代码
}catch( ExceptionName e1 )
{// catch 块
}catch( ExceptionName e2 )
{// catch 块
}catch( ExceptionName eN )
{// catch 块
}
2. 异常的使用
2.1 异常抛出和匹配的原则
1. 异常是通过抛出对象来激活的该对象的类型决定了应该激活那个catch的处理代码
2. 如果有多个处理代码与对象类型匹配那么就激活离的最近的一个 3. 抛出异常对象时会生成一个临时对象的拷贝这个临时对象的拷贝会在被catch以后销毁 4. 异常的捕获所有原则 可以使用 catch(...) 来捕获所有类型的异常。这种捕获方式通常用于那些不关心异常具体类型只想处理所有异常的情况。 2.2 在函数调用链中异常栈的展开匹配原则 1. 首先检查throw本身是否在try块内部如果是再查找是否有匹配的catch如果有则直接调用 2. 如果所在函数栈没有匹配的catch则退出当前函数栈到调用该函数的栈中进行寻找 3. 如果找到main函数的栈中依然没有匹配的catch则会直接终止程序。为了防止终止程序的这种情况出现我们一般都会在main函数中加入一个catch(...)捕获任意类型的异常 4. 找到匹配的catch后 就会继续执行catch中的语句 #includeiostream
using namespace std;
double func2(int x, int y)
{if (x 0)throw 除0错误;elsereturn (double)x / (double)y;
}
void func1()
{int x, y;cin x y;cout func2(x, y) endl;
}
int main()
{try{func1();}catch (const int e){cout e endl;}catch (const char* e){cout e endl;}catch (...) {cout 未知异常 endl;}return 0;
} 3. 异常的重新抛出 在 catch 块中可以使用 throw不带参数;来重新抛出当前捕获的异常。这通常用于在处理完一些资源清理工作后将异常传递给更高层的调用者。
void func1()
{// 这里可以看到如果发生除0错误抛出异常另外下面的array没有得到释放。// 所以这里捕获异常后并不处理异常异常还是交给外面处理这里捕获了再// 重新抛出去。int* arr new int[10];try{int x, y;cin x y;cout func2(x, y) endl;}catch(...){delete arr;throw;}
}4. 异常安全 在构造函数和析构函数中应避免抛出异常因为这可能导致对象状态不一致或资源泄漏。应该使用 RAIIResource Acquisition Is Initialization原则来管理资源确保异常发生时资源能够自动释放。这个会在后面讲智能指针时讲到 5. 异常规格 可以在函数声明中使用异常规格来指定函数可能抛出的异常类型。这有助于调用者了解预期的异常并做出相应的处理。 下面是几种常见的异常规格 // 这里表示这个函数会抛出A/B/C/D中的某种类型的异常
void fun() throw(ABCD);
// 这里表示这个函数只会抛出bad_alloc的异常
void* operator new (std::size_t size) throw (std::bad_alloc);
// 这里表示这个函数不会抛出异常
void* operator delete (std::size_t size, void* ptr) throw();
// C11 中新增的noexcept表示不会抛异常
thread() noexcept;
thread (thread x) noexcept; 6. C异常处理的实践应用 6.1 文件操作异常 在进行文件操作时可以使用异常处理来捕获和处理可能发生的错误如文件不存在、权限问题等。 #include fstream
#include iostreamvoid readFile(const std::string filename) {std::ifstream file(filename);if (!file) {throw std::runtime_error(无法打开文件);}// 读取文件内容
}int main() {try {readFile(example.txt);} catch (const std::exception e) {std::cerr 错误: e.what() std::endl;}return 0;
} 6.2 数学运算异常 在进行数学运算时可以捕获除以零等异常情况。上面的例子中也是这种 #include iostream
#include stdexceptvoid safeDivide(double a, double b) {if (b 0) {throw std::runtime_error(除数不能为零);}std::cout 结果: a / b std::endl;
}int main() {try {safeDivide(10, 0);} catch (const std::exception e) {std::cerr 错误: e.what() std::endl;}return 0;
} 7. 总结 异常能够帮助我们快速找到错误并判断错误类型增强我们处理错误的能力但同时异常也会带来执行流跳跃给我们调试等带来一些难题但总的来说异常还是给我们工作带来极大的便利如何正确使用异常是我们玩转C的重要一步。 感谢各位大佬观看创作不易还请各位大佬点赞支持