笔记不定期更新,读到哪里更到哪里:D
5.1 for循环
使用方法:
int i;//举例
for(i=0;i<5;i++) //控制部分,注意用分号分隔每个部分,结尾不需要分号
cout<<"哼哼啊啊啊啊啊"; //循环体注意缩进
格式:
for(初始化,循环测试,循环更新)
循环测试部分的参数会被强制转换为bool类型,非0转为true,0转为false(如果通过这种方式转换为ture将会导致死循环)
也就是说,循环测试部分的参数就像汇编语言中的cmp和je,先比较,比较完得出参数(个人理解,这部分可以划掉)。
循环将在循环测试部分变为0后停止。
1.表达式和语句
表达式的概念:任何值或任何有效的值和运算符的组合都是表达式
在C++中,每个表达式都有值(由此可判断是不是表达式),如:
22+22 是值为44的表达式。
像x<y这样的关系表达式将被判定为bool值,如:
int x;
x=100;
cout<<(x<3); //结果是0,因为cout在显示bool值前会将其转换为int类型
为了判定:表达式x=100,C++将会把100赋给x,
当判定一个表达式的值这种操作改变了内存中的数据的值时,我们说表达式有副作用。
我们在使用这种表达式时把赋值当成主要目的,但从C++的角度来看,判定才是主要目的。
判定x+15并没有副作用,因为它将计算出一个新的值,因此,一般有副作用的表达式都是赋值表达式。
将表达式转换成语句的方式:加上分号
如:
x=10 //是一个表达式
x=10; //是一个语句(表达式语句)
编译器允许无意义的语句,但可能会直接跳过执行。
2.非表达式和语句
任何表达式加上分号都能成为语句,但语句去掉分号不一定是表达式,如:
int toad; //它没有值,因此去掉分号也不是表达式
也并非所有语句都满足语句=表达式+分号,如for语句。
不是表达式就不能赋值和被赋值(因为不是表达式就没有值)
3.修改规则:
可以这么做:
for(int i=0;i<5;i++)
不要被书中的格式误导,不可以直接省略分号!!!(编程得来的经验)
在循环初始化部分声明的变量在循环结束后就会消失(但某些老式实现会保留变量)
5.1.2
阶乘的方法:
x*(x-1)! //零阶乘(0!)被定义为1
程序5.4:
由于前两个阶乘的结果都是1,所以在循环开始前直接为数组进行赋值。
表达式i<ArSize导致循环在数组索引到ArSize-1的地方停止
5.1.3
可以通过修改循环更新表达式来改变步长。
如:
int by=2;
for(int i=0,i<5,i=i+by) //注意赋值表达式的使用,i+by是无意义的
重点:循环更新表达式可以是任何有效的表达式
5.1.4
程序5.6:
循环初始化中int i=word.size() - 1 //这里的字符串是使用cin得来的,结尾包含空字符,所以最后-1
该程序使用了关系运算符大于或等于(>=)
5.1.5
粗略地讲,a++意味着使用a的当前值进行计算,然后再将a的值+1
++a则是先把a+1,再计算。
注意:不要在同一个语句内对同一个值递增或递减多次
5.1.6
副作用指的是在计算表达式时对某些东西进行了修改,
顺序点是程序执行过程中的一个点,在这里确保所有副作用都已完成。
语句中的每个分号都是顺序点,任何完整的表达式末尾也是顺序点。
y=(4+x++)+(6+x++);//分号是顺序点,因此这条语句在结束时才完成修改
5.1.7
如果递增运算符仅进行计算,没有被使用,则使用前缀格式和后缀格式没有任何区别,
但在用户定义的类中,前缀版本的效率比后缀版本的高。
5.1.8
将*和++同时用于指针时:
前缀递增递减和解除引用运算符的优先级相同,从右到左结合。
后缀递增递减的优先级比前缀递增递减高,从左到右结合。
5.1.9 组合赋值运算符
格式:
+=、-=、*=、/=、%=
含义:先将两个操作数进行计算,然后将得到的结果赋给左边的操作数
5.1.10
可以在循环体内包含任意条语句,方法是用花括号构造一个代码块(代码块被视为一条语句)
如果在代码块中声明变量,在代码块执行完毕后会释放该变量。
如果内外部语句块中有两个名称相同的变量,则在内部语句块结束之前,新变量将代替旧变量。
5.1.11 逗号运算符
逗号运算符允许两个表达式放到只允许放一个表达式的地方。
在同一语句内,逗号只能有一种含义(列表分隔符或运算符),例如:
for(int x=0,y=10; ......)不被允许,因为逗号已经是列表分割符了。
逗号运算符还有另外两个特性:
1.逗号运算符是一个顺序点
2.逗号表达式的值是逗号右边的值
在所有运算符中,逗号运算符的优先级是最低的,例如:
x=7,240; //结果为7,240不起作用
但这样的语句:
x=(7,240); //结果为240,原因为特性2
5.1.12 关系表达式
关系运算符可以对数字进行比较,for语句中就是靠关系运算符得出ture和false,
可以将它们用于:
数字、字符、string类型。不能用于C风格字符串。
5.1.14
因为C++将C风格字符串视为第一个字符的地址,因此无法使用==进行比较
如果想要比较C风格字符串,需要使用strcmp()函数,该函数接受两个字符串地址作为函数,
如果相同则返回0,如果第一个字符串的ASCII码比第二个字符串小,则返回负数,大则返回正数。
(ASCII码中,大写字母的编码比小写字母小)
这里顺便提一下之前学过的知识:C风格字符串的结尾是通过空字符而非数组长度确定的。
可以使用strcmp()函数在字符串相等时返回0(false)的特性用它来进行循环比较。
strcmp()的用法和汇编语言cmp有点像,如:
int str1=1,str2=0;
strcmp(str1,str2)>0; //将返回true
5.1.15
可以将关系运算符(如!=)用于string对象。例如:
word !="mate"
同时,可以使用数组表示法表示string对象的内容(老知识)
5.2 while循环
while是只有测试条件和循环体的for循环。
while(word[i] !='\0')
它的循环体必须修改i的值,否则将陷入死循环。
可以改成这样:
while(word[i])
它的效果不变,因为当i为空字符时,其编码为0,也就是false。
重点:不同于C风格字符串,string类不使用空字符来标记字符串末尾。
5.2.1
省略for循环的测试表达式将会导致死循环。
通常,程序员使用for循环,因为它能将所有相关的信息放到一个地方,
而选择在无法预先知道循环的次数时使用while循环。
记住,不要往循环的括号后面加分号,因为分号用来表示语句结束。
5.2.2
为了实现延时,可以使用循环,但是更好的方式是使用系统时间完成这个任务。
函数clock()可以完成这个任务,它返回开始执行后的系统时间,
为了控制其返回的时间单位和类型,需要使用头文件<ctime>中的定义。
它定义了一个符号常量:CLOCKS_PER_SEC,该常量为每秒钟包含的系统时间数,
将系统时间除以它将得到秒数,将秒数乘以它也能得到系统时间。
在ctime中定义了clock的返回类型(系统时间的类型)的别名clock_t,
使用clock_t创建变量将会被转换为头文件定义的系统时间的类型。
clock_t 变量名=输入的秒数*CLOCKS_PER_SEC;//可以将输入的秒数转换成系统时间
程序5.14解读:
clock_t delay =secs * CLOCKS+PER_SEC;//同上
clock_t start=clock(); //获得循环开始前的时间
while(clock() - start<delay); //用循环开始后的时间减去开始前的时间,算出已经循环了多久
类型别名:
C++为类型建立别名的方式有两种:
第一种:使用预处理器:#define 替换类型名 被替换的类型名
第二种:使用关键字:typedef 被替换的类型名 替换类型名
第二种方式同样可用于某种类型的指针,如:
typedef char * byte_pointer; //用byte_pointer代替char类型指针
使用tapedef进行置换可以在声明指针变量时无视必须在每个指针前都加上*的规则,如:
typedef type * char;
type pa,pb;
5.3 do while循环
do while循环不同于前面的两种循环是入口条件循环,它是出口条件循环,两者的差别是:
入口条件循环有可能一次都不会执行循环体内语句,出口条件循环则至少会执行一次循环体内语句。
do while循环多用于比较用户的输入。
5.4 基于范围的for循环(C++11)
这种循环简化了对数组或容器(模板)类反复执行同样的操作的循环,如下所示:
double prices[5]={4.99,10.99,6,87,7,99,8,49};
for(double x : prices) //冒号后面应为元素(使用{})或可代表元素的对象名(如数组名和指针)
cout<<x; //在这里,x代表prices的第一个元素
如果要用这种循环修改数组的内容,则需要使用引用变量(第8章再谈具体的):
for(double &x : prices)
5.5 循环和文本输入
5.5.1 cin进行输入
cin将会忽略换行符和空格,而且更为复杂的是,发送给cin的输入将会被缓冲,
也就是说,只有用户按下回车后,内容才会被发给程序。
(这个地方建议自己去编程理解)
5.5.2
这个地方就不多说了,使用cin.get()虽然能读入空格,但是输入依旧会被缓冲。
引用是C++新增的一种类型,头文件iostream将cin.get(ch)的参数声明为引用类型(这段不重要)。
5.5.3
C++中通过函数重载,可以声明多参数列表不同的同名函数(不同的函数版本)。
剩下的依旧是在讲C++和C语言的不同之处,就不多说了。
5.5.4 文件尾条件
前面的程序表明,使用某个符号表示输入结束很难令人满意(因为输入将被缓冲)
如果输入来自文件,则可以使用一种技术:检测文件尾(EOF)
很多操作系统都允许用文件替换键盘输入(重定向),
例如有一个名为 gofish.exe的可执行程序和一个名为fishtale的文本文件,则可以:
gofish<fishtale //在命令提示符中输入这行命令,<是命令提示符模式的重定向运算符
重点:有些C++实现允许通过键盘来模拟文件尾条件,大多为使用Ctrl+Z(我使用的是Microsoft Visual)
因此应在行首按下Ctrl+Z随后按下回车键。
检测到EOF后,cin将两位(eobit和failbit)都设置为1,因此有两种方法可检测EOF是否被检测到:
如果检测到EOF,则函数cin.eof()返回ture,否则将返回false
如果eobit或failbit位被设置为1,则函数cin.fail()返回ture,否则返回false
注意,cin.eof和cin.fail在事后报告,因此应在读取后再使用它们。
fail()相较于eof()可用于更多的实现中,因此程序5.18中使用了fail(),
它使用cin.fail()检测EOF是否被检测到,如果结果为ture则循环检测部分为false(0),循环体不执行。