第五章 C控制语句:循环

一个好的语言应该能够提供以下三种形式的程序流:

●顺序执行语句序列(顺序)

●在满足某个条件之前反复执行一个语句序列(循环)

●通过进行一个判断在两个可选的语句序列之间选择执行(分支)

5.1while循环

程序

//summing.c -- 对用户输入的整数求和
#include<stdio.h>
int main(void)
{
	long num;
	long sum = 0L;//把sum初始化为0
	int status;

	printf("Please enter an integer to be summed. ");
	printf("(q to quit):");
	status = scanf("%ld",&num);
	while (status == 1)
	{
		sum = sum + num;
		printf("Please enter next integer (q to quit):");
		status = scanf("%ld",&num);
	}
	printf("Those integers sum to %ld.\n",sum);
	return 0;
}

结果

Please enter an integer to be summed. (q to quit):44
Please enter next integer (q to quit):33
Please enter next integer (q to quit):88
Please enter next integer (q to quit):121
Please enter next integer (q to quit):q
Those integers sum to 286.

C:\Users\51670\source\repos\summing\Debug\summing.exe (进程 6224)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .

1.程序注解

  scanf返回成功读入的项目的个数。如果scanf()成功读入了一个整数,就把这个整数放在num中并返回值1,随后值1被赋值给status(请注意输入值赋给num,而不是status)。如果您输入的不是数字,例如输入q,那么scanf()就不能读入一个整数,所以它的返回值和status都为0。这将使循环终止。

  while是一个入口条件循环,所以程序员必须在进入循环体之前获取输入并检查status的值。

5.2比较大小:使用关系运算符和表达式

1.真值的问题

  关系运算符也可以用于字符的比较。进行比较时使用的是机器的字符代码(ASCLL)。然而,不能使用关系运算符来比较字符串。

  关系运算符也可以用与浮点数。但要小心,在浮点数比较中只能使用<和>。原因在于舍入误差可能造成两个逻辑上应该相等的数不相等。

  如果进行比较的数有一个是常量,则可以把它放在比较表达式的左边,这样有助于发现错误:

5 = canoes;//语法错误
5 == canoes;//检查canoes的值是否为5

2.新的__Bool类型

//boolean.c --使用_Bool变量
#include<stdio.h>
int main(void)
{
	long num;
	long sum = 0L;
	_Bool input_is_good;
	printf("Please enter an integer to be summed. ");
	printf("(q to quit): ");

	input_is_good = (scanf("%ld",&num) == 1);
	while (input_is_good)
	{
		sum = sum+num;
		printf("Please enter next integer (q to quit): ");
		input_is_good = (scanf("%ld", &num) == 1);
	}
	printf("Those integers sum to %ld.\n",sum);

	return 0;
}

  C99还提供了一个stdio.h头文件。包含这个头文件可以使用bool来代替_B00l,并把true和false定义成值为1和0的符号常量。在程序中包含这个头文件可以写出与C++兼容的代码,因为C++把bool、图恩和false定义为关键字。

  关系运算符的优先级要低于包括+和-在内的算数运算符,但是要高于赋值运算符。

5.3不确定循环与计数循环

#define _CRT_SECURE_NO_WARNINGS 1
//sweetie1.s -- 一个计数循环
#include<stdio.h>
int main(void)
{
	const int NUMBER = 22;
	int count = 1;
	                  //初始化
	while (count <= NUMBER)//判断
	{
		printf("Be my Valentine!\n");//动作
		count++;          //更新计数
	}
	return 0;

}

在建立一个重复执行固定次数的循环时涉及到三个动作:

1.必须初始化一个计数器

2.计数器与某个有限的值进行比较

3.每次执行循环,计数器的值都要递增

  while循环条件执行比较的动作,增量运算符执行递增的动作。上述程序中,递增在循环的结尾处执行。这种选择使得有可能不小心漏掉递增的动作。所以更好的方法是使用count++<=NUMBER来吧判断与更新动作结合在一个表达式中,但使用这种方法时计数器的初始化仍然是在循环之外进行的,这样就有可能忘记初始化。

5.4逗号运算符

#define _CRT_SECURE_NO_WARNINGS 1
//2022年4月8日08:57:37
#include<stdio.h>
int main(void)
{
	const int FIRST_OZ = 37;
	const int NEXT_OZ = 23;
	int ounces, cost;

	printf(" ounces cost\n");
	for (ounces = 1, cost = FIRST_OZ; ounces <= 16; ounces++, cost += NEXT_OZ)
		printf("%5d $%4.2f\n",ounces,cost/100.0);
	return 0;
}

  逗号运算符的两个属性。首先,它保证被它分开的表达式按从左到右的次序进行计算(换句话说,逗号是个顺序点,逗号左边产生的所有副作用都在程序运行到逗号右边之前生效)。其次,逗号运算符的值是右边成员的值。逗号也被用作分隔符。

5.5数组

  一个数组就是线性存储的一系列相同类型的值,整个数组有一个单一的名字,单独的项或元素可以使用一个整数索引来进行访问。

float debts[20];

  实际上,可以像使用相同类型的变量那样使用一个数组元素。例如,您可以把一个值读入一个特定的元素:

scanf("%f",&debts[4]);

  一个潜在的易犯错误是:出于执行速度的考虑,C并不检查您是否使用了正确的下标。例如,以下是错误的代码:

debts[20] = 88.32;//没有这个数组元素

  但是编译器并不会发现这样的错误。当程序运行时,这些语句把数据放在可能由其他数据使用的位置上,因而可能破坏程序的结果甚至使程序崩溃。

  如果字符数组包含了空字符\0,那么字符数组的内容就构成一个字符串,其中空字符标志着字符串的结尾。数组中元素是顺序存储的。

在for循环中使用数组

//2022年4月8日09:34:09
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#define SIZE 10
#define PAR 72
int main(void)
{
	int index, score[SIZE];
	int sum = 0;
	float average;

	printf("Enter %d golf scores:\n", SIZE);
	for (index = 0; index < SIZE; index++)
		scanf("%d", &score[index]);//读入10个分数
	printf("The scores read in are as follows:\n");
	for (index = 0; index < SIZE; index++)
		printf("%5d", score[index]);//验证输入
	printf("\n");
	for (index = 0; index < SIZE; index++)
		sum += score[index];//求它们的和
	average = (float)sum / SIZE;//节省时间的方法
	printf("Sum of scores = %d,average = %.2f\n", sum, average);
	printf("That's a handicap of %.0f.\n",average-PAR);
	return 0;
}

结果

Enter 10 golf scores:
102 98 112 108 105 103
99 101 96 102 100
The scores read in are as follows:
  102   98  112  108  105  103   99  101   96  102
Sum of scores = 1026,average = 102.60
That's a handicap of 31.

C:\Users\51670\Desktop\C Program\scores_in\Debug\scores_in.exe (进程 21444)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .

  首先,注意到尽管这个例子显示您输入了11个数,但只有10个被读入了,因为读取循环只读入10个值。因为scanf()跳过空白字符,所以您可以在一行之内输入所有的10个数,也可以在每一行只输入一个数,或者您也可以像这个例子一样混合使用新行与空格来分隔输入(因为要对输入进行缓冲,所以只有当您键入回车键的时候这些数字才被发送给程序)。

  这些例子说明了一些风格问题。首先,使用#define指令创建一个指定数组大小的明显常量(SIZE)是一个好主意,您可以在定义数组和设置循环限制条件时使用这个常量。

  其次,下面的代码可以很方便地处理一个大小为SIZE的数组:

for(index=0;index<SIZE;index++)

  第三,一个好的编程习惯是使程序重复输出或“回显”刚刚读入的值。这有助于确保程序出来了您所期望的数据。

5.6关键概念

  循环是一个强大的编程工具。在建立循环时应该特别注意三个方面:

●明确定义结束循环的条件

●确保在循环判断中使用的值在第一次使用之前已经初始化

●确保循环在每个周期中更新了判断值

  C通过数值计算来处理判断条件。结果为0表示假,任何其他值都表示为真。使用了关系运算符的表达式通常被用来进行判断,他们有些特殊。如果为真,关系表达式的值为1,假为0,这与新的_Bool类型所允许的值保持一致。

  数组由相同类型的邻近的内存位置组成。您需要谨记数组元素是从0开始编号的,这样最后一个元素的下标就比元素个数少1.C并不检查您是否使用了合法的下标值,所以这需要由您自己来负责。

  使用一个函数需要完成三个单独的步骤:

  1.使用函数原型声明该函数

  2.在程序中通过函数调用来使用该函数。

  3.定义函数

  原型使编译器可以检查您是否正确地使用了函数,而定义则规定了函数如何工作。现代的编程习惯是把程序的元素分为接口和实现部分,原型和定义就是这样的例子。接口部分描述了如何使用一个特性,这正是原型所做的;而实现部分说明了采取的具体动作,这正是定义所做的。

posted @ 2022-04-08 10:28  CodeMagicianT  阅读(80)  评论(0编辑  收藏  举报