C++每日一课(十九)

while循环
while循环是没有初始化和更新部分的for循环,它只有测试条件和循环体
while(test-condition)
    body


第一步,程序会计算圆括号内的测试test-condition
第二步,如果测试为true,则执行循环体中的语句,和for一样如果循环体中语句有多条则需要使用花括号括起来。
第三步,再回去测试test-condition
以上步骤直到test-condition测试结果为false则结束while循环
注意:如果希望循环最终可以结束,循环体中的代码必须完成某种影响测试条件表达式的操作。
     如果循环测试一开始就是false则循环体一次都不会执行


/*
作者:xiesheng
时间:2017-07-16
版本:v1.0
说明:while循环
*/
#include <iostream>
const int ArSize = 20;


int main() {


	using namespace std;
	char name[ArSize];
	cout << "你的名字是:";
	cin >> name;
	cout << "你的名字各字符对应的ASCII码是:" << endl;
	int i = 0;
	while (name[i] != '\0') {
		cout << name[i] << ": " << int(name[i]) << endl;
		i++;
	}


	system("pause");
	return 0;
}



你的名字是:xiesheng
你的名字各字符对应的ASCII码是:
x: 120
i: 105
e: 101
s: 115
h: 104
e: 101
n: 110
g: 103
请按任意键继续. . .


其实上面的while中的测试语句还可以调整为如下
while (name[i]),因为当name[i]为'\0'则为0则表示false
注意:要打印出字符的ASCII码必须要通过强制类型转换为整型,这个时候cout才会打印成整数而不是字符编码。


for与while


标准for与while循环
for(init-expr;test-expr;update-expre){
    statements
}


init-expr;
while(test-expr){
    statements
    update-expr;
}


while(test-expr)
    body


可以把它写成for循环如下
for(;test-expr;)
    body


for循环需要3个表达式,不过表达式可以是空表达式,这里面两个分号是必须的。
注意:当for中把test-expr省掉的时候会表示测试结果是true,这样会一直执行下去。


对于for与while的差别
1.for循环中省掉了测试条件时,会认为条件是true
2.for循环中,可使用初始化语句声明一个局部变量,while中是不可以的
3.如果循环体中存在continue语句时两者表现是有所不同的


程序中一般来说使用for来进行循环计数,对于知道具体执行次数的一般使用for,对于无法预知次数的使用while


设计循环时需要注意如下几点:
1.指定循环的终止条件
2.在首次测试之前初始化条件
3.在条件被再次测试前要进行更新条件




延时循环
这里的延时循环,指的是让计算机进行计数,以便等待一段时间。这是一种早期的技术


long wait = 0;
while(wait<10000)
    wait++;


这上面的延时会存在一个问题,当计算机处理器的运算速度变化时需要对计数进行调整。更好的一种实现方式是使用系统时钟来完成这种工作。
C和C++库中有一个函数clock()
在头文件ctime
1.定义了一个符号常量CLOCKS_PER_SEC,这个常量等于每秒钟包含的系统时间单位数
2.把系统时间除以这个值就可以得到秒数,或者使用秒乘以这个常量来得到系统时间单位为单位的时间
3.ctime中氢clock_t作为clock()返回类型的别名,这样的话可以把变量声明为clock_t类型,编译器会把它转为long、unsigned int等合适的其它类型


/*
作者:xiesheng
时间:2017-07-16
版本:v1.0
说明:程序等待
*/
#include <iostream>
#include <ctime>


int main() {


	using namespace std;
	cout << "请输入需要程序等待的秒数:";
	float secs;
	cin >> secs;
	clock_t delay = secs*CLOCKS_PER_SEC;
	cout << "开始!" << endl;
	clock_t start = clock();


	while (clock() - start < delay) {
		;
	}
	cout << "结束!" << '\a' << endl;


	system("pause");
	return 0;
}



请输入需要程序等待的秒数:10
开始!




请输入需要程序等待的秒数:10
开始!
结束!
请按任意键继续. . .


程序在开始后等待了10秒后显示结束


可以看到程序以系统时间单位为单位(而不是秒为单位)计算延迟时间
上面程序中有一个类型别名,clock_t
类型别名的建立
第一种方式:使用预处理器
#define BYTE char
这样的话预处理器会在编译程序时用char替换所有的BYTE,从而使BYTE成为char的别名
第二种方式:使用C++的关键字typedef来创建别名
typedef char byte;
通用的格式是:typedef typeName 别名;
如下为char指针声明别名可以如下
typedef char * byte_pointer;


注意:使用#define时如下情况
#define FLOAT_POINTER float *
FLOAT_POINTER pa,pb;
那么相当于
float * pa,pb;
这个时间就是pa是一个float指针,pb就是一个float类型的变量


typedef方法不会创建新的类型,它只是为已有的类型建立一个新的名称。




do while循环
这种循环是一种出口条件循环,这种循环会先执行循环体,然后再去测试表达式,决定它是否继续执行循环体,如果为false则会终止,否则进行下一轮的执行和测试。
这种循环会导致循环体至少会执行一次,因为程序流必须要经过循环体后才可以到达测试条件。
do
    body
while(test-expr);


通常来说入口条件循环(for、while)比出口条件循环(do while)要好。
因为入口条件循环可以在循环开始之前对条件进行检查。当然某些情况下出口条件循环也是有好处的,比如需要用户进行输入,获得输入值后再进行测试的情况。


/*
作者:xiesheng
时间:2017-07-16
版本:v1.0
说明:do while
*/
#include <iostream>


int main() {


	using namespace std;
	char exit = 'q';
	char u;
	
	do {
		cout << "请输入字符 q 退出程序:";
		cin >> u;
	} while (u != exit);


	system("pause");
	return 0;
}




请输入字符 q 退出程序:a
请输入字符 q 退出程序:f
请输入字符 q 退出程序:d
请输入字符 q 退出程序:q
请按任意键继续. . .




基于范围的for循环
C++新增了一种循环,它是基于范围的for循环。这个简化了一种常见的循环任务,对数组、容器类(vector、array)的每一个元素执行相同的操作




double prices[5] = {1.25,10.45,6.90,7.98,5.35};
for(double x:prices)
    cout<<x<<std::endl;
这里x表示从数组prices中按顺序取出对应的元素的值
上述的代码则把表把数组中的每一个元素按顺序取出来并打印到屏幕上


注意上面只是把数组中的元素直接取出来,如果想修改数据中的元素值,则需要使用另一种语法


for(double &x:prices)
    x = x*0.8;
&这个符号表明x是一个引用变量。


使用基于范围的for循环和初始化列表
for(int x:{3,4,5,6,7})
    cout<<x<<" ";
cout<<std::endl;


循环与文本输入
循环完成的另一个常见且重要的任务是,逐字符地读取来自文件或键盘的文本。


使用原始的cin进行输入
程序要使用循环来读取来自键盘的文本输入,则必须要有办法知道何时可以停止读取。如何知道这个停止呢?这个时候就需要选择一个特殊的字符,把它作为一个停止标记(这个字符称为哨兵字符)


/*
作者:xiesheng
时间:2017-07-16
版本:v1.0
说明:使用cin来读取输入的文本字符
*/
#include <iostream>


int main() {


	using namespace std;
	char ch;
	int count = 0;	//计数
	cout << "请输入字符串,输入#结束:";
	cin >> ch;	//获取字符
	while (ch != '#') {
		cout << ch;
		++count;
		cin >> ch;	//获得下一个字符
	}
	cout << "总共读入字符数:" << count << endl;
	system("pause");
	return 0;
}



请输入字符串,输入#结束:xiesehng#
xiesehng总共读入字符数:8
请按任意键继续. . .


这个程序中在循环之前先读取第一个输入字符,这样就可以在循环中测试第一个读入的字符,以防第一个字符就是#
如果读到的第一个字符不是#则会进入循环体,显示字符,增加计数,计取下一个字符。
上面的程序这样做是符合循环中的原则的:
循环的结束条件是读到一个字符#
在循环之前通过先读取一个字符做初始化
在循环体结尾时读取下一个字符来做更新


注意上面的程序会在读取字符的时候省略掉空格了,原因是cin读取char值时,与读其它基本类型是一样的,cin忽略空格和换行符。因而输入中的空格是不会被回显的也不会包括在计数内
发送给cin的输入是被缓冲的,这就意味着只有用户按下回车键后,它输入的内容才会被发送给程序




使用cin.get(char)进行读取


/*
作者:xiesheng
时间:2017-07-16
版本:v1.0
说明:使用cin.get(char)来读取输入的文本字符
*/
#include <iostream>


int main() {


	using namespace std;
	char ch;
	int count = 0;
	cout << "请输入字符串,输入#结束:";
	cin.get(ch);	//使用cin.get(ch)来读取字符


	while (ch != '#') {
		cout << ch;
		++count;
		cin.get(ch);	//读取下一个字符
	}
	cout << "总共读入字符数:" << count << endl;
	system("pause");
	return 0;
}



请输入字符串,输入#结束:xie sheng#
xie sheng总共读入字符数:9
请按任意键继续. . .


使用cin.get(char) 后,程序回显了所有字符,并且全部字符计算在内了。


cin.get()这个函数还可以接收两个参数
cin.get(数组名,整型)
第一个数组名也就是一个char*
这里看到cin.get()函数有不同的版本,可以接收一个字符参数,可以接收两个参数,这种能力就是OOP中的函数重载


文件尾条件
上面的程序中我们可以看到作为输入的结束可以使用#,这样做是没有问题的,对于输入来自于文件的则可以使用另一种技术,使用检测文件尾的方式(EOF)


/*
作者:xiesheng
时间:2017-07-23
版本:v1.0
说明:检测文件未尾 EOF
*/
#include <iostream>


int main() {


	using namespace std;
	char ch;
	int count = 0;	//计数器
	cin.get(ch);	//读取一个字符
	while (cin.fail() == false) {	//使用这个方法来校验是否到了文件未尾
		cout << ch;
		++count;
		cin.get(ch);
	}
	cout << endl << count << " 个字符被读入\n";


	system("pause");
	return 0;
}




xiesheng
xiesheng
advent
advent
^Z


16 个字符被读入
请按任意键继续. . .


在Windows系统控制台上可以使用ctrl+z和回车键来模拟EOF条件。
在unix和类unix系统中,用户按ctrl+z组合键会把程序挂起,命令fg恢复运行程序
通过重定向可以用上面的程序来显示文本文件。


EOF结束输入
cin方法检测到EOF的时候,会设置cin对象中一个指示EOF条件的标记。在设置这个标记后cin就不会再读取输入,再次去调用cin也是不会再读取的
对于文件的读取这个是正常的,在读到EOF的时候不会再读取超出文件尾的内容
对于模拟的EOF,可以使用cin.clear()来清除EOF标记,使输入继续进行。注意:在有些系统中cin.clear()是无法恢复的


常见字符输入做法如下循环


while (cin.fail() == false) { //使用这个方法来校验是否到了文件未尾
……
cin.get(ch);
}


上面的while循环部分可以写得更简单点
while(!cin.fail()){
……
cin.get(ch);
}


方法cin.get(char)返回的值是一个cin对象。然而,istream类提供了一个可以把istream对象(cin)转为bool值的函数,当cin出现在需要bool值的地方时这个函数就会被调用。
如果最后一次读取成功了,则转换得到bool值为true,否则是false,那么上面的while循环可以写成如下
while(cin){
……
cin.get(ch);
}




cin.get()的另一个版本:
getchar()、putchar()
上面的两个函数是C语言中的字符I/O函数,在C++中依然可以使用但是需要包含stdio.h这个头文件或者cstdio


不接受任何参数的cin.get()成员函数返回的是输入中的下一个字符
ch = cin.get();
这个函数的工作方式与C中的getchar()相似,把字符编码作为int值返回
注意:cin.get(ch)返回的是一个对象,而不是读取的字符
同样的可以使用cout.put()来显示字符
cout.put(ch); 这个函数与C中的putchar()类似只是它的参数是char而不是int


EOF常量
这个常量是定义在iostream中的,通常来说它被定义为-1,原因是ASCII码为-1的字符是不存在的。
int ch;
ch = cin.get();
while(ch != EOF) {
cout.put(ch);
++count;
ch = cin.get();
}
上面的循环表示,如果ch是一个字符则循环显示,如果是EOF则循环结束。


注意:
上面的写法中定义ch为int类型,原因是cin.get()可能返回的是EOF,而EOF可能是-1,对于某些系统来说这是不兼容的,因为char一般是没有符号的




嵌套循环与二维数组
for循环是一种处下数组的工具,对于多维数组来说需要使用嵌套for循环。


二维数组:
二维数组更加像一个表格,既有行数据又有列数据。
C++中没有提供二维数组类型,但是用户可以创建每个元素本身都是数组的数组。
int arr[4][5];
上面定义了一个二维数组,它的行列数分别是4与5
二维数组的初始化:
可以在声明二维数组时进行初始化
int arr[4][5] = {
{1,1,1,1,1},
{2,2,2,2,2},
{3,3,3,3,3},
{4,4,4,4,4}
};


使用二维数组中的值,可以使用for的嵌套循环
for(int i=0;i<4;i++){
for(int j=0;j<5;j++){
cout<<"arr["<<i"]"<<"["<<j<<"] = "<<arr[i][j]<<endl;
}
}


猜你喜欢

转载自blog.csdn.net/advent86/article/details/75949647