zoukankan      html  css  js  c++  java
  • C++ Primer 5th 第5章 语句

    和大多数语言一样,C++提供了条件执行语句、重复执行相同代码的循环语句和由于中断当前控制流的跳转语句,表达式语句和声明语句等。

    语句有简单语句和复合语句之分。简单语句但多数以分号结束,最简单的语句就是空语句,空语句中就只含有一个单独的分号。

    复合语句是用花括号括起来的语句或声明,复合语句也叫块。复合语句不同于简单语句的是,复合语句具有作用域,即块作用域,块中引入的名字只能被当前块或者当前块的字块访问。复合语句是不用分号结尾的。

    可以在if、switch、while、for语句的控制结构内定义变量,这个变量只能在当前语句内访问,语句结束,变量就消亡了。

    if语句的语法形式是

      if (condition)

        statement

    对于if的condition,必须使用括号括起来,condition可以是一个表达式,也可以是一个初始化了的变量声明,并且不允许为空。

    switch语句的语法形式是

      switch(expression)

        {

          case value:

        }

    对于switch语句,首先对expression表达式求值,expression也可以是一个初始化了的变量声明。表达式的值转换成整形。然后与每个case标签比较。

    case标签的值必须是个常量表达式,且是整型类型的。

    如果没有任何一个case标签能匹配switch表达式的值,在switch语句有default表达式的情况下,将默认执行该default表达式,default表达式的位置无关紧要。

    while语句的语法形式是

      while (condition)

        statement

    condition是不允许为空的,可以是个表达式,也可以是一个初始化了的变量声明。

    while循环不同于for循环的一点是,while条件部分或者while循环体内定义的变量每次迭代后都会被销毁。

    范围for语句的语法形式是

      for (declaration : expression)

        statement

    expression必须是一个序列,比如花括号括起来的初始值列表{1,2,3,4,5},或者数组、vector、string等类型的对象,这些对象的特点是可以使用begin和end成员或者函数来获取其相应的迭代器。

    do while语句中while的条件部分使用的变量必须是循环前定义的。 

    break语句用于终止循环,break语句只能出现在迭代语句或者switch语句的内部,嵌套在循环语句的子语句也是可以的。

    continue语句用于停止当前迭代的执行,重新开始下一次的迭代,但是不能终止循环,continue语句只能出现在for、while、do while循环的内部,或者循环内部的子块。

    goto语句较难把控,不建议使用

    try语句块和异常处理:

    当程序的某部分检测到一个它无法处理的问题时,需要使用异常处理,异常分为两块,一块是异常的检测,一块是异常的处理。

     检测部分是发出某种信号,表明遇到故障。发出是由throw完成的,称作throw引发了异常。某种信号则是异常的类型。

    异常的处理是try和catch负责的。

    throw表达式引发一个异常,表达式包含关键字和一个表达式,表达式的类型就是异常的类型,用于发出某种信号。

    try语句块是一个关键字加上紧随的复合语句块,必须是复合语句块,不能是一个简单语句。

    try语句之后是一个或多个catch子句。catch子句包含一个关键字catch,一个括号括起来的对象声明,一个语句块。当选中某个catch子句处理完毕后,程序就跳到所有catch子句之后的地方继续执行。如果没有catch子句,程序一般会非正常退出。

    另外,try语句块具有块作用域,出了该块,不能在外部访问块内引入的变量。

    练习5.1:什么是空语句?什么时候会用到空语句?

    空语句就是只含有一个单独分号的语句。当语法上需要一条语句,逻辑上不需要时,就需要使用空语句

    练习5.2:什么是块?什么时候会用到块?

    块就是用花括号括起来的语句或者声明序列,当语法上需要一条语句,但是逻辑上需要多条语句,此时就要使用块。


    练习5.3:使用逗号运算符(参见4.10节,第104页)重写1.4.1节(第10页)的 while 循环,使它不再需要块,观察改写之后的代码的可读性提高了还是降低了。

    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        int i = 50, sum = 0;
        while (i <= 100)
            sum += i, ++i;
    
        return 0;
    }

    改写后的可读性降低。

    练习5.4:说明下列例子的含义,如果存在问题,试着修改它。

    (a) while (string::iterator iter != s.end())
    {
        /* . . . */
    }
    
    (b) while (bool status = find(word))
    {
        /* . . . */
    }
    if (!status)
    {
        /* . . . */
    }

    (a) 用循环遍历string s,语法错误,while头部只能是一个表达式或者初始化了的变量声明。应该将iter放在while外面定义。

    (b) while头部定义的变量只在当前循环内可见,if无法访问,应该将status的定义放在最外面。

    练习5.5:写一段自己的程序,使用if else 语句实现把数字成绩转换为字母成绩的要求。

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    int main()
    {
        const vector<string> scores = {"F", "D", "C", "B", "A", "A++"};
        string lettergrade;
        int grade;
        while (cin >> grade)
        {
            if (grade < 60)
                lettergrade = scores[0];
            else
                lettergrade = scores[(grade - 50) / 10];
            cout << lettergrade << '
    ';
        }
        return 0;
    }

    练习5.6:改写上一题的程序,使用条件运算符(参见4.7节,第134页)代替if else语句。

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    int main()
    {
        const vector<string> scores = {"F", "D", "C", "B", "A", "A++"};
        string lettergrade;
        int grade;
        while (cin >> grade)
        {
            (grade < 60) ? ( lettergrade = scores[0]) :    (lettergrade = scores[(grade - 50) / 10]);
            cout << lettergrade << '
    ';
        }
        return 0;
    }

    练习5.7:改写下列代码段中的错误。

    (a) if (ival1 != ival2)
           ival1 = ival2
        else
            ival1 = ival2 = 0;
    
    (b) if (ival < minval)
        minval = ival;
        occurs = 1;
    
    (c) if (int ival = get_value())
            cout << "ival = " << ival << endl;
        if (!ival)
            cout << "ival = 0
    ";
    
    (d) if (ival = 0)
            ival = get_value();

    (a) ival1 = ival2 后面缺少分号。

    (b) 应该用花括号括起来。

    (c) if (!ival) 应该改为else。

    (d) if (ival = 0) 应该改为 if (ival == 0)。


    练习5.8:什么是“悬垂else”?C++语言是如何处理else子句的?

    悬垂else就是一个if语句嵌套在另一个if语句内部,使得if分支多于else分支。C++规定else与离它最近的尚未匹配的if匹配。

    练习5.9:编写一段程序,使用一系列if语句统计从cin读入的文本中有多少元音字母。

    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        char c;
        size_t num = 0;
        while (cin >> c)
        {
            if (c == 'a')
                ++num;
            if (c == 'e')
                ++num;
            if (c == 'i')
                ++num;
            if (c == 'o')
                ++num;
            if (c == 'u')
                ++num;
        }
        cout << num << endl;
        return 0;
    }

    练习5.10:我们之前实现的统计元音字母的程序存在一个问题:如果元音字母以大写形式出现,不会被统计在内。编写一段程序,既统计元音字母的小写形式,也统计元音字母的大写形式,也就是说,新程序遇到'a'和'A'都应该递增 aCnt 的值,以此类推。

    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        char c;
        size_t num = 0;
        while (cin >> c)
        {
            if (c == 'a' || c == 'A')
                ++num;
            if (c == 'e' || c == 'E')
                ++num;
            if (c == 'i' || c == 'I')
                ++num;
            if (c == 'o' || c == 'O')
                ++num;
            if (c == 'u' || c == 'U')
                ++num;
        }
        cout << num << endl;
        return 0;
    }

    练习5.11:修改统计元音字母的程序,使其也能统计空格、制表符、和换行符的数量。

    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        size_t num;
        char ch;
        while (cin >> ch)
        {
            switch (ch)
            {
            case 'a':      case 'A':      case 'e':      case 'E':      case 'i':      case 'I':      case 'o':
            case 'O':      case 'u':      case 'U':      case ' ':      case '	':     case '
    ':
                ++num;
            }
        }
        return 0;
    }

    练习5.12:修改统计元音字母的程序,使其能统计含以下两个字符的字符序列的数量: ff、fl和fi。

    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        size_t num;
        string s;
        while (cin >> s)
        {
            if (s == "ff" || s == "fl" || s == "fi")
            {
                ++num;
            }
        }
        return 0;
    }

      

    练习5.13:下面显示的每个程序都含有一个常见的编码错误,指出错误在哪里,然后修改它们。

    (a) unsigned aCnt = 0, eCnt = 0, iouCnt = 0;
    char ch = next_text();
    switch (ch)
    {
        case 'a': aCnt++;
        case 'e': eCnt++;
        default: iouCnt++;
    }
    
    (b) unsigned index = some_value();
    switch (index) 
    {
    case 1:
        int ix = get_value();
        ivec[ ix ] = index;
        break;
    default:
        ix = ivec.size() - 1;
        ivec[ ix ] = index;
    }
    
    (c) unsigned evenCnt = 0, oddCnt = 0;
    int digit = get_num() % 10;
    switch (digit) 
    {
    case 1, 3, 5, 7, 9:
        oddcnt++;
        break;
    case 2, 4, 6, 8, 10:
        evencnt++;
        break;
    }
    
    (d) unsigned ival = 512, jval = 1024, kval = 4096;
    unsigned bufsize;
    unsigned swt = get_bufCnt();
    switch (swt) 
    {
    case ival:
        bufsize = ival * sizeof(int);
        break;
    case jval:
        bufsize = jval * sizeof(int);
        break;
    case kval:
        bufsize = kval * sizeof(int);
        break;
    }

    (a) 每个case缺少break语句。

    case 'a': aCnt++;
    break;
    case 'e': eCnt++;
    break;
    default: iouCnt++;
    break;

    (b) default标签中的ix 未定义。修改为

    int ix;
    unsigned index = some_value();
    switch (index)
    {
    case 1:
    ix = get_value();
    ivec[ ix ] = index;
    break;
    default:
    ix = ivec.size() - 1;
    ivec[ ix ] = index;
    }


    (c) case标签错误,变量名错误。修改为

    unsigned evenCnt = 0, oddCnt = 0;
    int digit = get_num() % 10;
    switch (digit)
    {
    case 1:case 3:case 5:case 7:case 9:
    oddcnt++;
    break;
    case 2:case 4:case 6:case 8:case 10:
    evencnt++;
    break;
    }


    (d) case 标签必须是整型常量表达式。修改为

    constexpr unsigned ival = 512, jval = 1024, kval = 4096;
    unsigned bufsize;
    unsigned swt = get_bufCnt();
    switch (swt)
    {
    case ival:
    bufsize = ival * sizeof(int);
    break;
    case jval:
    bufsize = jval * sizeof(int);
    break;
    case kval:
    bufsize = kval * sizeof(int);
    break;
    }


    练习5.14:编写一段程序,从标准输入中读取若干string对象并查找连续重复出现的单词。所谓连续重复出现的意思是:一个单词后面紧跟着这个单词本身。要求记录连续重复出现的最大次数以及对应的单词。如果这样的单词存在,输出重复出现的最大次数;如果不存在,输出一条信息说明任何单词都没有连续出现过。例如:如果输入是:

    how now now now brown cow cow
    那么输出应该表明单词now连续出现了3次。

    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        string s1, s2;
        if (cin >> s1)
        {
            int cnt = 1;
            while (cin >> s2)
            {
                if (s1 == s2)
                    ++cnt;
                else
                {  
                    cout << s1 << "occurs " << cnt << " times" << endl;
                    s1 = s2;
                    cnt = 1;
                }
            }
            cout << s1 << "occurs " << cnt << " times" << endl;
        }
    
        return 0;
    }

    练习5.15:说明下列循环的含义并改正其中的错误。

    (a) for (int ix = 0; ix != sz; ++ix) { /* ... */ }
    if (ix != sz)
    // . . .
    (b) int ix;
    for (ix != sz; ++ix) { /* ... */ }
    (c) for (int ix = 0; ix != sz; ++ix, ++sz) { /*...*/ }

    (a) if不可以访问for的局部变量ix,应该将ix放在for的前面定义

    (b) for的语法格式错误,应改为for( ; ix != sz; ++ix)

    (c) 死循环,ix != sz 恒成立,不应该使用 ++ix,++sz

    练习5.16:while 循环特别适用于那种条件不变、反复执行操作的情况,例如,当未达到文件末尾时不断读取下一个值。for 循环更像是在按步骤迭代,它的索引值在某个范围内依次变化。根据每种循环的习惯用法各自编写一段程序,然后分别用另一种循环改写。如果只能使用一种循环,你倾向于哪种?为什么?

    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        int i = 0, sum = 0;
        while (i <= 100)
        {
            sum += i;
            ++i;
        }
    
        for (int i = 0; i != 100; ++i)
        {
            sum += i;
        }
        return 0;
    }

    如果只能使用一种,我倾向于for循环,因为for循环头部提供更多的选项,可以更多的控制循环,相对while循环来说更强大易用。

    练习5.17:假设有两个包含整数的vector对象,编写一段程序,检验其中一个vector对象是否是另一个的前缀。为了实现这一目标,对于两个不等长的vector对象,只需挑出长度较短的那个,把它的所有元素和另一个vector对象比较即可。例如,如果两个vector对象的元素分别是0、1、1、2 和 0、1、1、2、3、5、8,则程序的返回结果为真。

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    int main()
    {
        vector<int> v1{0, 1, 1, 2}, v2{0, 1, 1, 2, 3, 5, 8};
        if (v1.size() < v2.size())
        {
            for (size_t i = 0; i != v1.size(); ++i)
            {
                if (v1[i] != v2[i])
                    cout << "not equal
    ";
            }
        }
        else
        {
            for (size_t i = 0; i != v2.size(); ++i)
            {
                if (v1[i] != v2[i])
                    cout << "not equal
    ";
            }
        }
        return 0;
    }

    练习5.18:说明下列循环的含义并改正其中的错误。

    (a) do
            int v1, v2;
            cout << "Please enter two numbers to sum:" ;
            if (cin >> v1 >> v2)
                cout << "Sum is: " << v1 + v2 << endl;
        while (cin);
    
    (b) do {
            // . . .
        } while (ival = get_response());
    (c) do {
            ival = get_response();
        } while (ival);

    (a) 语法错误,do后面,while前面的语句应该用花括号括起来

    (b) 语法错误,do while条件使用的表达式规定必须是在循环前定义!

    (c) 语法错误,do while条件使用的表达式规定必须是在循环前定义!


    练习5.19:编写一段程序,使用do while 循环重复地执行下述任务:首先提示用户输入两个string对象,然后挑出较短的那个并输出它。

    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        string s1, s2;
        char c;
        do
        {
            cout << "input two strings:";
            cin >> s1 >> s2;
            if (s1.size() > s2.size())
                cout << s1 << endl;
            else
                cout << s2 << '
    ' << "More ? Enter 'y' or 'n' " << endl;
            cin >> c;
        }
        while (c != 'n');
        return 0;
    }


    练习5.20:编写一段程序,从标准输入中读取string对象的序列直到连续出现两个相同的单词或者所有单词都读完为止。使用while循环一次读取一个单词,当一个单词连续出现两次时使用break语句终止循环。输出连续重复出现的单词,或者输出一个消息说明没有任何单词是连续重复出现的。

    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        string s1, s2;
        if (cin >> s1)
        {
            while (cin >> s2)
            {
                if (s1 == s2)
                {
                    cout << s2;
                    break;
                }
                else
                {
                    s1 = s2;
                }
            }
        }
    
        return 0;
    }

    练习5.21:修改5.5.1节练习题的程序,使其找到的重复单词必须以大写字母开头。

    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        string s1, s2;
        if (cin >> s1)
        {
            while (cin >> s2)
            {
                if (s1 == s2 && isupper(s2[0]))
                {
                    cout << s2 << endl;
                    break;
                }
                else
                {
                    s1 = s2;
                }
            }
        }
    
        return 0;
    }

    练习5.22本节的最后一个例子跳回到 begin,其实使用循环能更好的完成该任务,重写这段代码,注意不再使用goto语句。

    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        int sz = get_size();
        while (sz <= 0)
            sz = get_size();
        return 0;
    }

    练习5.23:编写一段程序,从标准输入读取两个整数,输出第一个数除以第二个数的结果。

    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        int i1, i2;
        cin >> i1 >> i2;
        if (i2 == 0)
            throw "ERROR! Division by zero!";
    
        cout << i1 / i2 << endl;
        return 0;
    }

    练习5.24:修改你的程序,使得当第二个数是0时抛出异常。先不要设定catch子句,运行程序并真的为除数输入0,看看会发生什么?

    程序终止。


    练习5.25:修改上一题的程序,使用try语句块去捕获异常。catch子句应该为用户输出一条提示信息,询问其是否输入新数并重新执行try语句块的内容。 

    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        int i1, i2;
        while (cin >> i1 >> i2)
        {    try
            {
                if (i2 == 0)
                    throw string("ERROR! Division by zero!");
            }
            catch (string s)
            {
                cout << s << endl;
                cout << "Try again? 'Y' or 'N'";
                char c;
                cin >> c;
                if (!cin || c == 'n')
                    break;
                else
                    continue;
            }
            cout << i1 / i2 << endl;
        }
        return 0;
    }
  • 相关阅读:
    URL
    VI,CI,UI
    ubuntu优化使用
    Django入门之自定义页面
    python3 连接SQLserver
    Python3 捕捉异常
    python3 异常处理
    Django入门
    较大型站立会议(交付前两天)--张永组-2014-04-15
    站立会议-2014-04-14
  • 原文地址:https://www.cnblogs.com/pluse/p/5106712.html
Copyright © 2011-2022 走看看