for循环
for循环的组成部分
for循环完成以下步骤:
-
设置初始值
-
执行测试,看看循环是否应当继续进行
-
执行循环操作
-
更新用于测试的值
for(initialization; test-expression; update-expression) body
C++语法将整个for看作一条语句(包含多条语句时,需要使用复合语句或代码块)
-
test-expression(测试表达式):决定循环体是否被执行,C++强制转换此语句为bool类型,得到的结果是true或false
-
for循环是入口条件(entry-condition)循环,即每轮循环进行前计算测试表达式的值,当表达式结果为false时,将不会执行循环体。
-
update-expression(更新表达式):在每轮循环结束时执行,此时循环体已经执行完毕,更新表达式可以是任意的C++表达式,还可以是其他控制表达式
表达式和语句
首先明确一点,C++中,任何值或任何有效的值和运算符的组合都是表达式。例:10是值为10的表达式,X =20是一个表达式
表达式的副作用:当判定表达式的操作改变了内存中数据的值时,我们说表达式有副作用(side effect)例:(X =100)此表达式作为判定表达式将X 的值赋为100 改变了X 的值
语句:只要加上分号,所有的表达式都可以成为语句,但不一定编程意义 例:rodents + 6; 没有意义
非表达式和语句
对任何表达式加上分号都可以成为语句,但是反过来不成立。即从语句中删除分号并不一定能使它成为一个表达式 例:返回语句、声明语句、for语句都不满足
由此可以判断:int load;
是一条语句,但int load
并不是表达式,因为它没有值,因此eggs = int load * 100;
非法 ;同样 ,不能把for循环赋给变量
修改规则
C++相对于C语言添加的特性,允许for结构的初始化部分直接声明,即:for(int i = 0; i < 5; i++)
是允许的。
for ( for-init-statement condition; expression)
其中for-init-statement被视为一条语句,有自己的分号,因而总共两个分号没有少
使用这种初始化的一个好处:这个变量只存在于for循环中
递增运算符和递减运算符
可以分为前缀形式和后缀形式 即:++X 和 X++,分别表示将X的值加一,进行计算 和 使用当前值进行计算表达式,再将X 的值加一
避免一条语句中重复出现多个递增或递减运算符
副作用和顺序点
副作用(side effect)指的是在计算表达式时对某些东西进行了修改(如储存在变量中的值);顺序点(sequence point)是程序执行过程中的一个点,在这里,进入下一步前将确保对所有的副作用进行了评估。C++中,语句的分号是一个顺序点,另外,任何完整的表达式末尾都是一个顺序点。
何为完整表达式?不是另一个更大的表达式的子表达式。例:表达式语句中的表达式部分以及用作while循环中检测条件的表达式
前缀格式和后缀格式
对于类而言,使用前缀形式比后缀形式运行更快,内置形式没有区别
递增递减运算符和指针
前缀递增,前缀递减和解除引用运算符的优先级相同,从右往左结合。后缀递增和后缀递减优先级相同,但比前缀运算符优先级高,从左往右结合。
注意指针位置是否发生改变。例:++*p 前缀递增和解引用运算符优先级相同,从右往左结合,所以先计算解引用,再计算前缀递增,即:先取得p的值,再把这个值加1;在这种情况下,指针仍指向原位置
复合语句(语句块)
代码块由一对花括号和它们包含的语句组成,被视为一条语句,从而满足句法的要求。因而对于for循环而言,若不使用花括号,那只有for括号后紧跟的一条语句在循环中。
复合语句中定义的变量只有在代码块中存在,代码块执行完后,变量被释放。
其他语法技巧——逗号运算符
逗号运算符允许将两个表达式放到C++语法只允许放一个表达式的位置。例: ++j, --i;
逗号并不总是逗号运算符,也有可能只是将变量列表中相邻的名称分开: int i, j;
逗号运算符是一个顺序点(确保先计算第一个表达式,然后计算第二个表达式)。在所有的运算符中,逗号运算符的优先级是最低的。
字符串的比较
C++将C-风格字符串视为地址,因而不能用关系运算符来比较。
使用C-风格字符串库中的strcmp()函数来比较。
存储在不同数组长度的不同数组中的字符串可能相同,因为C-风格字符串是通过结尾处的空值字符定义的。
string类字符串的比较
类设计使其可以使用关系运算符进行比较。因为类函数重载了运算符。
while循环
while循环是没有初始化和更新部分的for循环,它只有测试条件和循环体:
while (test-condition) body
while循环也是入口条件循环,因此,若条件一开始是false则程序不会执行循环体。
for和while
在C++中,for和while循环本质上是相同的,两者之间可以相互转换
for循环需要三个表达式,但是表达式可以为空,只有分号是不可省略的。例如下面的循环将会一直执行下去:for( ; ; ) body
for循环和while循环的差别:
-
for循环省略测试条件时,将认定条件为true
-
for循环可以用初始化语句声明一个局部变量,但在while循环中不被允许
-
如果循环体中有continue语句,情况不同
等待一段时间:编写延时循环
clock()函数使用系统时钟。包含在头文件ctime中。
ctime定义了一个符号常量:CLOCKS_PER_SEC,该常量等于每秒钟包含的系统时间单位数。因此,将系统时间除以这个值,可以得到秒数。其次,ctime将clock_t作为clock()返回类型的别名,这意味着可以将变量声明为clock_t类型,编译器自动将其转换为long、unsigned int或适合系统的其他类型。
clock()是现在系统时间。
do while 循环
不同于 while和for循环,是出口条件循环(exit condition),即循环至少执行一次。
基于范围的for 循环(C++ 11)
基于范围的for循环简化了一种常见的循环任务:对数组(或容器类,如vector和array)的每个元素执行相同的操作,例:
double prices[5] = {4.66 ,5.66 ,1.55 ,8.36 }; for (double x:prices) cout<< x<<std::endl;
要修改数组中的元素,要使用不同的循环变量语法:
for(double &x :prices) x = x * 0.5;
符号&表明x 是一个引用变量,只有使用引用变量才能改变数组内容,而第一种方式不能。
基于范围的for循环和初始化列表:
for (int x : {3 ,5 ,2 ,8 ,6}) cout<< x <<" "; cout<<'\n';
循环和文本输入
cin支持3种不同的单字符输入,用户接口各不相同。
使用原始的cin进行输入
cin忽略空格和换行符
使用cin.get(char)
cin.get(ch)读取输入中的下一个字符,并将其赋给ch(包括空格)
解释:C语言中,要修改变量的值,必须将变量的地址传给函数,但C++中将参数声明为引用类型即可(声明在头文件iostream)中
不同的getchar()
C++中的函数重载允许同名函数存在不同的参数列表
cin.getchar(char * ,ArSize)第一个参数是数组名(字符串char * 类型的地址)第二个参数是int 类型的整数
cin.get(ch),不接受任何参数 返回iostream中定义的对象
cin.get(),同样不接受任何参数
cin.get(char)只接受一个参数
文件尾条件(EOF)
文件尾的信息在操作系统中被定义,不同操作系统对文件尾的定义可能不同
操作系统的重定向支持从文件输入,输出到文件等一系列操作
很多操作系统支持模拟文件尾条件,在Windows命令提示符下,任意位置按下 Ctrl + Z 和 Enter
检测到文件尾后,cin将两位(eofbit 和 failbit ,这两个标记都是cin对象的属性)都设置为1 。 可以使用函数eof()和 fail()判断是否到达文件尾 注意:两个函数都是事后报告,因而应该将他们放在读取后。
EOF在iostream中被定义为值-1
嵌套循环和二维数组
初始化二维数组
int maxtemps[4][5] = { {9,2,2,3,3}, {7,8,9,63,1}, {2,3,66,55,1}, {4,5,66,6,3} };
二维数组的使用
特殊的,对于char类型的二维数组,提供另一种指针数组,相比定长的char二维数组,更加实用经济(事实上,使用string数组更加方便)
const int Cites=5; //字符串指针数组 const char * cities[Cites]={ "Gribble City", "Gribbletown", "New Gribble", "San Gribble", "Gribble Vista" }; //char类型二维数组 在此处规定定长不超过24个字符 char cities[Cities][25]={ "Gribble City", "Gribbletown", "New Gribble", "San Gribble", "Gribble Vista" }; //string类型数组 自动调整大小 比二维数组更常用 const string cities[Cities]={ "Gribble City", "Gribbletown", "New Gribble", "San Gribble", "Gribble Vista" };