第五章 循环和关系表达式
文章目录
for循环
递增/递减运算符和指针
前缀递增、前缀递减和解除应用运算符的优先级相同,以从右至左的方式进行结合。
后缀递增和后缀递减的优先级相同,但比前缀运算符的优先级高,这两个运算符以从左至右的方式进行结合。
*pt=ar[1];
++*pt; //先取得pt指向的值,然后将这个值加1,不是下一个元素
*++pt; //指针加1,取得的是下一个元素的值
x=* pt++; //后缀++运算符的优先级更高,这意味着将运算符用于pt,而不是 *pt,因此对指针递增。 *pt++的值为下一个元素的值,pt的值为下下个元素的地址
int main(){
using namespace std;
float x,y;
double arr[5]={1.2,3.4,5.6,6.7,6.7};
double *pt=arr;
++pt;
cout<<*pt<<endl;
cout<<pt<<endl;
cout<<*++pt<<endl;
cout<<*pt<<endl;
cout<<++*pt<<endl;
cout<<pt<<endl;
cout<<pt<<endl;
cout<<*pt++<<endl;
return 0;
}
组合赋值运算符
+=;-=;*=;/=;%=
复合语句
在循环体中包含任意多条语句,用两个花括号来构造一条复合语句(代码块)。
for(int i=1;i<=5;i++)
{
cout<<"value: "<<i<<endl;
cin>>number;
sum+=number;
}
for后没有冒号。
如果在语句块中定义一个变量,则仅当程序执行该语句块的语句时,该变量才存在,执行完该语句块后,变量将被释放。
在外部语句块中定义的变量在内部语句块中也是被定义了的。
如果在一个语句块中声明一个变量,而外部语句块中也有一个这种名称的变量,则在声明位置到内部语句块结束的范围内,新变量将隐藏旧变量:然后旧变量再次可见。
int main(){
using namespace std;
int x=20;
{
int y=100;
cout<<x<<endl;
//x=50;
cout<<x<<endl;
cout<<y<<endl;
}
cout<<x<<endl;
//cout<<y<<endl;
return 0;
}
如上边程序所示,输出为20 20 100 20
如果不注释掉cout<<y<<endl;则会编译出错
如果不注释掉x=100;输出为20 50 100 50
逗号运算符
逗号运算符允许把两个表达式放在c++句法只允许放在一个表达式的地方,例如:
假设一个循环,每轮都将一个变量加1,将另一个变量减1,则**++j,–i**
还有 int i,j;
int x=(1,024); //值为右侧表达式的值,024为20,所以x=20
int y;
y=1,024; //运算符优先级导致被判定为(y=1),024;。所以y=1
赋值、比较和可能犯的错误
m==4;和 m=4;
C风格字符串的比较
word=="mate";//word是数组名
数组名是数组的地址,用括号引起的字符串常量也是其地址,因此上面的语句是判断地址是否相同,答案是否定的。应使用strcmp()函数来比较:
strcmp()
该函数接受两个字符串地址作为参数,这意味着参数可以是指针、字符串常量或字符数组名。如果两个字符串相同,该函数返回0;如果第一个字符串按字面顺序排在第二个字符串之后,则strcmp()返回一个正数值。实际上,按系统排列顺序更准确,例如ASCII码所有的大写字母的编码都比小写字母小。
虽然不可以用关系运算符比较字符串,但可以用来比较字符,因为字符实际上是整型。
#include <iostream>
int main(){
using namespace std;
char word[5]="?ate";
for(char ch='a';strcmp(word,"cate");ch++)
{
cout<<word<<endl;
word[0]=ch;
}
cout<<"loop end word "<<word<<endl;
return 0;
}
用strcmp()检测相等或排列顺序
如果str1和str2相等:strcmp(str1,str2)==0 表达式为true
如果str1和str2不相等:strcmp(str1,str2)!=0以及strcmp(str1,str2)表达式为true
如果str1在str2的前面:strcmp(str1,str2)<0表达式为true
如果str1在str2的后面:strcmp(str1,str2)>0表达式为true
根据要如何设置测试条件,strcmp()可以扮演==、!=、<和>运算符的角色。
比较string类字符串
使用string类字符串将比C-风格字符串更为简单
#include <iostream>
#include <string>
int main(){
using namespace std;
string word="?ate";
for(char ch='a';word!="cate";ch++)
{
cout<<word<<endl;
word[0]=ch;
}
cout<<"loop end word "<<word<<endl;
return 0;
}
while循环
等待一段时间,编写延时循环
让程序等待一段时间很有用,例如,读者可能会遇到这样的程序,在屏幕上显示了一条信息,还没来得及阅读之前,又出现了其他内容。
long wait =0;
while(wait<10000)
wait++;
这种方法的问题是,当计算机处理器的速度发生变化时,必须修改技术限制。更好的方法是让系统时钟来完成这种工作。
有一个函数可以完成这项工作,函数名为clock(),返回程序开始执行后所用的系统时间。但涉及到两个问题:首先,clock()返回的不一定是秒,其次,该函数返回的类型在某些系统上可能是long,在另一个系统可能是unsigned long或其他类型。
头文件ctime提供了解决方法:
- 首先,定义了一个符号常量——CLOCK_PER_SEC,该常量等于每秒钟包含的系统时间单位数。系统时间除以这个值,可以得到秒数。
- ctime将clock_t作为clock()返回类型的别名,这意味着可以讲变量声明为clock_t类型,编译器把它转换为long、unsigned long或其他适合系统的类型。
#include <iostream>
#include <ctime>
int main(){
using namespace std;
cout<<"Enter the delay time: ";
float secs;
cin>>secs;
clock_t delay=secs*CLOCKS_PER_SEC;
cout<<"starting\a\n";
clock_t start=clock();
while (clock()-start<delay)
;
cout<<"done\a\n";
return 0;
}
类型别名
c++为类型立别名的方式有两种:
-
使用预处理器
#define BYTE char //在编译程序时用char替换所有的BYTE,从而使BYTE成为char的别名。
-
使用typedef
typedef char byte;//将byte作为char的别名
不过声明一系列变量时,用define不适用:
#define FLOAT_POINTER float *
FLOAT_POINTER pa,pb;
预处理器将声明转换为这样:
float *pa,pb; //pa转换为float指针,而pb只是一个float。
typedef则不会有这样的问题。
do while 循环
do while 属于出口条件循环,先执行循环体,在再判定测试表达式,这样循环至少执行一次。
有时使用do while循环更为合理,例如:请求用户输入时,程序必须先获得输入,然后对他进行测试。
#include <iostream>
int main(){
using namespace std;
cout<<"Enter the delay time: ";
int n;
cout<<"enter number ";
cout<<"my \n";
do
{
cin>>n;
}while(n!=7);
cout<<"Yes\n";
return 0;
}
基于范围的for循环(c++11)
它简化了一种常见的循环任务:对数组(或容器类,如vector或array)的每个元素执行相同的操作。
double prices[5]={1.2,3.4,5.6,6.7,6.7};
for (double x:prices)
cout<<x<<std::endl;
该循环显示数组中的每个值。
要修改变量中的元素,使用不同的变量语法:
for (double &x:prices)
x=x*0.80;
循环和文本输入
使用原始的cin进行输入
#include <iostream>
int main(){
using namespace std;
char ch;
int count=0;
cout<<"enter \n";
cin>>ch;
while(ch!='#')
{
cout<<ch;
++count;
cin>>ch; //这一步极其重要,没有这一步,循环将反复处理第一个输入字符
}
cout<<endl<<count<<"read\n";
return 0;
}
但存在一个问题是,输入中的空格没有被回显,原因在于cin在读取char时,会忽略空格和换行符。
使用cin.get(char)进行补救
通常,逐个字符读取输入的程序需要检查每个字符,包括空格、制表符和换行符。
cin.get(ch)读取输入中的下一个字符(即使它是空格),并将其赋给变量ch 。使用这个函数调用替换cin>>ch;可以修补上一个程序的问题。
使用哪一个cin.get()
函数重载允许创建多个同名函数,条件是它们的参数列表不同。例如:
c++中使用cin.get(name,Arsize)和cin.get(ch)
文件尾条件
很多操作系统都支持重定向,允许用文件替换键盘输入。例如,假设在windows中有一个名为gofish.exe的可执行程序和一个名为fishtale的文本文件,则可以再命令提示符模式下输入下面的命令:gofish <fishtale
这样程序将从fishtale文件(而不是键盘)获取输入。
getchar()和putchar()
需要包含头文件stdio.h(或cstdio)
不接受任何参数的cin.get()成员函数返回输入中的下一个字符:
ch=cin.get();
也可以使用cout.put()来显示字符:
cout.put(ch);
嵌套循环和二维数组
#include <iostream>
const int Cities=5;
const int Years=4;
int main(){
using namespace std;
const char * cities[Cities]={
"a","b","c","d","e"
};
int maxtemps[Years][Cities]={
{1,2,4,4,5},
{1,2,7,4,5},
{1,2,4,8,5},
{1,2,5,4,5}
};
cout<<"max:\n";
for (int city=0;city<Cities;++city){
cout<<cities[city]<<":\t";
for (int year=0;year<Years;++year)
cout<<maxtemps[year][city]<<"\t";
cout<<endl;
}
return 0;
}
输出中使用制表符比使用空格可使数据排列更有规则。