文章目录

  • 3.1 do-while循环
    • 例3.1:加法机
    • 练习3.1.1
    • 练习3.1.2
  • 3.2 随机数入门
    • 例3.2:猜数游戏
      • 优化
    • 练习3.2.1
      • 练习3.2.2
      • 练习3.2.3
      • 例3.2.4
  • 3.3 switch-case语句
    • 例3.3:打印数字
      • 练习 3.3.1
      • 练习3.3.2
      • 练习3.3.3
      • 练习3.3.4
  • 小结

3.1 do-while循环

事实上,单用while循环就可以写出很复杂的程序,但是也有一个很明显的缺点:无论结果如何都会先循环一次,这样就可以使用do-while来弥补这个缺点。
语法:
do
{
多个语句;
}
while (条件);

例3.1:加法机

// adding.cpp
//用户输入一系列数字,直到输入一个特殊码退出(可选择0)。程序反复提示输入,但运行程序时至少要提示一次。
# include <iostream>
using namespace std;int main()
{int sum = 0;int n = 0;do{cout << "输入一个数(0表示退出):";cin >> n;sum += n;}while (n > 0);cout << "总和是:" << sum <<endl;return 0;
}

当然,这个也可以用只用while 来写。

# include <iostream>
using namespace std;int main()
{int sum = 0, n = 0;while (true){cout << "输入一个数(0表示退出):";cin >> n;sum += n;if (n <= 0){break;}}
}

练习3.1.1

修改程序来接受浮点输入并打印浮点结果。常量要正确表示。

答案:

# include <iostream>
using namespace std;int main()
{int n = 0;float sum = 0;do{cout << "输入一个数(0表示退出):";cin >> n;sum += n;}while (n > 0);cout << "总和是:" << sum << endl;return 0;
}

练习3.1.2

修改例子使用while循环但不要用do或break关键字。要求程序行为和例3.1完全一样。

答案:

# include <iosream>
using namespace std;int main()
{int sum = 0, n = 1;while (n > 0){cout << "输入一个数(0表示退出):";cin >> n;sum += n;}cout << "总和是:" << sum << endl;return 0;
}

3.2 随机数入门

随机数是游戏和模拟经常用到的东西,听起来容易,但生成随机数并不是一件简单的事情。不妨想一想:从哪里获得这种数?用什么当“虚拟骰子”?

幸好,C++程序员可通过两个步骤生成随机数,这是我们的“虚拟骰子”。

  • 设置随机数种子。
  • 通过复杂的数学运算生成序列中的下一个数(细节不重要)。
    有一个问题:虽然序列几乎不可能预测,但它仍是确定性的,数字计算机中的一切都是确定性的。不设置随机数种子,程序每次运行都获得相同的随机数序列。所以,第二次生成的数就不是真正的随机数了。为防止这种情况的发生,必须设置种子,而且每次都要不同。这就回到了原来的问题:从哪里获得这样的一个数?解决方案很简单:系统时间。

从C++程序员的角度来看,获取随机数实际是一个分三步走的过程。
首先用include指令引入对C++库的两个部分的支持:

# include <cstdlib> // 支持srand和rand函数
# include <ctime> //支持ctime函数

包含cstdlib后,就获得了随机函数的声明。包含ctime是因为要用到事件函数。
下一步是设置种子。记住不管程序要获得随机数多少次,都只需设置该种子值一次:

srand (time (nullptr));

注意:从C++11 开始支持nullptr关键字,即 空指针(null pointer)。如编译器较老,可改为NULL或0。

设置号随机数种子后,就可调用rand函数来生成随机数了。再次提醒,种子值无需多次设置。

cout << rand () << endl; //打印一个随机数
cout << rand () << endl; // 打印另一个

以下程序模拟掷10次骰子,每次生成1到6的随机数。

# include <iostream>
# include <cstdlib> //支持随机函数
# include <ctime> // 支持ctime
using namespace std;int main ()
{srand (time(nullptr));for (int i = 0; i < 10; ++i){cout << (rand() % 6) + 1 << endl;}return 0;
}

例3.2:猜数游戏

玩法很简单。首先生成一个随机数,然后让用户猜,输入猜的数之后,程序必须要做出判断。

  • 如果猜的数大于目标数,报告这一事实,提示再猜。
  • 如果猜的数小于目标数,报告这一事实,提示再猜。
  • 猜的数正确,报告这一事实,退出循环。游戏结束。

除非猜对,程序就必须继续。

// guessing.cpp
# include <iostream>
# include <cstdlib> //支持rand和srand
# include <ctime> // 支持时间函数
using namespace std;int main()
{int n = 0;bool do_more = true;srand (time(nullptr)); //设置随机数种子int target = rand() % 50 + 1;    // 获取1-50的随机数do{cout << "1-50, 你猜是哪个:";cin >> n;if (n == 0){cout << "再见!";do_more = false;}elseif (n > target){cout << "太大" << endl;}elseif (n < target){cout << “太小” << endl;}else{cout << "你赢了!";cout << "答案是:" << n << endl;do_more = false;}}while (do_more);return 0;
}

注意:C++14规范在标准模版库中提供了新的、增强的随机函数。虽然还是需要设置种子值,但在范围、随机数生成引擎和概率分布方面更灵活。不过,对于这种最简单的应用程序,标准的、老式的随机函数功能已经足够。

优化

如果使用Microsoft Visual Studio,你可能会注意到调用srand会造成开发环境显示一条警告。因为将time_t类型(一个长整数)的数据赋给获取unsigned int 的函数后,可能造成数据丢失。
两个都是整数,正负号也不是问题,所以可安全忽略该警告。但许多老程序员不喜欢警告。解决方案是执行强制类型转换(cast)。最简单的事老式C风格的强制类型转换。

srand ((unsigned int) time (nullptr));

然而,目前的首选方案是使用新的强制类型转换操作符static_cast。语法有点复杂,也不好看,但成为首选是有原因的。

srand (static_cast <unsigned int> (time(nullptr)));

static_cast常规语法如下所示:
static_cast <类型>(表达式)
它获取指定表达式,并将其转换成指定类型。即使编译器已知如何转换(比如将有符号整型赋给无符号整型),不显示执行强制类型转换还是消除不了警告。

练习3.2.1

修改程序来使用while循环。可继续使用do_more变量,也可去掉该变量,使用break关键字在必要时退出。

答案:

# include <iostream>
# include <cstdlib>
# include <ctime>
using namespace std;int main()
{int n = 0;boo do_more = true;srand (time (nullptr));int target = rand() % 50 + 1;while (do_more){cout << "1-50,你猜哪个:";cin >> n;if (n == 0){cout << "再见!";do_more = false;}elseif (n > target){cout << "猜大了!" << endl;}elseif (n < target){cout << "猜小了!" << endl;}else{cout << "你赢了!";cout << "答案是:" << n << endl;do_more = false;}}return 0;
}

练习3.2.2

玩过几次游戏后,应该对最优的玩家策略有所体会。可以用伪代码总结该策略吗?

答案:

  • 找出最小值和最大值的平均数。
  • 猜这个值。
  • 根据结果提示,猜这个值与最小值或最大值的平均数。
  • 依次类推。

练习3.2.3

完成上一题,你应该能写一个程序来实现最优策略。你心里记住一个数,让程序去猜这个数,每次都询问是太大、太小还是刚刚好。然后程序根据你的回答来调整所猜的数,前提是你要诚实回答。
提示:为方便写程序,用一套记号系统来表示你的回答:1=太大,2=太小,3=答对了。应该在提示中告知用户:告诉我猜得怎么样(1=太大,2=太小,3=答对了)。

答案:

# include <iostream>
using namespace std;int main()
{cout << "在1到50间猜一个数,并且记住这个数" << endl;int lo = 1, hi = 50, cmd = 0;while (true){int guess = (lo + hi) / 2;cout << "我猜的数是:" << guess << "。" << endl;cout << "请告诉我,我猜的怎么样?" << endl;cout << "1表示太大了,2表示太小了,3表示猜对了。" << endl;cin >> cmd;while (cmd < 1 || cmd > 3){cout << "输入有误。请重新输入:";cin >> cmd;}if (cmd == 3){cout << "我猜对了!真高兴跟你一起玩。" << endl;break;}elseif (cmd == 1){hi = guess -1;}else{lo = guess + 1;}}return 0;
}

例3.2.4

这个练习更像是数学问题而不是编程问题,但仍然有趣。一个包含N个数的有序数列,最多猜几次就能猜到目标数?提示:用二分法,大难是最多猜log2(N+1)次,向上取整。

答案:

1 move is sufficient to guarantee success for range size 1.

2 moves are sufficient to guarantee success for range size 3.
(Because there’s one spot on either side of the mid point.)

3 moves are sufficient to guarantee success for range size 7.
(Because there are two areas of 3 on either side of mid point.)

4 moves are sufficient to guarantee success for range size 15.
(Because there are two areas of 7 on either side of mid point.)

Note that if you add 1 to the sizes 1, 3, 7, 15, etc., you get powers of 2:
2, 4, 8, 16… Therefore, the solution is to add 1 to the size of the range,
and take the log-base-2 of this number, always rounding up:

 Ceiling(log-base-2(N + 1))

In C++ code, we can write this as:

 #include <cmath>  // Brings in support for ceil and log.int answer = ceil(log(n + 1)/log(2))

3.3 switch-case语句

和do-while一样,switch-case并非严格需要。
switch-case之所以有用,是因为许多程序的许多小节只是测试一系列值。
例如,根据n等于多少(1,2,3)打印对应单词。

switch (n)
{case 1:cout << "one" << endl;break;case 2:cout << "two" << endl;break;case 3:cout << "three" << endl;
}

switch 语句常规语法如下所示:
switch(值)
{
语句(s)
}

某个case不写break语句会发生什么?答案是“直通”到下个case。少数情况才需要这样做,但一般都应该习惯性地添加break。
还要注意,加了标签的语句具有以下形式:
标签:语句

case和default属于特殊标签。由于加了标签的语句本身就是语句,所以一个语句可以有多个标签。例如:

case 'a':
case 'e':
case 'i':
case 'o':cout << "是元音字母。";break;

例3.3:打印数字

# include <iostream>
using namespace std;int main()
{int n = 0;cout << "输入20到99的数:";cin >> n;int tens_digits = n / 10;int units_digits = n % 10;switch (tens_digits){case 2: cout << "贰拾"; break;case 3: cout << "叁拾"; break;case 4: cout << "肆拾"; break;case 5: cout << "伍拾"; break;case 6: cout << "陆拾"; break;case 7: cout << "柒拾"; break;case 8: cout << "捌拾"; break;case 9: cout << "玖拾"; break;}switch (units_digits){case 1: cout << "壹"; break;case 2: cout << "貳"; break;case 3: cout << "叁"; break;case 4: cout << "肆"; break;case 5: cout << "伍"; break;case 6: cout << "陆"; break;case 7: cout << "柒"; break;case 8: cout << "捌"; break;case 9: cout << "玖"; break;}return 0;
}

练习 3.3.1

例3.3 的程序能重复执行就好了。(事实上,大多数程序都应如此,用户退出才退出。)所以,将程序放到do-while循环中,用户输入0就退出循环。

答案:

# include <iostream>
using namespace std;int main()
{int n = 0;while (true){cout << "输入20到99之间的数:";cin >> n;int tens_digits = n / 10;int units_digits = n % 10;switch (tens_digits){case 2: cout << "贰拾"; break;case 3: cout << "叁拾"; break;case 4: cout << "肆拾"; break;case 5: cout << "伍拾"; break;case 6: cout << "陆拾"; break;case 7: cout << "柒拾"; break;case 8: cout << "捌拾"; break;case 9: cout << "玖拾"; break;}switch (units_digits){case 1: cout << "壹" << endl; break;case 2: cout << "貳" << endl; break;case 3: cout << "叁" << endl; break;case 4: cout << "肆" << endl; break;case 5: cout << "伍" << endl; break;case 6: cout << "陆" << endl; break;case 7: cout << "柒" << endl; break;case 8: cout << "捌" << endl; break;case 9: cout << "玖" << endl; break;}cout << "继续吗?(1表示是,0表示否):";cin >> n;if (n != 1){break;}}return 0;
}

练习3.3.2

修改程序使之能处理0到9的数。这应该很容易,或许不用修改?

答案:

# include <iostream>
using namespace std;int main()
{int n = 0;cout << "请输入0到9或20到99之间的数:";cin >> n;int tens_digits = n / 10;int units_digits = n % 10;if (n >= 20){switch (tens_digits){case 2: cout << "贰拾"; break;case 3: cout << "叁拾"; break;case 4: cout << "肆拾"; break;case 5: cout << "伍拾"; break;case 6: cout << "陆拾"; break;case 7: cout << "柒拾"; break;case 8: cout << "捌拾"; break;case 9: cout << "玖拾"; break;}}switch (units_digits){case 1: cout << "壹" << endl; break;case 2: cout << "貳" << endl; break;case 3: cout << "叁" << endl; break;case 4: cout << "肆" << endl; break;case 5: cout << "伍" << endl; break;case 6: cout << "陆" << endl; break;case 7: cout << "柒" << endl; break;case 8: cout << "捌" << endl; break;case 9: cout << "玖" << endl; break;}return 0;
}

练习3.3.3

修改使之能处理11到19的数。提示:添加十位数为1时的case。

答案:

# include <iostream>
using namespace std;int main()
{int n = 0;cout << "请输入1到99之间的数:";cin >> n;int tens_digits = n / 10;int units_digits = n % 10;if (n >= 20){switch (tens_digits){case 2: cout << "贰拾"; break;case 3: cout << "叁拾"; break;case 4: cout << "肆拾"; break;case 5: cout << "伍拾"; break;case 6: cout << "陆拾"; break;case 7: cout << "柒拾"; break;case 8: cout << "捌拾"; break;case 9: cout << "玖拾"; break;}}if (n > 10 && n < 20){switch (units_digits){case 1: cout << "拾壹" << endl; break;case 2: cout << "拾贰" << endl; break;case 3: cout << "拾叁" << endl; break;case 4: cout << "拾肆" << endl; break;case 5: cout << "拾伍" << endl; break;case 6: cout << "拾陆" << endl; break;case 7: cout << "拾柒" << endl; break;case 8: cout << "拾捌" << endl; break;case 9: cout << "拾玖" << endl; break;}}else{switch (units_digits){case 1: cout << "壹" << endl; break;case 2: cout << "貳" << endl; break;case 3: cout << "叁" << endl; break;case 4: cout << "肆" << endl; break;case 5: cout << "伍" << endl; break;case 6: cout << "陆" << endl; break;case 7: cout << "柒" << endl; break;case 8: cout << "捌" << endl; break;case 9: cout << "玖" << endl; break;}}return 0;
}

练习3.3.4

扩展程序使之能处理最大为999的数。提示:先完成练习3.3.3,否则随着值范围增大,会出现许多“漏洞”。

答案:

//
# include <iostream>
using namespace std;int main()
{int n = 0;cout << "输入一个数(1-999):";cin >> n;int hundreds_digits = n / 100;int remainder_from_100 = n % 100;int tens_digits = remainder_from_100 / 10;int units_digits = remainder_from_100 % 10;if (hundreds_digits > 0){switch (hundreds_digits){case 1: cout << "壹佰" ; break;case 2: cout << "貳佰" ; break;case 3: cout << "叁佰" ; break;case 4: cout << "肆佰" ; break;case 5: cout << "伍佰" ; break;case 6: cout << "陆佰" ; break;case 7: cout << "柒佰" ; break;case 8: cout << "捌佰" ; break;case 9: cout << "玖佰" ; break;}}if (remainder_from_100 > 0){cout << " , ";}if (remainder_from_100 >= 20){switch (tens_digits){case 2: cout << "贰拾"; break;case 3: cout << "叁拾"; break;case 4: cout << "肆拾"; break;case 5: cout << "伍拾"; break;case 6: cout << "陆拾"; break;case 7: cout << "柒拾"; break;case 8: cout << "捌拾"; break;case 9: cout << "玖拾"; break;}}if (remainder_from_100 > 10 && remainder_from_100 < 20){switch (units_digits){case 1: cout << "拾壹"; break;case 2: cout << "拾贰"; break;case 3: cout << "拾叁"; break;case 4: cout << "拾肆"; break;case 5: cout << "拾伍"; break;case 6: cout << "拾陆"; break;case 7: cout << "拾柒"; break;case 8: cout << "拾捌"; break;case 9: cout << "拾玖"; break;}}else{switch (units_digits){case 1: cout << "壹" << endl; break;case 2: cout << "貳" << endl; break;case 3: cout << "叁" << endl; break;case 4: cout << "肆" << endl; break;case 5: cout << "伍" << endl; break;case 6: cout << "陆" << endl; break;case 7: cout << "柒" << endl; break;case 8: cout << "捌" << endl; break;case 9: cout << "玖" << endl; break;}}cout << endl;return 0;
}

小结

  • do-while 循环和 while 循环相似,只是循环主体至少执行一次.
do 语句
while(条件);
  • 和其他控制结构一样,语句可替换为复合语句(用大括号封闭的代码块).
do
{多个语句
}while(条件);
  • 一般用bool变量控制循环。注意,该变量不需要和 true 比较,可以直接作为条件使用。
  • 这种 bool 变量可以使用逻辑NOT操作符(!)和false比较来反转其真假.
  • 生成随机数要包含 来使用srand和rand函数,还要包含 来使用时间函数。
#include <cstdlib>
#include <ctime>
  • 生成随机数的下一步是设置随机数种子,确保程序每次运行都获得一组不同的“随机”(实际是伪随机)数。
srand(time(nullptr));
  • 然后调用 rand 生成序列中的下个随机数。结果是无符号 int 范围中的任意数字。应用取余操作符(%)可获得从 0 到 n-1 的随机数。
cout << rand()%n;  //打印0到n-1的随机数
  • 使用 if 和 else if 子句反复测试单个值时,适合用 switch-case 语句替代。
if(n == 1){cout <<  "1";
}else if(n == 2){cout << "2";}else if(n*3){cout <<"3";}
  • 上述代码可替换成以下形式:
switch(n){case 1:cout  <<  "1";break;case 2:cout  << "2";break;case 3:cout  << "3";break;
  • switch-case的语法如下所示:
switch(值){
语句(s)
}
  • 这个块做下面这些事情:首先求值,执行和该值匹配的case.如果没有匹配项,就执行 default(如果有的话)语句。
  • 一旦执行语句,就按照正常流程一直执行到break语句,此时会跳出 switch-case 块
  • 加后赋值操作符(+=)是在变量上加一个值的简写形式。也有对应的减后赋值操作符。
n += 50; // n = n + 50
n -= 25; // n=n-25

第3章 判断语句进阶相关推荐

  1. 第 3 章 判断语句

    if 语句 if判断语句的基本语法 在python中,if语句就是用来进行判断的,格式如下: if 要判断的条件:条件成立时,要做的事情... 注意:代码的缩进为一个tab键,或者4个空格–不建议使用 ...

  2. Python入门第三章--第一节:条件判断语句

    从这一节开始,我们就进入到了进阶的阶段,这一章是在前一章的基础上进行提高扩展的,从本章开始,我会在每一节的结尾留下作业,大家可以将作业提交到我的邮箱或者直接将作业提交到QQ群的群文件中,我将在QQ群中 ...

  3. 《Visual C# 从入门到精通》第三章使用判断语句——读书笔记

    第3章 使用判断语句 3.1 使用布尔操作符 布尔操作符是求值为true或false的操作符. C#提供了几个非常有用的布尔操作符,其中最简单的是NOT(求反)操作符,它用感叹号(!)表示.!操作符求 ...

  4. WDL 流程语言编写及进阶(标准结构/线性输入输出/默认参数设置/判断语句)

    目录 简介 1.WDL 的标准结构 2.进阶版:线性输入 3.进阶版:默认参数输入如何设置 4.进阶版:判断功能 简介 WDL 定义了一个可执行的流程,它由call调用的一系列task组成,task ...

  5. switch语句判断范围_MQL5从入门到精通【第四章】(一)条件判断语句

    文档日期:2019年12月7日 # 判断语句 程序的基础功能之一就是做判断.判断语句通过评估条件的真伪作出决定.MQL5中有三个条件判断语句:if - else,三目操作符,和switch - cas ...

  6. 【Python语法系列】第三章:Python判断语句

    进行逻辑判断,是生活中常见的行为.同样,在程序中,进行逻辑判断也是最为基础的功能,一个逻辑判断的流程非常简单,我们有一个判断的条件,那么他无非给我们返回两个结果,是或者否,是的话有是的操作,否的话也有 ...

  7. 第4章 基础知识进阶 第4.1节 Python基础概念之迭代、可迭代对象、迭代器

    第四章 基础知识进阶 第十七节 迭代.可迭代对象.迭代器 一.    引言 本来计划讲完元组和字典后就讲列表解析和字典解析,但要理解列表解析和字典解析,就需要掌握Python的高级的类型迭代器,因此本 ...

  8. 小学生都能学会的Python基础语法——代码规范判断语句循环语句

    前言: Python 语言与 Perl,C 和 Java 等语言有许多相似之处.但是,也存在一些差异,在本章中我们将来学习 Python 的基础语法,让你快速学会 Python 编程. 一.代码的执行 ...

  9. 上升沿判断语句_FPGA入门系列6判断语句

    文章 简介 本系列文章主要针对FPGA初学者编写,包括FPGA的模块书写.基础语法.状态机.RAM.UART.SPI.VGA.以及功能验证等.将每一个知识点作为一个章节进行讲解,旨在更快速的提升初学者 ...

最新文章

  1. H.264的一些资料整理
  2. VS中调试CS程序时提示:不支持互操作调试
  3. AngularJS路由使用案例
  4. PHP — Cookie and Session篇
  5. SAP Commerce Cloud CMS page 和 page template 的概念
  6. rss spring 接口_spring 接口支持返回多种格式
  7. SQL基础-- 数据处理(DML、RETURNING、MERGE INTO)
  8. cdh中hdfs非ha环境迁移Namenode与secondaryNamenode,从uc机器到阿里;
  9. 例子---PHP与Form表单之一
  10. c语言操作目录,c语言中目录及文件操作.doc
  11. 04-11 常见接口安全测试工具
  12. Shell:export命令
  13. pytorch图片数据归一化,通常传入transforms.Normalize(mean,std,inplace=False)中的mean和std是如何获取的?
  14. 根据crash学习ARM64虚拟地址空间布局
  15. Linux 文件系统类型 文件系统结构 与Windows文件系统的比较
  16. CAD打开多个文档只启动一个程序
  17. 分支-04. 出租车计价(15)
  18. 原生html例子,原生js的innerHTML用法示例
  19. 【FPGA】自动售货机综合实现
  20. 微信小程序view标签hover-class属性和text标签selectable和decode属性

热门文章

  1. CAP 原理和分布式矩阵的应用
  2. overflow属性的用法
  3. [kuangbin带你飞]专题十二 基础DP1 题解+总结
  4. c语言的源程序的后缀名是,C语言源程序文件的后缀名是()。
  5. IBM x3690 x5服务器安装Debian Linux
  6. finall,finally,finalize
  7. c语言字符指针分配内存,内存分配函数及使用注意事项,C语言内存分配函数完全攻略...
  8. Android 插件化学习 加载apk并调用类的函数
  9. pci和pci_PCI合规性
  10. ArangoDB——图遍历 Graph