C语言-基础入门-学习笔记(4):选择结构和循环结构
一、选择结构
1. if语句
if语句分为两部分:if头和if体。例如:
if(判断表达式){ //if头
操作1; //if体
操作2;
````
}
其执行顺序为:1.先判断表达式的布尔值是否为真;2.如果是真,则执行if体;否则跳过if体,继续执行后续语句。
if语句经常和else语句组合使用。else语句也由两部分组成:else头和else体:
if(判断表达式){
操作1;
}else{
操作2;
}
其执行顺序为:1.先判断表达式的布尔值是否为真;2.当判断表达式的布尔值为真时,执行if体;当判断表达式的值为假时,执行else体。3. if 和 else 执行完后,该执行语句结束,继续执行后面的语句。
由此可以总结出有if结构、if-else结构和else if结构三种。
范例1
#include <stdio.h>
int main(void){
int salary = 0;
float ratio = 0.0;
printf("Please input your salary:");
scanf("%d",&salary);
if(salary > 50000)
ratio = 0.5;
else if(salary > 10000)
ratio = 0.3;
else if(salary > 7000)
ratio = 0.2;
else if(salary > 5000)
ratio = 0.1;
else
ratio = 0;
printf("The tax is %.2f\n",salary*ratio);
return 0;
}
一般将较重要的放在if分支中,将次要的放在else分支中,按优先级进行排列。
为了避免= 和 == 之间的误写,在if 语句中:使用等号关系表达式时,将右值放在等号的左边。
例如if(2 == a) //这样做法的好处是当不小心将== 写成 =,编译器会报错。
一般情况下,不要讲赋值语句写在if判别条件之中。
2. switch语句
switch语句分为switch头和switch体。switch头包含关键字switch和一个判断表达式;switch体是一个复合语句,包含若干个case语句和一个default语句。标准如下:
switch(判断表达式){ //switch头,下面为switch体
case 常量表达式1:操作1;//分支1
case 常量表达式2:操作2;//分支2
case 常量表达式3:操作3;//分支3
····
default:操作n; //异常情况
}
执行顺序为:1. 计算判断表达式的值;2. 在所有case分支中查找其常量表达式的值与switch头的判断表达式相等的分支。3.如果有则跳转到这个分支,执行其操作,没有跳转default分支,执行其操作。
在switch语句中,遇到break语句便终止执行,跳出本层switch体,继续执行后面的操作。
范例2
#include <stdio.h>
int main(void){
int month = 0;
int day = 0;
/*输入查询的月份*/
printf("which month:");
scanf("%d",&month);
switch(month){
case 2:
printf("there are 28 or 29 days in this month!\n");
break;
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
printf("there are 31 days in this month!\n");
break;
case 4:
case 6:
case 9:
case 11:
printf("there are 30 days in this month!\n");
break;
default:
printf("input a wrong month.\n");
break;
}
return 0;
}
范例3
#include <stdio.h>
int main(void){
int month = 0;
int day = 0;
/*输入查询的月份*/
printf("which month:");
scanf("%d",&month);
if(2 == month)//左边赋值
printf("there are 28 or 29 days in this month!\n");
else if(1 == month
|| 3 == month
|| 5 == month
|| 7 == month
|| 8 == month
|| 10 == month
|| 12 == month)
printf("there are 31 days in this month!\n");
else if(4 == month
|| 6 == month
|| 9 == month
|| 11 == month)
printf("there are 30 days in this month!\n");
else
printf("input a wrong month.\n");
return 0;
}
在使用switch语句时要注意switch体中永远执行不到的语句,比如switch头与第一个标号之间的语句。
在switch语句中通常引用具名常量,因为具名常量是经过#define更换过名字的常量,这样直接用它的名字就可以替换代码中的常量,提高了程序的可读性。
3. 条件操作符
条件操作符是C语言中唯一的三元操作符,其标准如下:
表达式1 ? 表达式2 : 表达式3 :
其执行顺序为:1. 先判断表达式1的布尔值;2. 如果为真,执行表达式2,条件表达式的值为表达式2的值;3. 否则,执行表达式3,条件表达式的值为表达式3的值。
条件表达式最常用的方式是作为赋值表达式的右值。
max = (a > b ? a : b); //求a,b中较大的值
min = (a < b ? a : b); //求a,b中较小的值
在条件表达式中,第2个表达式的值类型必须与第3个表达式的值类型相同。
条件表达式也可以进行嵌套,例如将范例1进行改写:
ratio = salary <= 5000 ? 0.0 : (
salary <= 7000 ? 0.1 : (
salary <= 10000 ? 0.2 : (
salary <= 50000 ? 0.3 : 0.5)))
4. 隐式选择
使用隐式表达的时候,逻辑与表达式和逻辑或表达式中的第2个表达式都是不保证被执行。
范例4
#include <stdio.h>
int main(void){
int a = 8;
int b = 8;
if(10 == (a += 1) && 10 == (b += 1))
printf("if:\ta = %d,b = %d\n",a,b);
else if(10 == (a += 1) && 10 == (b += 1))
printf("else if:\ta = %d,b = %d\n",a,b);
else
printf("else:\ta = %d,b = %d\n",a,b);
return 0;
}
解释:当执行第一个判别式的时候,10 == 9为假,所以后面的表达式也不执行;接下来执行第二个表达式10 == 10为真,则执行后面的表达式,但是整体为假,也不执行;最后进入else语句后,a为10,b为9。
技巧:我们可以借助隐式选择的特点来实现某些情况的限制作用
- 变量用作除数
当变量用作除数时,需要先检查是否为0,为0则后面的不执行。
if(a != 0 && b /a >= a) //将含有判断成分的写在前面
- 使用结构体指针
当变量为结构体指针时,若要访问其成员,必须要保证该变量指向一个实体3。
if(ptr && ptr->data == data)
练习1
//从键盘上读入4个整数,输出这4个整数中最大的值
#include <stdio.h>
int main(void){
int a1 = 0,a2 = 0,a3 = 0,a4 = 0;
int max = 0;
printf("please enter the four numbers:");
scanf("%d %d %d %d",&a1,&a2,&a3,&a4);
max = a1;
if(max < a2)
max = a2;
if(max < a3)
max = a3;
if(max < a4)
max = a4;
printf("Max = %d\n",max);
return 0;
}
练习2
//输出其等级:85~100为'A',60~84为'B',小于60为'C'
#include <stdio.h>
int main(void){
int score;
printf("Please enter the score(1~100):");
scanf("%d",&score);
if(85 <= score && score <= 100){
printf("Your score is A.");
}else if(60 <= score && score <85){
printf("Your score is B.");
}else if(0 <= score && score < 60){
printf("Your score is C.");
}else{
printf("Please enter the right score.");
}
return 0;
}
练习3
//输出其等级:'A'为85~100,'B'为60~84,'C'为小于60(使用switch)
#include <stdio.h>
int main(void){
char grade = 0;
printf("Please enter the grade(A, B or C):");
scanf("%c",&grade);
switch(grade){
case 'A':
printf("85 - 100\n");
break;
case 'B':
printf("60 - 84\n");
break;
case 'C':
printf("0 - 59\n");
break;
default:
printf("Please enter the right grade.\n");
break;
}
return 0;
}
二、循环结构
1. for语句
for语句可以分为两部分:for头和for体。其标准形式如下:
for(表达式1;表达式2;表达式3){ //for头
操作; //for体
}
其中表达式1用作循环结构的初始化;表达式2负责条件的判断;表达式3负责改变表达式2中的循环变量的值。
如果表达式2为空,则将表达式2的值视为真,此时该语句将陷入死循环中。
范例1
//数列求和,计算从m到n的和
#include <stdio.h>
int main(void){
int m = 0;
int n = 0;
int i = 0;
int sum = 0;
printf("Please input m and n:");
scanf("%d %d",&m,&n);
for(;m > n;){ //当m大于n时则一直陷在这个循环中
printf("Error:m must be no more than n.\n");
printf("Please input new m and n:");
scanf("%d %d",&m,&n);
}
for(i = m,sum = 0;i<= n;++i){
sum += i;
}
printf("Sum = %d\n",sum);
return 0;
}
对于表达式1,可以使用多个逗号表达式赋值;但是对于表达式2,则不应该使用逗号表达式。
for循环的嵌套:如果外层循环次数为m,内层循环次数为n,则被执行的次数为m*n次。
范例2
//对1到n的阶乘求和
#include <stdio.h>
int main(void){
int i,j;
int n = 0;
int sum = 0;
int product;
printf("Please input n:");
scanf("%d",&n);
for(i = 1;i<=n;++i){ //外层循环执行加法
for(j = 1,product = 1;j <= i;++j){ // 内层循环执行乘法
product *=j;
}
sum += product;
}
printf("sum = %d\n",sum);
return 0;
}
执行过程:在进行for循环时,首先是进行表达式1的赋值初始化,之后进行表达式2的判断,然后进入循环,执行完后,下一次进行表达式3,然后进入表达式2的判断,再执行。
测试如下
#include <stdio.h>
int main(void){
int i,j;
for(i = 0;i <5 ;++i){
printf("%d",i);
}
return 0;
}
补充一下 i++ 和 ++i 的区别:(1)i++是变量i执行之后实现自增1;(2)++i是变量i先实现自增1之后再执行
举个例子
#include <stdio.h>
int main(void){
int i = 0,j = 0;
int a = 2;
int b = 2;
a += ++i;
printf("%d\n",a);
b += j++;
printf("%d\n",b);
return 0;
}
这里由于++i是在执行前先对i实现了自增,所以在执行时i已经变成了1,所以a=2+1=3;而j++是在执行后才为1,所以在执行时仍然为0,即b = 2+0=2。
在for循环中,++i和i++的效果是一样的,但是要根据具体情况而定到底选择哪个,因为i执行前和执行后的值会根据你的选择不同,但执行时的效果相同。
2. while语句
while语句可以分为while头和while体。其标准形式如下:
while(表达式){
操作;
}
等效于for循环的:
for(;表达式;){
操作;
}
for语句省略了第一个初始化表达式和第三个改变循环变量的表达式以后,是与while等价的。
范例3
#include <stdio.h>
int main(void){
int m = 0;
int n = 0;
int i = n;
int sum = 0;
printf("Please input m and n:");
scanf("%d %d",&m,&n);
while(m > n){
printf("Error: m must be no large than n.\n");
printf("Please input new m and n:");
scanf("%d %d",&m,&n);
}
i = m;
while(i <= n){
sum += i;
++i;
}
printf("Sum = %d\n",sum);
return 0;
}
范例4
//求小于n的最大Fibonacci数
#include <stdio.h>
int main(void){
int n = 0;
int tmp = 0; //类似于一个中间变量
int f1 = 1; //上一个f数
int f2 = 1; //下一个f数
printf("Please input n:");
scanf("%d",&n);
while(f2 < n){
tmp = f2;
f2 = f1 + f2;
f1 = tmp;
}
printf("The maximal fibonacci number less than %d is %d.\n",n,f1);
return 0;
}
范例5
//求两个整数的最大公约数和最小公倍数
#include <stdio.h>
int main(void){
int m,n,r;
int product = 0;
int tmp;
printf("Please input two numbers:\n");
scanf("%d %d",&m,&n);
product = m*n;
if(m < n){
/*交换m和n*/
tmp = m;
m = n;
n = tmp;
}
/*辗转相除法*/
r = m % n;
while(r != 0){
m = n;
n = r;
r = m % n;
}
printf("The maximal common divisor: %d\n",n);
printf("The minimal common multiple: %d\n",product/n);
return 0;
}
3. do - while语句
do-while语句是对跳出循环进行条件判断,先执行循环体,再做条件判断。其标准形式为:
do{
操作;
}while(表达式);
while语句适用于现需要进行条件判断,再执行循环体操作的场景;而do-while语句适用于先执行循环体操作,后进行循环条件判断的场景。
do - while语句可以保证循环体至少被执行一次。
范例6
#include <stdio.h>
int main(void){
int m = 0;
int n = 0;
int i = 0;
int sum = 0;
do{
printf("Please input m and n(m <= n):");
scanf("%d %d",&m,&n);
}while(m > n);//只要不是m <= n就一直循环(m>n就一直循环)
i = m;
do{
sum += i;
++i;
}while(i <= n);
printf("Sum = %d\n",sum);
return 0;
}
范例7
//输入一个大于70的整数
#include <stdio.h>
int main(void){
int n = 0;
do{
printf("Please enter a number (>70)\n");
scanf("%d",&n);
}while(n <= 70);
printf("The number is : %d.",n);
return 0;
}
4. continue和break语句
continue语句是一个控制语句,其功能为结束本次循环,直接开始下一次循环。其标准形式为:
continue;
范例8
//输出ASCII码值为奇数的小写字母
#include <stdio.h>
int main(void){
char ch = '\0';
for(ch = 'a';ch <= 'z'; ++ch){
if(0 == ch % 2)
continue;//退出本次循环
printf("%c ",ch);
}
printf("\n");
return 0;
}
这里的continue语句可以等效为:
for(ch = 'a';ch <= 'z'; ++ch){
if(0 == ch % 2)
;
else
printf("%c",ch);
break语句的功能是终止本层循环。其标准形式为:
break;
范例9
//输出所有小于100的平方数
#include <stdio.h>
int main(void){
int i = 0;
for(i = 1;1;i++){
/*如果i的平方大于100,结束循环*/
if(i * i > 100)
break;
printf("The square of %d: %d\n",i,i*i);
}
return 0;
}
continue语句是退出本次循环:也就是说在循环内部如果执行到continue语句,那么该语句后面的语句都不执行,直接跳进行下次循环(循环不终止,接着执行这个循环体);break语句是终止循环:在循环内部执行到break语句,那么直接跳出这个循环体。
使用break语句只能终止一层循环,若要终止多层循环,必须多次调用break语句。
范例10
//输入3*3的矩阵,并对元素求和
#include <stdio.h>
int main(void){
int i,j;
int data;
int sum = 0;
const int m = 3;//行数
const int n = 3;//列数
printf("Please input a %d*%d matrix:\n",m,n);
for(i = 0;i < m;++i){
for(j = 0;j < n;++j){
printf("matrix[%d][%d](>0) = ",i,j);
scanf("%d",&data);
if(data <= 0){
printf("Error: wrong data !!! Exit inner loop\n");
break;
}
sum += data;
}
if(data <= 0){
printf("Error: wrong data !!! Exit outer loop\n");
break;
}
}
if(i == m && j == n)
printf("The sum of numbers in this matrix is %d.\n",sum);
return 0;
}
5. goto语句
goto语句在C语言中可以实现无条件跳转,但由于goto语句容易破坏程序结构,一般不推荐使用。其基本形式为:
goto 标号名;
其执行逻辑为:当程序执行这一句后,将无条件跳转到标号名所在的位置,然后执行该位置的代码。
范例11
#include<stdio.h>
int main(void){
infinite_loop:
printf("this is an infinite loop!!!!\n");
goto infinite_loop;
return 0;
}
使用goto语句可以瞬间跳出多层循环,效果相当于多个break语句。
在使用结构嵌套时,尽量将选择结构放到循环结构外面,以减少选择条件判断的次数。
范例12
#include <stdio.h>
int main(void){
int i,j;
int length;
printf("Please input length(>0):");
scanf("%d",&length);
for(i=0;i < length;i++){
for(j=0;j<length;j++){
if(0 == i % 2){
printf("=");
}else{
printf("+");
}
}
printf("\n");
}
return 0;
}
练习1
//数列求积:计算从m~n的积
#include <stdio.h>
int main(void){
int m,n;
int pro = 0;
do{
printf("Please enter the number m and n:(m<=n)");
scanf("%d %d",&m,&n);
}while(m > n);
for(pro = 1;m <= n;m++){
pro *= m;
}
printf("pro = %d\n",pro);
return 0;
}
练习2
//打印九九乘法口诀表
#include <stdio.h>
int main(void){
int i,j;
for(i=1;i<=9;i++){//行
for(j=1;j<=i;j++){//列
printf("%d * %d = %d",j,i,i*j);
}
printf("\n");
}
return 0;
}