一、C语言的基本逻辑结构
C语言程序有3种基本结构:顺序结构、选择结构和循环结构
1)顺序结构:所谓顺序结构,就是从上到下的所有语句都会依次执行
2)选择结构:选择结构中存在一条(或多条)分支语句,当满足分支的条件时语句才会执行,否则不会执行
3)循环结构:循环结构即是在某些条件的控制下重复执行一段代码语句,当满足循环条件时执行循环语句,否则不执行循环语句。
二、选择结构:if-else结构
1、if-else结构使用
if(表达式)-else是最常见的2分支判断选择结构,常见的if()-else有3种形式:
⒈if(表达式)
{
    语句块
    ……
}
⒉if(表达式)
{
    语句块1
    ……
}
else
{
    语句块2
    ……
}
⒊if(表达式1)
{
    语句块1
    ……
}
else if(表达式2)
{
    语句块2
    ……
}
....
else 
{
    语句块n
}
……
1)if(表达式)
用法:
if(表达式)
{
    语句块;
    ……
}
说明:
当程序执行到if语句时,会判断if()内表达式的真假,若为真,则会执行语句块,否则跳过语句块
示例:

int main()
 {
     int a = 5;
     if(a>0)
     {
         printf("a大于0\n");//满足if条件,这条语句会执行
     }
     a = -5;
     if(a>0)
     {
         printf("a大于0\n");//不满足if条件,这条语句不会执行
     }
     return 0;
 }

执行结果:输出一条"a大于0"
2)if(表达式)-else
用法:
if(表达式)
{
    语句块1;
    ……
}
else
{
    语句块2;
    ……
}
说明:
当程序执行到if语句时,会判断if()内表达式的真假,若为真,则会执行if下语句块1;若为假,则会执行else下语句块2
示例:

int main()
 {
     int a = 5;
     if(a>0)
     {
         printf("a大于0\n");
     }
     else
     {
         printf("a小于0\n");
     }
     a = -5;
     if(a>0)
     {
         printf("a大于0\n");
     }
     else
     {
         printf("a小于0\n");
     }
     return 0;
 }


3)多个if(表达式)-else
用法:
if(表达式1)
{
    语句块1
    ……
}
else if(表达式2)
{
    语句块2
    ……
}
……//可使用多个
else//最后一个以else结尾
{
    语句块3
    ……
}
说明:当程序执行到if(表达式1)时,会判断表达式1的真/假。当表达式1为真时,执行语句块1;
否则,执行if(表达式2),会判断表达式2的真/假
依次进行每个if(表达式)的判断
如果以上if(表达式)都为假,则执行最后的else语句后的语句块3
实际上多个if()-else表达式就是使用多个2分分支判断实现了多重分支判断
示例:
程序输入成绩,为0~100之间的整数。之后输出成绩代表的分数段:
90~100为优,80~89为良,70~79为中,60~69为及格,0~59为不及格,其他则输出错误信息

#include<stdio.h>
 #include<stdlib.h>
 int main()
 {
     int score;
     printf("请输入学生成绩:");
     scanf("%d",&score);
     if(score<=100 && score>=90)
     {
         printf("成绩为优\n");
     }
     else if(score<90 && score>=80)
     {
         printf("成绩为良\n");
     }
     else if(score<80 && score>=70)
     {
         printf("成绩为中\n");
     }
     else if(score<70 && score>=60)
     {
         printf("成绩为及格\n");
     }
     else if(score<60 && score>=0)
     {
         printf("成绩为不及格\n");
     }
     else
     {
         printf("输入非法数据\n");
     }
     return 0;
 }


4)如果if()或者else表达式下未使用{}限制,则只会执行if()或else下的第一条语句。
示例:

#include<stdio.h>
 int main()
 {
     int a = 5;
     if(a>0)
         printf("a是正数\n");
     else
         a = -3;
         printf("a不是正数\n");
     printf("a is %d\n",a);
     return 0;
 }


程序输出结果:
a是正数
a不是正数
a is 5
尽管在本例中,else下的两句表达式缩进相同(以代表两句都隶属于else语句块)但是由于else后没有{},因此实际上隶属于else的语句只有第一句(即a=-3,如果能执行的话),而printf()语句则会照常执行。因此我们建议使用{}将if()和else后的语句都括起来,以免出现逻辑错误
上面输入成绩输出分数段的示例等价于:

#include<stdio.h>
 int main()
 {
     int score;
     printf("请输入学生成绩:");
     scanf("%d",&score);
     if(score<=100 && score>=90)
         printf("成绩为优\n");
     else if(score<90 && score>=80)
         printf("成绩为良\n");
     else if(score<80 && score>=70)
         printf("成绩为中\n");
     else if(score<70 && score>=60)
         printf("成绩为及格\n");
     else if(score<60 && score>=0)
         printf("成绩为不及格\n");
     else
         printf("输入非法数据\n");
     return 0;
 }


练习1:输入3个整数,从小到大输出
答案:

int main()
 {
     int a,b,c,tmp;//tmp用于交换值的中间变量
     scanf("%d %d %d",&a,&b,&c);
     if(a>b && a>c)//此时a是最大值
     {
         tmp = a;
         a = c;
         c = tmp;
     }
     else if(b>c && b>a)//此时b是最大值
     {
         tmp = b;
         b = c;
         c = tmp;
     }
     //程序执行到这,c中存的是3个数中最大值,剩下a,b两个数待比较
     if(a>b)
     {
         tmp = a;
         a = b;
         b = tmp;
     }
     printf("%d %d %d\n",a,b,c);
     return 0;
 }


练习2:输入3个正整数作为3条线段的长度,判断这3条线段能否构成三角形。构成三角形的条件是:任意两边之和大于第三边
答案:

#include<stdio.h>
 int main()
 {
     int bian1,bian2,bian3;
     int flag=0;//用于标识状态
     //flag状态:0能构成三角形、1输入非法数据、2不能构成三角形
     printf("请输入三角形的3条边:\n");
     scanf("%d%d%d",&bian1,&bian2,&bian3);
     if(bian1<=0 || bian2<=0 || bian3<=0)
         flag=1;
     else if(bian1+bian2<=bian3 || bian1+bian3<=bian2 || bian2+bian3<=bian1)
         flag=2;
     //程序执行到这里,flag获得状态
     if(flag==0)
         printf("三条边能构成三角形\n");
     else if(flag==1)
         printf("输入数据错误\n");
     else if(flag==2)
         printf("三条边不能构成三角形\n");
     return 0;
 }


2、if()的嵌套使用
在if()-else语句中又包含一个或多个if()-else语句称为if()的嵌套使用。一般形式如下:
if(表达式1)
{
    if(表达式2)
    {
        语句块1
        ……
    }
    else
    {
        语句块2
        ……
    }
}
else
{
    if(表达式3)
    {
        语句块3
        ……
    }
    else
    {
        语句块4
        ……
    }
}
程序的执行逻辑:
表达式1为真:
    表达式2为真:
        执行语句块1
    否则:
        执行语句块2
否则:
    表达式3为真:
        执行语句块3
    否则
        执行语句块4
示例:输入一个整数,判断这个整数是正整数、0还是负整数
1)使用多个if()-else

int main()
 {
     int input;
     scanf("%d",&input);
     if(input>0)
         printf("输入的是正整数\n");
     else if(input==0)
         printf("输入的是0\n");
     else
         printf("输入的是负整数\n");
     return 0;
 }


2)使用if()嵌套

int main()
 {
     int input;
     scanf("%d",input);
     if(input>0)
         printf("输入的是正整数\n");
     else
     {
         if(input==0)
             printf("输入的是0\n");
         else
             printf("输入的是负整数\n");
     }
     return 0;
 }


练习:输入一个年份(正整数),判断这年是否是闰年
闰年判断标准:年份能被4整除;如若遇到100的倍数,则需判断年份能否被400整除。(逢4一闰,逢百不闰,逢400又闰)
如1900年不是闰年,1904年是闰年,2000年是闰年
答案:

int main()
 {
     int input;
     scanf("%d",&input);
     if(input%4==0)
     {
         if(input%100!=0)
         {
             printf("%d是闰年\n",input);
         }
         else if(input%400==0)
         {
             printf("%d是闰年\n",input);
         }
         else
         {
             printf("%d不是闰年\n",input);
         }
     }
     else
     {
         printf("%d不是闰年\n",input);
     }
     return 0;
 }


3、if()和else的配对
(当没有{}限定的时候)当else与if配对的时候,else总是与它上面最近的未配对的if()结合
if()
    if()语句1
else 语句2
    if()语句3
else 语句4
在这段程序中,虽然编程人员将else 语句2放在与第一个if()同一缩进上以表示该else与首个if()结合,但实际上这个else是与它的上一个if(即if()语句1)结合。因此在使用if()-else语句(尤其在嵌套使用时)一定要使用{}来限定

三、选择结构:switch-case结构
if()-else语句只能判断2个分支,若要判断多个分支则需要if()-else的多次使用或嵌套使用,十分不便
switch()语句是多分支选择语句。通过switch()的多分支判断可以简便地实现多分支选择结构
switch()语句的一般形式如下:
switch(表达式)
{
    case 常量1:
    语句1;
    break;
    case 常量2:
    语句2;
    break;
    ……//多个case结构
    case 常量n:
    语句n;
    break;
    default:
    语句n+1;
}
说明:
1)switch(表达式)表达式的值应是一个整数(包括字符数据)
2)switch()下的{}是一段语句块,这段语句包含若干个以case开头的语句块和至多一个以default开头的语句块
3)case后需要一个常量(或常量表达式),case和default都是标号作用。首先判断switch(表达式)的表达式的值,之后与各个case之后的值进行比对,如果某个case后的值与表达式的值相同,则跳转到此case语句;如果所有的case都不匹配,则跳转到default后的语句
4)可以没有default语句。若没有default语句,则如果没有匹配的case,则程序不执行任何语句
5)各个case之间的先后顺序以及default的位置不影响程序执行结果,不过我们强烈推荐按一定顺序排列case语句,default语句放在最后
6)每个case语句后的常量值必须各不相同,否则会发生互相矛盾现象
7)break语句用来终止switch()语句。如果case语句后没有break语句,则当匹配到合适的case后,程序会一直执行接下来的语句直至遇到break或switch()结束
示例:使用switch()实现:输入一个正整数,输出对应的星期。如输入1代表星期一,输入2代表星期二……输入7代表星期日。输入其他数输出错误信息

#include<stdio.h>
 int main()
 {
     int input;
     scanf("%d",&input);
     switch(input)
     {
         case 1:
         printf("今天是星期一\n");
         break;
         case 2:
         printf("今天是星期二\n");
         break;
         case 3:
         printf("今天是星期三\n");
         break;
         case 4:
         printf("今天是星期四\n");
         break;
         case 5:
         printf("今天是星期五\n");
         break;
         case 6:
         printf("今天是星期六\n");
         break;
         case 7:
         printf("今天是星期日\n");
         break;
         default:
         printf("输入错误\n");
     }
     return 0;
 }


在示例中,如果去掉所有的break语句,则:

#include<stdio.h>
 int main()
 {
     int input;
     scanf("%d",&input);
     switch(input)
     {
         case 1:
         printf("今天是星期一\n");        case 2:
         printf("今天是星期二\n");        case 3:
         printf("今天是星期三\n");        case 4:
         printf("今天是星期四\n");        case 5:
         printf("今天是星期五\n");        case 6:
         printf("今天是星期六\n");        case 7:
         printf("今天是星期日\n");        default:
         printf("输入错误\n");
     }
     return 0;
 }


程序执行结果:
输入4,输出:今天是星期四  今天是星期五  今天是星期六  今天是星期日  输入错误
练习1:将上文的“输入学生成绩,输出优、良、中、及格、不及格”问题使用switch()语句来实现
答案:

int main()
 {
     int input;
     printf("请输入学生成绩:");
     scanf("%d",&input);
     if(input>100 || input<0)
         printf("输入数据错误!\n");
     else
         input /= 10;
     switch(input)
     {
         case 10:
         case 9:
         printf("成绩为优\n");
         break;
         case 8:
         printf("成绩为良\n");
         break;
         case 7:
         printf("成绩为中\n");
         break;
         case 6:
         printf("成绩为及格\n");
         break;
         case 5:
         case 4:
         case 3:
         case 2:
         case 1:
         case 0:
         printf("成绩为不及格\n");
         break;
         default:
         printf("输入非法数据\n");
     }
     return 0;
 }


注意在case 10处,以及case 5~case 0处均没有break,则匹配到这些case后会顺序执行之后的语句直至出现break或switch()语句结束
练习2:运输公司对用户按路程计算费用。路程越远,每吨*千米运费折扣越高。计算运费公式如下:
freight = weight * distance * price * (1-discount);
路程与折扣的关系如下:
s<250:无折扣
250<=s<500:2%折扣
500<=s<1000:5%折扣
1000<=s<2000:8%折扣
2000<=s<3000:10%折扣
3000<=s:15%折扣
要求从键盘输入货运总重(单位吨)、货运路程(单位千米)、每吨*千米货运单价(单位元),输出总花费
答案:

#include<stdio.h>
 int main()
 {
     int distance,c;
     float price,weight,discount,freight;
     printf("请输入货运总重量:");
     scanf("%f",&weight);
     printf("请输入货运路程:");
     scanf("%d",&distance);
     printf("请输入单价:");
     scanf("%f",&price);
     if(distance>=3000)
         c=12;
     else
         c=distance/250;
     switch (c)
     {
         case 0:
         discount=0;break;
         case 1:
         discount=2;break;
         case 2:
         case 3:
         discount=5;break;
         case 4:
         case 5:
         case 6:
         case 7:
         discount=8;break;
         case 8:
         case 9:
         case 10:
         case 11:
         discount=10;break;
         case 12:
         discount=15;break;
     }
     freight = price * distance *weight * (1-discount/100);
     printf("总运费是%f\n",freight);
     return 0;
 }