• C++编程常见错误及处理


    C++编程常见错误及处理

    在 C++ 程序错误一般分类:

    语法错误;运行错误;语义错误(也称逻辑错误)。本文介绍相关错误产生的原因及处理。

    语法错误(syntax errors

    是指程序中含有不符合语法规定的语句,在编译过程中显现,如:

    1. #include <iostream>
    2. using namespace std;
    3. main()
    4. {
    5. int a=5 //语句末尾必须有英文分号
    6. cout << "a=" << A <<endl; //忽略了大小写字母的区别
    7. return 0;
    8. }

    1)引号、逗号、分号,运算符是英文的,而不能是中文的,注意切换输入法。

    2)变量未定义就用,注意C++ 严格区分大小写,在写关键字、标识符要注意int为关键字,INT则为用户标识符,即可定义int INT;  int Int;

    3)变量赋值、运算时显示类型不匹配(如:int a=2;float b=2.001;当使a=b时)

    处理:编译阶段报错,根据报错的信息,我们修改代码,再次编译,直到没有语法错误为止。

    运行错误(runtime errors

    运行过程中,程序可能出现错误。这些错误属于运行错误,不会在编译过程中显现,如:

    打开不存在的文件、下标越界,栈溢出等。

    C++ 异常(Exception)机制就是为解决运行时错误而引入的。运行时错误如果放任不管,系统就会执行默认的操作,终止程序运行,也就是我们常说的程序崩溃(Crash)。C++ 提供了异常(Exception)机制,让我们能够捕获运行时错误,给程序一次“起死回生”的机会,或者至少告诉用户发生了什么再终止程序。

    一个发生运行时错误的程序:

    1. #include <iostream>
    2. #include <string>
    3. using namespace std;
    4. int main(){
    5. string str = "Hello, world!";
    6. char ch1 = str[100]; //下标越界,ch1为垃圾值
    7. cout<<"ch1="<<ch1<<endl;
    8. char ch2 = str.at(100); //下标越界,抛出异常
    9. cout<<"ch2="<<ch2<<endl;
    10. cout << "呵呵" << endl;
    11. return 0;
    12. }

    运行之效果如下:

    运行代码,在控制台输出 ch1 的值后程序崩溃。下面我们来分析一下原因。

    at() 是 string 类的一个成员函数,它会根据下标来返回字符串的一个字符。与[ ]不同,at() 会检查下标是否越界,如果越界就抛出一个异常;而[ ]不做检查,不管下标是多少都会照常访问。at() 函数检测到下标越界会抛出一个异常,这个异常可以由程序员处理,但是我们在代码中并没有处理,所以系统只能执行默认的操作,也即终止程序执行。

    我们可以借助 C++ 异常机制来捕获上面的异常,避免程序崩溃。捕获异常的语法为:

    try{

        // 可能抛出异常的语句

    }catch(exceptionType variable){

        // 处理异常的语句

    }

    try和catch都是 C++ 中的关键字,后跟语句块,不能省略{ }。try 中包含可能会抛出异常的语句,一旦有异常抛出就会被后面的 catch 捕获。从 try 的意思可以看出,它只是“检测”语句块有没有异常,如果没有发生异常,它就“检测”不到。catch 是“抓住”的意思,用来捕获并处理 try 检测到的异常;如果 try 语句块没有检测到异常(没有异常抛出),那么就不会执行 catch 中的语句。catch 关键字后面的exceptionType variable指明了当前 catch 可以处理的异常类型,以及具体的出错信息。

    修改上面的代码,加入捕获异常的语句:

    1. #include <iostream>
    2. #include <string>
    3. #include <exception>
    4. using namespace std;
    5. int main(){
    6. string str = "Hello, world!";
    7. try{
    8. char ch1 = str[100]; //下标越界
    9. cout<<"ch1="<<ch1<<endl;
    10. }catch(exception e){
    11. cout<<"[1]out of bound!"<<endl;
    12. }
    13. try{
    14. char ch2 = str.at(100); //下标越界
    15. cout<<"ch2="<<ch2<<endl;
    16. }catch(exception &e){ //exception类位于<exception>头文件中
    17. cout<<"[2]out of bound!"<<endl;
    18. }
    19. cout << "呵呵" << endl;
    20. return 0;
    21. }

     运行之效果如下:

    可以看出,第一个 try 没有捕获到异常,输出了一个没有意义的字符(垃圾值)。因为[ ]不会检查下标越界,不会抛出异常,所以即使有错误,try 也检测不到。换句话说,发生异常时必须将异常明确地抛出,try 才能检测到;如果不抛出来,即使有异常 try 也检测不到。所谓抛出异常,就是明确地告诉程序发生了什么错误。

    第二个 try 检测到了异常,并交给 catch 处理,执行 catch 中的语句。需要说明的是,异常一旦抛出,会立刻被 try 检测到,并且不会再执行异常点(异常发生位置)后面的语句。本例中抛出异常的位置是第at() 函数,它后面的 cout 语句就不会再被执行,所以看不到它的输出。执行完 catch 块所包含的代码后,程序会继续执行 catch 块后面的代码,就恢复了正常的执行流,输出了“呵呵”。

    C++ 异常处理(try catch)https://blog.csdn.net/qq_26460841/article/details/88352736

    C++ 高级教程之异常处理 https://bbs.huaweicloud.com/blogs/281241

    语义错误(semantic errors

    也称逻辑错误,编译没有报错,运行也没有抛出异常,但是输出的结果不正确,这种错误可以通过调试来解决。如:求一个数的阶乘,代码中的for语句中的i <= n误写为i < n 造成输出的结果不正确:

    1. #include <iostream>
    2. using namespace std;
    3. int main()
    4. {
    5. unsigned int n;
    6. unsigned long long factorial = 1;
    7. cout << "输入一个整数: ";
    8. cin >> n;
    9. for(int i = 1; i < n; ++i) //i < n 应改为 i <= n
    10. {
    11. factorial *= i;
    12. }
    13. cout << n << " 的阶乘为:"<< " = " << factorial;
    14. return 0;
    15. }

    运行之效果如下:

  • 相关阅读:
    SpringBoot-19-模块开发-员工修改/删除
    【Hack The Box】linux练习-- Previse
    大一作业HTML网页作业:简单的旅游 1页 (旅游主题)
    解密Prompt系列21. LLM Agent之再谈RAG的召回信息密度和质量
    flask 支付宝的使用
    计算机毕设(附源码)JAVA-SSM基于推荐算法的鞋服代购平台
    数模电路基础知识 —— 7. PN结与二极管的工作原理
    8年经验之谈:月薪3000到30000,测试工程师的变“行”记
    [SPOJ FASTFLOW] Fast Maximum Flow [最大流]
    上海亚商投顾:沪指震荡反弹 汽车产业链全天强势
  • 原文地址:https://blog.csdn.net/cnds123/article/details/125545628