程序设计基础

第三章 分支结构

第3章 分支结构

3.1 简单的猜数游戏
3.2 四则运算
3.3 查询自动售货机中商品的价格

本章要点

  • 什么是分支结构? 它的作用是什么?
  • switch语句中的break语句的作用是什么?
  • 逻辑运算和关系运算的相同点是什么?它们的不同之处又是什么?
  • 字符型数据在内存中是如何存储的?

3.1 简单的猜数游戏

例3-1. 简单猜数游戏

输入你想猜的整数(假定1~100),与计算机产生的被猜数相比较,若相等,显示猜中;若不等,显示与被猜数的大小关系

3.1.1 程序解析

例3-1. 简单的猜数游戏
输入你想猜的整数yournumber(假定1~100),与计算机产生的被猜数mynumber相比较,若相等,显示猜中;若不等,显示与被猜数的大小关系

yournumber vs mynumber有三种情况:

  • yournumber==mynumber,if(==) ==>Good Guess
  • yournumber>mynumber, else if(>) ==>Too Big!
  • yournumber<mynumber, else ==>Too Small!

猜数游戏源程序

                        
#include<stdio.h>
int main()
{
    int mynumber=38;
    int yournumber;

    printf("Input your number: ");
    scanf("%d", &yournumber);
    if(yournumber==mynumber)
    {
        printf("Good Guess!\n");
    }
    else if(yournumber>mynumber)
    {
        printf("Too Big!\n");
    }
    else
    {
        printf("Too Small!\n");
    }
    return 0;
}
                        
                    

多层缩进的书写格式使程序层次分明

3.1.2 二分支结构和if-else语句

if(表达式)
    语句1
else
    语句2

if(表达式)
    语句1

判断数字的奇偶性

例3-2. 奇偶分家

输入一个正整数n,再输入n个非负整数,统计奇数和偶数各有几个?

分析
判断number的奇偶性:number%2==0

                        
count_odd=0; count_even=0;
for(i=1; i<=n; i++)
{
    //读入一个非负整数number
    if(number能被2整除)    /* 该数为偶数 */
        count_odd++;
    else    /* 该数为奇数 */
        count_even++;
}
                        
                    

奇偶分家源程序

                        
#include<stdio.h>
int main()
{
    int count_odd, count_even, i, n, number;
    count_odd=0; count_even=0;
    printf("Enter n: ");
    scanf("%d", &n);
    printf("Enter %d numbers: ", n);
    for(i=1; i<=n; i++)
    {
        scanf("%d", &number);
        if(number%2==0)
        {
            count_odd++;
        }
        else
        {
            count_even++;
        }
    }
    printf("Odd: %d. Even: %d\n", count_odd, count_even);
    return 0;
}
                        
                    

统计学生的成绩

例3-3. 统计学生的成绩

输入一个正整数n,再输入n个学生的成绩,计算平均分,并统计不及格成绩的个数。

                        
for(i=1; i<=n; i++)
{
    输入1个学生的成绩score
    累加成绩total
    统计不及格成绩的个数count
}
输出成绩
                        
                    

统计学生的成绩源程序

                        
#include<stdio.h>
int main()
{
    int count, i, n;
    double score, total;
    printf("Enter n: ");
    scanf("%d", &n);
    total=0; count=0;
    for(i=1; i<=n; i++)
    {
        printf("Enter score #%d:", i);
        scanf("%lf", &score);
        total=total+score;
        if(score<60)
        {
            count++;
        }/* 这里省略了else */
    }
    if(n!=0)
    {
        printf("Average=%.2f\n", total/n);
    }
    else
    {
        printf("Average=%.2f\n", 0.0);
    }
    printf("Number of failures=%d\n", count);
    return 0;
}
                        
                    

3.1.3 多分支结构和else-if语句

else-if语句是最常用的实现多分支(多路选择)的方法

                        
if(表达式1)
    语句1;
else if(表达式2)
    语句2;
//...
else if(表达式n-1)
    语句n-1;
else
    语句n;
                            
                        

n个分支需要n-1次比较

更改分段计算水费问题

例3-4. 求分段水费

输入用户的月用水量$x$(吨),计算并输出该用户应支付的水费$y$(元)(保留2位小数),其中计算关系修正为下式 $$ y=f(x)=\begin{cases} 0 & x<0\\ \frac{4x}{3} & 0\leq x\leq15\\ 2.5x-10.5 & x> 15 \end{cases} $$

分段计算水费源程序

                        
#include<stdio.h>
int main()
{
    double x, y;
    printf("Enter x:");
    scanf("%lf", &x);
    if(x<0)
    {
        y=0;
    }else if(x<=15)
    {
        y=4*x/3;
    }
    else
    {
        y=2.5x-10.5;
    }
    printf("f(%.2f)=%.2f\n", x, y);
    return 0;
}
                        
                    

3.2 四则运算

例3-5. 求简单的四则运算表达式

输入一个形如“操作数 运算符 操作数”的四则运算表达式,输出运算结果,要求对除数为0的情况作特别处理

3.2.1 程序解析

比如:输入3.1+4.8, 输出=7.9
               输入5.0-3.9, 输出=1.1

value1 op value2  op用于存放一个字符(+-*/等)
if(op=='+')  value1+value2
else if(op=='-')  value1-value2
else if(op=='*')  value1*value2
else if(op=='/')  value1/value2
else "Unknown operator"

四则运算源程序

                        
#include<stdio.h>
int main()
{
    double value1, value2;
    char op;
    printf("Type in an expression:");
    scanf("%lf%c%lf", &value1, &op, &value2);
    if(op=='+')
    {
        printf("=%.2f\n", value1+valuew);
    }
    else if(op=='-')
    {
        printf("=%.2f\n", value1-value2);
    }
    else if(op=='*')
    {
        printf("=%.2f\n", value1*value2);
    }
    else if(op=='/')
    {
        if(value2!=0)
        {
            printf("=%.2f\n", value1/value2);
        }
        else
        {
            printf("Divisor cannot be 0!\n");
        }
    }
    else
    {
        printf("Unknown operator!\n");
    }
    return 0;
}
                        
                    

3.2.2 字符型数据

                        
char op;
scanf("%lf%c%lf", &value1, &op, &value2);
if(op=='+')
{
    //...
}
else if(op=='-')
{
    //...
}
else if(op=='*')
{
    //...
}
else if(op=='/')
{
    //...
}
else
{
    //...
}
                            
                        

字符型数据

  • 字符常量: '+' '-' '*' '/'
  • 字符变量: op

字符常量

字符常量是指单个字符,用一对单引号及其所括起来的字符表示,如'a', 'A', 'z', 'Z', '0', '9', ' ', '\n'等。每个字符均有唯一的编码值,如ASCII字符集,定义了128个基本字符,扩展ASCII字符集定义了256个字符,包括'0'-'9', 'a'-'z', 'A'-'Z'
注意区分数字1和字符'1'

ASCII字符码表

字符变量

                        
char op;  /* 定义字符型变量op, 类型为char, 用于存放字符型数据 */
op='+';

char op1, op2;
op1='A';
op2=op1;
                        
                    

3.2.3 字符型数据的输入和输出

  • 用scanf和printf输入输出字符
  •                         
    double value1, value2;
    char op;
    printf("Type in an expression:");
    scanf("%lf%c%lf", &value1, &op, &value2);
    printf("%.2f%c%.2f\n", value1, op, value2);
                                
                            
  • 用getchar和putchar输入输出一个字符
  •                         
    char ch;
    ch=getchar();
    putchar(ch);
    putchar('-');
                                
                            

输出一批字符

输入8个字符,然后将这些字符输出,输出时在字符之间加一个减号,第一个字符的前面和最后一个字符的后面都没有减号
输入:AMETHYST
输出:A-M-E-T-H-Y-S-T

                        
for(k=1; k<=8; k++)
{
    ch=getchar();
    if(ch是第一个字符)
    {
        putchar(ch);
    }
    else
    {
        putchar('-');
        putchar(ch);
    }
}
                        
                    

输出一批字符源程序

                        
#include<stdio.h>
int main()
{
    char ch;
    int first=1, k;  /* first为1表示将要处理第1个字符 */
    printf("Enter 8 characters:");
    for(k=1; k<=8; k++)
    {
        ch=getchar();
        if(first==1)
        {
            putchar(ch);
            first=0;  /* first为0表示将要处理第2个及以后的字符 */
        }
        else
        {
            putchar('-');
            putchar(ch);
        }
    }
    return 0;
}
                        
                    

3.2.4 逻辑运算

-1<=x<=1

x>=-1 并且 x <=1
x>=-1 && x<=1

判断一个字符是否是英文字符

                        
#include<stdio.h>
int main()
{
    char ch;
    printf("Enter a character:");
    ch=getchar(); // scanf("%c", &ch);
    if((ch>='a' && ch<='z') || (ch>='A' && ch<='Z'))
    {
        printf("%c is a letter.\n", ch); //putchar(ch);
    }
    else
    {
        printf("%c is not a letter.\n", ch); //putchar(ch);
    }
}
                        
                    

三种逻辑运算

逻辑与&&
逻辑或||
逻辑非!

三种逻辑运算符的含义

逻辑与&&
逻辑或||
逻辑非!

三种逻辑运算符的功能

a b 逻辑与
a&&b
逻辑或
a||b
逻辑非
!a
true true true true false
true false false true false
false true false true true
false false false false true

逻辑表达式

逻辑表达式
用逻辑运算符将逻辑运算对象连接起来的式子

ch>='a' && ch<='z'==> 判断ch是否为小写字母
(ch>='a' && ch<='z') || (ch>='A' && ch<='Z')==>判断ch是否为英文字母,区分大小写

条件的表示

例3-6. 写出满足下列条件的C表达式

  • ch是空格或者回车
    ch==' ' || ch=='\n'
  • ch是数字字符
    ch>='0' && ch<='9'
  • year是闰年,即year能被4整除但不能被100整除,或者year能被400整除
    (year%4==0 && year%100!=0) || (year%400==0)

分类统计字符

例3-7. 输入n个字符,统计其中英文字母、数字字符和其它字符的个数

                        
for(i=1; i<=n; i++)
{
    输入1个字符ch;
    if(ch是英文字母)
        letter++;
    else if(ch是数字字符)
        digit++;
    else
        other++;
}
输出分类统计结果
                        
                    

分类统计字符源程序

                        
#include<stdio.h>
int main()
{
    int digit, i, letter, n, other;
    char ch;
    digit=letter=other=0;
    printf("Enter n:");
    scanf("%d", &n);
    getchar();
    printf("Enter %d characters:", n);
    for(i=1; i<=n; i++)
    {
        ch=getchar();
        if((ch>='a' && ch<='z') || (ch>='A' && ch<='Z'))
            letter++;
        else if(ch>='0' && ch<='9')
            digit++;
        else
            other++;
    }
    printf("letter=%d, digit=%d, other=%d\n", letter, digit, other);
    return 0;
}
                        
                    

3.3 查询自动售货机中商品的价格

例3-8. 查询自动售货机中商品的价格

假设自动售货机出售4种商品:薯片(crisps)、爆米花(popcorn)、巧克力(chocolate)和可乐(cola),售价分别是每份3.0、2.5、4.0和3.5元。在屏幕上显示以下菜单(编号和选项),用户可以连续查询商品的价格,当查询次数超过5次时,自动退出查询;不到5次时,用户可以选择退出。当用户输入编号1~4,显示相应商品的价格(保留1位小数);输入0,退出查询(输入其它编号,显示价格为0)。
(1) Select crisps
(2) Select popcorn
(3) Select cola
(4) Select chocolate
(0) Exit

3.3.1 程序解析

菜单显示控制

                        
显示菜单
for(i=1; i<=5; i++)
{
    输入选项choice
    if(choice==0)
        退出循环
    若choice的值
        ==1~4 -->price赋单价
        ==其它 -->price赋0
    输出单价price
}
                        
                    

售货机源程序

                        
#include<stdio.h>
int main()
{
    int choice, i;
    double price;
    printf("[1] Select crisps\n");
    printf("[2] Select popcorn\n");
    printf("[3] Select chocolate\n");
    printf("[4] Select cola\n");
    printf("[0] Exit\n");

    for(i=1; i<=5; i++)
    {
        printf("Enter choice:");
        scanf("%d", &choice);
        if(choice==0)
            break;
        switch(choice)
        {
            case 1: price=3.0; break;
            case 2: price=2.5; break;
            case 3: price=4.0; break;
            case 4: price=3.5; break;
            default: price=0.0; break;
        }
        printf("price=%0.1f\n", price);
    }
    printf("Thanks\n");
    return 0;
}
                        
                    

3.3.2 Switch语句

switch用于处理多分支选择问题,面对不同情况有不同的使用方法

case 1.在switch语句的每个语句段中都使用break语句

                        
switch(表达式)
{
    case 常量表达式1:
        语句段1;
        break;
    case 常量表达式2:
        语句段2;
        break;
    ...
    case 常量表达式n:
        语句段n;
        break;
    default:
        语句段n+1;
        break;
}
                        
                    

switch语句-case 1

常量表达式的值不重复

两个数的简单计算器

例3-9. 编写一个简单的计算器程序,可根据输入的运算符,对两个整数进行加、减、乘、除和求余运算,请对除数为0的情况作特别处理。要求使用switch语句编写

                        
//value1 op value2
switch(op)
{
    case '+':
        value1+value2
    case '-':
        value1-value2
    case '*':
        value1*value2
    case '/':
        value1/value2
    default:
        "Unknown operator"
}

                        
                    

两个数的简单计算器源程序

                        
#include<stdio.h>
int main()
{
    int value1, value2;
    char op;
    printf("Type in an expression:");
    scanf("%d%c%d", &value1, &op, &value2);
    switch(op)
    {
        case '+':
            printf("=%d\n", value1+value2);
            break;
        case '-':
            printf("=%d\n", value1-value2);
            break;
        case '*':
            printf("=%d\n", value1*value2);
            break;
        case '/':
            if(value2!=0)
                printf("=%d\n", value1/value2);
            else
                printf("divisor cannot be 0!\n");
            break;
        default:
            printf("Unknown operator!\n");
            break;
    }
    return 0;
}
                        
                    

Switch语句

case 2.在switch语句中不使用break;

                        
switch(表达式)
{
    case 常量表达式1:
        语句段1;
    case 常量表达式2:
        语句段2;
    ......
    case 常量表达式n:
        语句段n;
    default:
        语句段n+1;
}
                        
                    
                        
switch(choice){
    case 1: price=3.0;
    case 2: price=2.5;
    case 3: price=4.0;
    case 4: price=3.5;
    default: price=0.0;
}
                            
                        

price=?

switch语句-case 2

Switch语句

case 3.在switch的某些语句段中使用break;

例3-10. 输入n个字符,分别统计出其中空格或回车、数字字符和其它字符的个数

比较: 例3-7. 输入n个字符,统计其中英文字母、数字字符和其它字符的个数

统计字符源程序

                        
#include<stdio.h>
int main()
{
    int blank, digit, other, i, n;
    char ch;
    blank=digit=other=0;
    printf("Enter n:");
    scanf("%d", &n);
    getchar();
    printf("Enter %d characters:", n);
    for(i=1; i<=n; i++)
    {
        ch=getchar();
        switch(ch)
        {
            case ' ': case'\n':
                blank++;
                braek;
            case '0': case '1': case '2': case '3': case '4':
            case '5': case '6': case '7': case '8': case '9':
                digit++;
                break;
            default:
                other++;
                break;
        }
    }
    printf("blank=%d, digit=%d, other=%d", blank, digit, other);
    return 0;
}
                        
                    

3.3.3 多分支结构

  • 分支结构一般分为二分支和多分支两种结构
  • 二分支结构用基本的if语句实现
  • 多分支结构实现方法
    • else-if语句
    • switch语句
    • 嵌套的if-else语句

嵌套的if-else语句

嵌套的if-else语句

嵌套的if-else语句即指if-else条件中的语句也能是if-else语句

                        
if(表达式1)
    if(表达式2) 语句1
    else 语句2
else
    if(表达式3) 语句3
    else 语句4
                        
                    

else和if的匹配

else与最靠近它的、没有与别的else匹配过的if匹配

                        
if(表达式1)
    if(表达式2) 语句1
    else 语句2
else
    if(表达式3) 语句3
    else 语句4
                            
                        
                        
if(表达式1)
    if(表达式2) 语句1
else
    if(表达式3) 语句3
    else 语句4
                            
                        

上段代码变为

                        
if(表达式1)
    if(表达式2) 语句1
    else
        if(表达式3) 语句3
        else 语句4
                            
                        

改变else和if的配对

例3-11.改写下列if语句,使else和第1个if配对

                        
if(x<2)
    if(x<1)
        y=x+1;
    else
        y=x+2;
                        
                    

思考每条语句的执行条件分别是什么?

                        
if(x<2)
{
    if(x<1)
        y=x+1;
}
else
    y=x+2;
                            
                        
                        
if(x<2)
    if(x<1)
        y=x+1;
    else;
else
    y=x+2;