一,深入while循环
-
/******************************************************************************** * @author: Mr.Y * @date: 2022/2/3 17:07 * @description: 根据用户键入的整数求和 ********************************************************************************/ #include <stdio.h> int main(void) { long num; long sum = 0L; int status; printf("Please enter an integer to be summed "); printf("(q to quit):\n"); 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; }
1,程序注释
-
status == 1
- ==运算符是C的相等运算符,该表达式判断status是否等于1。
-
scanf()
- scanf()返回成功读取项的数量。如果scanf()成功读取一个整数,就把该数存入num并返回1,随后返回值将被赋给status。如果用户输入的不是数字,scanf()会读取失败并返回0.此时,status的值就是0,循环结束。
- 如果scanf()在转换之前出了问题(如:检测到文件结尾或遇到硬件问题),会返回一个特殊值EOF(其值通常被定义为**-1**)。这个值也会引起循环终止。
-
伪代码
-
伪代码(pseudocode),是一种用简单的句子表示程序思路的方法,它与计算机语言的形式相对应。伪代码有助于设计程序的逻辑。确定程序的逻辑无误之后,再把伪代码翻译成实际的编程代码:如下伪代码
-
把sum初始化为0 提示用户输入数据 读取用户输入的数据 当输入的数据为整数时,输入添加给sum, 提示用户进行输入, 然后读取下一个输入 输入完成后,打印sum的值
-
-
-
每次循环都被称为一次迭代(iteration)
2,观察下面程序输出并分析
-
/******************************************************************************** * @author: Mr.Y * @date: 2022/2/3 19:35 * @description: ********************************************************************************/ #include <stdio.h> int main(void) { int n = 0; while (n++ < 3) printf("n is %d\n",n); printf("That's all this program does.\n"); return 0; } /*** * output * n is 1 * n is 2 * n is 3 * That's all this program does. */
-
/******************************************************************************** * @author: Mr.Y * @date: 2022/2/3 19:35 * @description: ********************************************************************************/ #include <stdio.h> int main(void) { int n = 0; while (n++ < 3); printf("n is %d\n",n); printf("That's all this program does.\n"); return 0; } /*** * output * n is 4 * That's all this program does. */
-
/******************************************************************************** * @author: Mr.Y * @date: 2022/2/3 19:35 * @description: ********************************************************************************/ #include <stdio.h> int main(void) { int n = 0; while (n++ < 3) { printf("n is %d\n", n); printf("That's all this program does.\n"); } return 0; } /*** * output * n is 1 * That's all this program does. * n is 2 * That's all this program does. * n is 3 * That's all this program does. */
-
while语句本身使用复合语句,在语句构成上,它也是一条单独的语句。该语句从while开始执行,到第1个分号结束。在使用了复合语句的情况下,到右花括号结束。
二,用关系运算符和表达式比较大小
-
while循环经常依赖测试表达式作比较,这样的表达式被称为关系表达式(relational expression),出现在关系表达式中间的运算符叫做关系运算符(relational operator)。C语言中的所有关系运算符如下:
-
运算符 含义 < < < 小于 < = <= <= 小于或等于 = = == == 等于 > = >= >= 大于或等于 > > > 大于 ! = != != 不等于
-
-
虽然关系运算符可用来比较浮点数,但是要注意:比较浮点数时,尽量只使用**<和>**。因为浮点数的舍入误差会导致在逻辑上应该相等的两数却不相等。
-
使用fabs()函数(声明在math.h头文件中)可以方便地比较浮点数,该函数返回一个浮点值的绝对值。
-
/******************************************************************************** * @author: Mr.Y * @date: 2022/2/4 14:53 * @description: 浮点数大小比较 ********************************************************************************/ #include <stdio.h> #include <math.h> int main(void) { const double ANSWER = 3.14159; double response; printf("What is the value of pi?\n"); scanf("%lf",&response); while (fabs(response - ANSWER) > 0.0001) { printf("Try again!\n"); scanf("%lf",&response); } printf("Close enough!\n"); return 0; } /*** * output * What is the value of pi? * 1 * Try again! * 2.3 * Try again! * 3.1415 * Close enough! * * /
-
1,什么是真
-
/******************************************************************************** * @author: Mr.Y * @date: 2022/2/4 15:03 * @description: 真假的表示 ********************************************************************************/ #include <stdio.h> int main(void) { int true_val,false_val; true_val = (10 > 2); //关系为真的值 false_val = (10 == 2); //关系为假的值 printf("true = %d; false = %d",true_val,false_val); return 0; } /*** * output * true = 1; false = 0 * 对于C而言,表达式为真的值是1,表达式为假的值是0。 */
-
一些C程序使用下面的循环结构,由于1为真,所以循环会一直进行。
-
while(1) { ...... }
-
-
一般而言,所有的非零值都视为真,只有0被视为假。只要测试条件的值为非零,就会执行while循环。
2,_Bool类型
-
C99新增了**_Bool类型,表示真或假的变量被称为布尔变量**(Boolean variable)。
-
_Bool类型的变量只能存储1(真)或0(假)。如果把其他非零数值赋给布尔类型的变量,该变量会被设置为1。
-
/******************************************************************************** * @author: Mr.Y * @date: 2022/2/4 16:00 * @description: 使用布尔类型改造上面示例 ********************************************************************************/ #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; } /*** * output * Please enter an integer to be summed (q to quit):12 * Please enter next integer (q to quit):23 * Please enter next integer (q to quit):q * Those integers sum to 35. */
- C99提供了stdbool.h头文件,该头文件让bool成为**_Bool的别名,而且把true和false分别定义为1和0**的符号常量。包含该头文件后,写出的代码可以与C++兼容。
- 如果系统不支持布尔类型,导致无法运行该程序,可以把布尔替换成int即可。
3,优先级和关系运算符
-
关系运算符的优先级比算术运算符(包括+和-)低,比赋值运算符高。
-
关系运算符之间有两种不同的优先级
- 高优先级组:<<= >>=
- 低优先级组: == !=
-
运算符优先级
-
运算符(优先级从高至低) 结合律 ( ) 从左往右 - + ++ – sizeof 从右往左 * / % 从左往右 + - 从左往右 < > <= >= 从左往右 == != 从左往右 = 从右往左
-
三,不确定循环和计数循环
- 不确定循环(indefinite loop),指在测试表达式为假之前,预先不知道要执行多少次循环。如前面用户输入数字计算示例,不知用户何时结束。
- 计数循环(counting loop),这类循环在执行循环之前就知道要重复执行多少次。
四,for循环
-
/******************************************************************************** * @author: Mr.Y * @date: 2022/2/4 22:35 * @description: for循环示例 ********************************************************************************/ #include <stdio.h> int main(void) { const int NUMBER = 22; int count; for (count = 0; count <= NUMBER ; count++) printf("Be my Valentine! count = %d\n",count); return 0; } /*** * output * Be my Valentine! count = 0 * Be my Valentine! count = 1 * Be my Valentine! count = 2 * ...... * Be my Valentine! count = 21 * Be my Valentine! count = 22 */
- 关键字for后面的括号中有3个表达式,分别用两个分号隔开。
- 第一个表达式是初始化,只会在for循环开始时执行一次。
- 第二个表达式是测试条件,在执行循环之前对表达式求值。如果表达式为假,循环结束。
- 第三个表达式执行更新,在每次循环结束时求值。
- 完整的for语句还包括后面的简单语句或复合语句。for圆括号中的表达式也叫控制表达式,他们都是完整表达式。
- 关键字for后面的括号中有3个表达式,分别用两个分号隔开。
五,逗号运算符
-
逗号运算符扩展了for循环的灵活性,以便在循环头中包含更多的表达式。
-
/******************************************************************************** * @author: Mr.Y * @date: 2022/2/5 15:12 * @description: 逗号运算符 ********************************************************************************/ #include <stdio.h> int main(void) { const int FIRST_OZ = 46; const int NEXT_OZ = 20; 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; } /*** * output * ounces cost * 1 $0.46 * 2 $0.66 * 3 $0.86 * 4 $1.06 * ...... * 15 $3.26 * 16 $3.46 */
-
其次,逗号也可用作分隔符。在下面语句中的逗号都是分隔符,不是逗号运算符。
-
char ch,date; printf("%d %d\n",chimps, chumps);
-
六,出口条件循环:do while
-
出口条件循环(exit-condition loop),即在循环的每次迭代之后检查测试条件,保证了至少执行循环体中的内容一次。
-
/******************************************************************************** * @author: Mr.Y * @date: 2022/2/5 15:54 * @description: 出口条件循环 ********************************************************************************/ #include <stdio.h> int main(void) { const int secret_code = 13; int code_entered; do { printf("To enter the triskaidekaphobia therapy club,\n"); printf("please enter the secret code number: "); scanf("%d",&code_entered); }while (code_entered!=secret_code); //当输入的值是13退出。 printf("Congratulations! You are cured!\n"); return 0; }
1,do while格式
-
do statement while (expression);
- statement可以是一条简单语句或复合语句。
- do while循环在执行完循环体后才执行测试条件,所以至少执行循环体一次;而for或while循环都是在执行循环体之前先执行测试条件。do while循环适用于那些至少要迭代一次的循环。
七,如何选择循环
-
首先确定需要入口条件循环还是出口条件循环。一般而言入口条件循环用得比较多。
-
当循环涉及初始化和更新变量时,用for循环比较合适,而在其他情况下用while循环更好。例如:
-
while (scanf("%ld", &num) == 1)
-
-
对于涉及索引计数的循环,用for循环更适合。例如:
-
for (count = 1; count <= 100; count++)
-
八,嵌套循环
-
嵌套循环(nested loop)指在一个循环内包含另一个循环。嵌套循环常用于按行和列显示数据。
-
/******************************************************************************** * @author: Mr.Y * @date: 2022/2/5 17:11 * @description: ********************************************************************************/ #include <stdio.h> #define ROWS 6 #define CHARS 10 int main(void) { int row; char ch; for (row = 0; row < ROWS; row++) //外层循环 { for (ch = 'A'; ch < ('A' + CHARS); ch++) //内层循环 printf("%c", ch); printf("\n"); } return 0; } /*** * OutPut * ABCDEFGHIJ * ABCDEFGHIJ * ABCDEFGHIJ * ABCDEFGHIJ * ABCDEFGHIJ * ABCDEFGHIJ */
-
嵌套循环中的内层循环在每次外层循环迭代时都执行完所有的循环。
九,数组
-
数组可以作为一种存储多个相关项的便利方式。
-
数组(array)是按照顺序存储的一系列类型相同的值,整个数组有一个数组名,通过整数下标访问数组中单独的项或元素(element)。如,以下声明:
-
float debts[20]; //声明debts是一个内含20个元素的数组,每个元素都可以存储float类型的值。数组的第一个元素是debts[0],第二个元素是debts[1],以此类推,直到debts[19]。注意数组的编号是从0开始。
-
-
考虑到影响执行的速度,C编译器不会检查数组的下标是否正确。下面的代码,都不正确。
-
debts[20] = 88.32; //该数组元素不存在 debts[33] = 828.12; //该数组元素不存在
-
编译器不会查找这样的错误。当运行程序时,这会导致被放置在已被其他数据占用的地方,可能会破坏程序的结果甚至导致程序异常中断。
-
-
数组的类型可以是任意数据类型。
-
如果char类型的数组末尾包含一个表示字符串末尾的空字符**\0**,则该数组中的内容就构成了一个字符串。
-
用于识别数组元素的数字被称为下标(subscript),索引(index)或偏移量(offset)。下标必须是整数,而且要从0开始计数。数组的元素被依次存储在内存中相邻的位置。
1,在for循环中使用数组
-
/******************************************************************************** * @author: Mr.Y * @date: 2022/2/5 19:52 * @description: 使用循环处理数组 ********************************************************************************/ #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]); 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; } /*** * output * Enter 10 golf scores: * 99 95 109 105 100 96 98 93 99 97 98 * The scores read in are as follows: * 99 95 109 105 100 96 98 93 99 97 * Sum of scores = 991, average = 99.10 * That's a handicap of 27 */
- 注意,int类型数组元素的用法与int类型变量的用法类似。要读取int类型变量fue,应该这样写
scanf("%d",&fue)
。上面程序是因为要读取int类型的元素score[index]
,所以写成scanf("%d",&score[index])
。
- 注意,int类型数组元素的用法与int类型变量的用法类似。要读取int类型变量fue,应该这样写
2,使用函数返回值的循环示例
-
编写有返回值的函数,要完成以下内容。
- 定义函数时,确定函数的返回类型。
- 使用关键字return表明待返回的值。
-
/******************************************************************************** * @author: Mr.Y * @date: 2022/2/5 20:48 * @description: 计算数的整数幂 ********************************************************************************/ #include <stdio.h> double power(double n,int p); //ANSI函数原型 int main(void) { double x,xpow; int exp; printf("Enter a number and the positive integer power"); printf("to which\n the number will be raised. Enter q"); printf(" to quit.\n"); while (scanf("%lf%d", &x,&exp) == 2) { xpow = power(x , exp); //函数调用 printf("%.3g to the power %d is %.5g\n",x,exp,xpow); printf("Enter next pair of numbers or q to quit.\n"); } printf("Hope you enjoyed this power trip -- bye!\n"); return 0; } double power(double n,int p) //函数定义 { double pow = 1; int i; for (i = 1;i <= p; i++) pow *= n; return pow; //返回pow的值 } /*** * Enter a number and the positive integer powerto which * the number will be raised. Enter q to quit. * 2 2 * 2 to the power 2 is 4 * Enter next pair of numbers or q to quit. * 3 3 * 3 to the power 3 is 27 * Enter next pair of numbers or q to quit. * q * Hope you enjoyed this power trip -- bye! * /
-
**power()**函数在程序中出现了3次。首次出现是:
-
double power(double n, int p); //ANSI函数原型
- 这是power()函数的原型,它声明程序将使用一个名为power()的函数。开头的关键字double表明power()函数返回一个double类型的值。编译器要知道**power()函数返回值的类型,才能知道有多少字节的数据,以及如何解释它们。这就是为什么必须声明函数的原因。圆括号中的
double n
,int p
表示power()**函数的两个参数类型。
- 这是power()函数的原型,它声明程序将使用一个名为power()的函数。开头的关键字double表明power()函数返回一个double类型的值。编译器要知道**power()函数返回值的类型,才能知道有多少字节的数据,以及如何解释它们。这就是为什么必须声明函数的原因。圆括号中的
-
-
第二次出现:
-
xpow = power(x,exp); //函数调用
- 程序调用power(),把两个值传递给它。该函数计算x的exp次幂,并把计算结果返回给主调函数。在主调函数中,返回值将被赋给变量xpow。
-
-
第三次出现:
-
double power(double n, int p) //函数定义
- power()有两个形参,一个是double类型,一个是int类型,分别由变量n和变量p表示。
-
-
为什么在使用scanf()的返回值之前没有声明scanf()?为什么在定义中说明power()的返回类型为double,还要单独声明这个函数?
- 编译器在程序中首次遇到power()时,需要知道power()的返回类型。此时,编译器尚未执行到power()的定义,并不知道函数定义中的返回类型是double。因此,必须通过前置声明预先说明函数的返回类型。前置声明告诉编译器,power()定义在别处,其返回类型为double。如果把power()函数的定义置于main()的文件顶部,就可以省略前置声明,因为编译器在执行到main()之前已经知道power()的所有信息。但是,这不是C的标准风格。因为**main()通常只提供整个程序的框架,做好把main()**放在所有函数定义的前面。另外,通常把函数放在其他文件中,所以前置声明必不可少。
- stdio.h头文件中已经包含了scanf(),printf()和其他I/O函数的原型。