程序设计基础

第二章 用C语言编写程序

第2章 用C语言编写程序

2.1 在屏幕上显示Hello World!
2.2 求华氏温度100°F对应的摄氏温度
2.3 计算分段函数
2.4 输出华氏--摄氏温度转换表
2.5 生成乘方表与阶乘表

本章要点

  • 怎样编写程序,在屏幕上显示一些信息?
  • 怎样编写程序,实现简单的数据处理,例如将华氏温度转换为摄氏温度?
  • 怎样使用if语句计算分段函数?
  • 怎样用for语句求1+2+...+100?
  • 如何定义和调用函数生成一张乘方表?

2.1 在屏幕上显示Hello World!

                            

例2-1. 在屏幕上显示一个短句:

Hello World!

在屏幕上显示Hello World!


/* 显示Hello World! */
#include<stdio.h>
int main()                /* 主函数 */
{
    printf("Hello World!\n"); /* printf--输出函数, \n--换行符, ;--语句结束 */
    return 0;
}
                        
  1. 任何程序都有主函数
  2. 程序由若干语句组成
  3. 语句由;结束

在屏幕上显示一些信息

                            

例2-2. 在屏幕上显示一个短句:
Programming is fun!
And Programming in C is even more fun!


#include<stdio.h>                /* 编译预处理命令 */
int main()
{
    printf("Programming is fun!\n");
    printf("And Programming in C is even more fun!\n");

    return 0;
}
                        

思考:可以用一条语句完成吗? 能否打印一个简单图案?

2.2 求华氏温度100°F对应的摄氏温度

从华氏温度转换到摄氏温度: $C=\frac{5*(F-32)}{9}$

2.2.1 程序解析

                            

例2-3. 求华氏温度100°F对应的摄氏温度
摄氏温度 C=5*(F-32)/9
输出: fahr=100, celsius=37


#include<stdio.h>
int main()
{
    int celsius, fahr;             /* 变量定义 */
    fahr=100;
    celsius=5*(fahr-32)/9;         /* 变量使用 */
    printf("fahr=%d,celsius=%d\n", fahr, celsius);    /* 输出结果 */
    return 0;
}
                        

2.2.2 常量、变量和数据类型


int celsius, fahr;
celsius=5*(fahr-32)/9;
                        
  • 数据
    • 常量:在程序运行过程中,其值不能被改变
    • 变量:在程序运行过程中,其值可以被改变
  • 数据类型
    • 常量:5和9是整型常量(整数)
    • 变量:在定义时指定

变量的定义

变量定义的一般形式是:

类型名 变量名;


变量名的定义一般用小写字母,做到见名知义


int celsius, fahr; //定义整型变量
float x; //定义单精度浮点型变量
double area, height; //定义双精度浮点型变量
                        

double型数据精度比float型高,取值范围更大

变量的定义

  • 定义变量时要指定变量名数据类型
  • 变量名代表内存中的一个存储单元,用于存放该变量的值
  • 存储单元的大小由变量的数据类型决定
  • C语言中的变量代表保存数据的存储单元
  • 数学中的变量代表未知数,如$x=x+1$

变量的定义与使用

  • 变量必须先定义(赋值),后使用
  • 一个变量名只能定义一次
  • 一般都定义在程序的头上
  • 不能定义在程序的中间或后面

#include<stdio.h>
int main()
{
    int celsius, fahr;

    fahr=100; //变量先赋值
    celsius=5*(fahr-32)*9; //变量后引用
    printf("fahr=%d,celsius=%d\n",fahr,celsius);

    return 0;
}
                        

2.2.3 算术运算和赋值运算


fahr=100;
celsius=5*(fahr-32)/9;
                        
  • 算术运算
    • 双目算术运算符: + - * / %
    • 算术表达式:用算术运算符运算对象连接起来的符合C语言语法规则的式子

思考:

数学式:5(f-32)/9 --> C语言表达式:5*(f-32)/9 或者 (f-32)*5/9

数学式:s(s-a)(s-b)(s-c) --> C语言表达式:s*(s-a)*(s-b)*(s-c)

算术运算

双目运算符两侧操作数的类型要相同

  • "/"表示整数除整数,得到结果为整数
    1/2=0, 9/4=2
    5*(f-32)/9和5/9*(f-32)等价吗?
  • "%"针对整型数据
    5%6=5, 9%4=1, 100%4=0

赋值运算

  • 赋值运算符 =
  • 赋值表达式:用 = 将一个变量和一个表达式连接起来的式子
    变量 = 表达式
    要注意,= 的左边必须是一个变量,如
  • 
    fahr=100;
    celsius=5*(fahr-32)/9
                                
    • 计算赋值运算符右侧表达式的值
    • 将赋值运算符右侧表达式的值赋给左侧的变量

2.2.4 格式化输出函数printf()

数据输出:用格式化输出函数printf()
printf(格式控制字符串, 输出参数1, ..., 输出参数n);
格式控制字符串: 用双引号括起来,表示输出的格式
输出参数1...n: 要输出的数据


printf("Hello World!\n");
printf("fahr=%d, celsius=%d\n", fahr, celsius);
                        
  • 普通字符,按原样输出
  • 格式控制说明,按指定格式输出数据,%d为int型,%f为float和double型,如第2行输出为
  • fahr=100, celsius=37

2.3 计算分段函数

例2-4. 求分段水费

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

2.3.1 程序解析

例2-4. 求分段水费

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

要解决的问题:

  • 输入
  • 计算分段函数
  • 输出,并保留2位小数

2.3.1 程序解析


#include<stdio.h>
int main()
{
    double x,y;
    printf("Enter x(x>=0):\n");        /* 输入提示 */
    scanf("%lf", &x);                  /* 调用scanf函数输入数据 */
    if(x<=15)                          /* if-else语句 */
    {
        y=4*x/3;
    }
    else
    {
        y=2.5*x-10.5;
    }
    printf("f(%f)=%.2f\n", x, y);

    return 0;
}
                            
                        

Enter x(x>=0):
9.5
f(9.500000)=12.67

Enter x(x>=0):
15
f(15.000000)=20.00

Enter x(x>=0):
21.3
f(21.300000)=42.75

2.3.2 关系运算

x<=15 比较x和15的大小,比较结果为

当x取值为9.5时,x <=15的结果是:真
当x取值为21.3时,x<=15的结果是:假

关系运算,比较运算,用于比较两个操作数

  • 关系运算符
  • x<y   x <=y   x==y
    x>y   x>=y   x!=y

    注意区分=和==

  • 关系表达式,用关系运算符将2个表达式连接起来的式子,如x<=1

运用关系表达式

表示比较的数学式 C关系表达式
$x\leq 10$ x<=10< /td>
$x\geq 10$ x>=10
$x\neq 10$ x!=10
$x=10$ x==10

用关系表达式描述条件

  • 判断x是否为负数: x<0
  • 判断x是否不为零: x!=0

2.3.3 if-else语句

                                
if(表达式)
    语句1
else
    语句2
                                
                            
                                
if(x<=15){
    y=4*x/3;
}else{
    y=2.5*x-10.5;
}
                                
                            

计算二分段函数

函数定义为 $$ f(x)=\begin{cases} \frac{1}{x} & x\neq 0\\ 0 & x=0 \end{cases} $$

                            
if(x!=0){
    y=1/x;
}else{
    y=0;
}
                            
                        

计算二分段函数完整源代码

                            
#include<stdio.h>
int main()
{
    double x, y;

    printf("Enter x:\n");
    scanf("%lf", &x);
    if(x!=0)
    {
        y=1/x;
    }
    else
    {
        y=0;
    }
    printf("f(%.2f)=%.1f\n", x, y);

    return 0;
}
                            
                        

input x:
2.5
f(2.50)=0.4

input x:
0
f(0.00)=0.0;

软件测试的基本思想

软件测试
精心设计一批测试用例[输入数据,预期输出结果],然后分别用这些测试用例运行程序,看程序的实际运行结果与预期输出结果是否一致。

计算阶梯水费 计算二分段函数

2.3.4 格式化输入函数scanf()

数据输入:格式化输入函数scanf()
scanf("%lf", &x);
printf( 格式控制字符串, 输入参数1, ..., 输入参数n );
格式控制字符串: 用双引号括起来,表示输入的格式
输入参数1...n: 变量的地址


scanf("%lf", &x);
scanf("x=%lf", &x);
                        
  • 普通字符,按原样输入,尽量不要出现普通字符
  • 格式控制说明,按指定格式输入数据,%d为int型,%f为float型,%lf为double型
  • 第1行,输入为9.5
    第2行,输入为x=9.5

改进例2-3的程序

例2-3. 求华氏温度100°F对应的摄氏温度
摄氏温度 C=5*(F-32)/9
输出: fahr=100, celsius=37


#include<stdio.h>
ing main()
{
    int celsius, fahr;
    printf("Enter fahr:\n");
    scanf("%d", &fahr);
    celsius=5*(fahr-32)/9;
    printf("fahr=%d, celsius=%d\n", fahr, celsius);

    return 0;
}
                        

2.3.5 常用数学库函数

  • 库函数
    • C语言处理系统提供事先编好的函数,供用户在编程时调用,如scanf(), printf(), exp()等
    • 在相应的系统文件(头文件)中定义一些必需的信息
  • #include命令
    • 用户在调用库函数时,需将相应的头文件包含到源程序中,如
    • 调用scanf, printf时,需要#include<stdio.h>
    • 调用sqrt,需要#include<math.h>

常用数学库函数

  • 平方根函数 sqrt(x)
  • 绝对值函数 fabs(x),如fabs(-3.56)的值为3.56
  • 幂函数pow(x,n),即$x^n$,pow(1.1, 2)的值为1.21
  • 指数函数exp(x),即$e^x$,exp(2.3)的值为$e^{2.3}$
  • 以$e$为底的对数函数log(x),即$ln(x)$,log(123.45)的值为4.815836
  • 以10为底的对数函数log10(x),即$log_{10}(x)$,log10(123.45)的值为2.091491

坚持的力量

例2-4. 以第一天的能力值为基数,用initial表示,能力值相比前一天最高的值factor就是努力参数,坚持天数为day,让我们一起来看看坚持的力量。
输入能力的初始值initial、努力参数factor和坚持天数day,根据下列公式计算出坚持努力后达到的能力值,输出时保留两位小数

$$ result=initial(1+factor)^{day} $$

例2-4源代码

                            
#include<stdio.h>
#include<math.h>
int main()
{
    int day;
    double factor, initial, result;

    printf("Enter initial: ");
    scanf("%lf", &initial);
    printf("Enter factor: ");
    scanf("%lf", &factor);
    printf("Enter day: ");
    scanf("%d", &day);

    result=initial*pow(1+factor, day);
    printf("result=%.2f\n", result);
    return 0;
}
                            
                        

用scanf函数输入多个数据

scanf("%lf %lf %d", &initial, &factor, &day);
输入: 1 0.01 365
输出: 37.78

  • scanf需要多个输入参数和多个格式控制说明,输入参数的类型、个数和位置要与格式控制说明一一对应
    如scanf("%lf %d %lf", &initial, &day, &factor);
  • 程序运行时,输入的多个数据之间必须有间隔
    scanf("%lf %d %lf", &initial, &day, &factor)该如何输入?

计算存款本息

输入存款金额mone、存期year和年利率rate,根据公式计算存款到期时的本息合计sum(税前),输出时保留两位小数

$$ sum=money(1+rate)^{year} $$

                            
#include<stdio.h>
#include<stdio.h>
int main()
{
    int money, year;
    double rate, sum;

    printf("Enter money, year, rate: ");
    scanf("%d %d %lf", &money, &year, &rate);
    sum=money*pow((1+rate), year);
    printf("sum=%.2f\n", sum);
    return 0;
}
                            
                        

2.4 输出华氏--摄氏温度转换表

例2-6. 输入2个整数lower和upper,输出一张华氏--摄氏温度转换表,华氏温度的取值范围是[lower, upper],每次增加1°

2.4.1程序解析

                            
#include<stdio.h>
int main()
{
    int fahr, lower, upper;
    double celsius;
    printf("Enter lower: ");
    scanf("%d", &lower);
    printf("Enter upper: ");
    scanf("%d", &upper);
    if(lower<=upper)
    {
        printf("fahr celsius\n");
        for(fahr=lower; fahr<=upper; fahr++)
        {
            celsius=(5.0/9.0)*(fahr-32);
            printf("%4d%6.1f\n",  fahr, celsius);
        }
    }
    else
    {
        printf("Invalid value\n");
    }
    return 0;
}
                            
                        

例2-6中的for语句流程

                        
for(fahr=lower; fahr<=upper; fahr++)
{
    celsius=(5.0/9.0)*(fahr-32);
    printf("%4d%6.1f\n",  fahr, celsius);
}
                            
                        

Enter lower: 30
Enter upper: 35
fahr  celsius
30      -1.1
31      -0.6
32       0.0
33       0.6
34       1.1
35       1.7

2.4.2 for语句--循环语句

for(表达式1;表达式2;表达式3)
  循环体语句

实现C语句的重复执行
3个表达式、循环体语句
!书写顺序和执行顺序不同
!表达式1只执行一次

for语句说明

循环(控制)变量: for语句中,通过改变或判断某个变量的值来控制循环的执行

                            
for(fahr=lower; fahr<=upper; fahr++)
{
    celsius=(5.0/9.0)*(fahr-32);
    printf("%4d%6.1f\n",  fahr, celsius);
}
                            
                        
  • 表达式1: 给循环变量赋初值,指定循环的起点,fahr=lower;
  • 表达式2: 给出循环的条件,判断循环是否达到终点,fahr<=upper;
  • 表达式3: 设置循环的步长,改变循环变量的值,从而可改变表达式2的真假性,fahr++;
  • 循环体语句: 被反复执行的语句,一条或多条语句

复合语句{}和空语句

                            
/* 代码1 */
for(fahr=lower; fahr<=upper; fahr++)
    celsius=(5.0/9.0)*(fahr-32);
    printf("%4d%6.1f\n",  fahr, celsius);
                            
                        
                            
/* 代码2 */
for(fahr=lower; fahr<=upper; fahr++);
    celsius=(5.0/9.0)*(fahr-32);
    printf("%4d%6.1f\n",  fahr, celsius);
                            
                        

思考:以上两段代码的执行结果如何? 为什么?

2.4.3 指定次数的循环程序设计

例2-7. 输入一个正整数,求$\sum_{i=1}^{n}i$

当n=100时,计算的是1+2+3+...+100的值

抽取具有共性的算式:sum=sum+i
若sum初值为0,该算式重复100次,i从1变到100,每次增1

设i为循环变量,则有:
指定循环起点的表达式1: i=1
给出循环条件的表达式2: i <=100
设置循环步长的表达式3: i++
循环体中的语句: sum=sum+i;

                            
for(i=1; i<=100; i++)
{
    sum=sum+i;
}
                            
                        

求1+2+3+...+100源程序

                        
#include<stdio.h>
int main()
{
    int i, sum;
    sum=0;                /* 设置累加和sum的初值为0 */
    for(i=1; i<=100; i++) /* 循环重复100次 */
    {
        sum=sum+i;        /* 反复累加 */
    }
    printf("sum=%d\n", sum);  /* 输出累加和 */
    return 0;
}
                            
                        

思考:循环体能否改为

                        
for(int i=1; i<=100; i++)
{
    sum=0;
    sum=sum+i;
}
                            
                        

求1+1/2+1/3+...+1/100

                            
#include<stdio.h>
int main()
{
    int i;
    double sum;
    sum=0;                  /* 设置累加和sum的初值为0 */
    for(i=1; i<=100; i++)   /* 循环重复100次 */
    {
        sum=sum+1.0/i;        /* 反复累加 */
    }
    printf("sum=%f\n", sum);    /* 输出累加和 */
    return 0;
}
                            
                        

思考:循环体第9行能否改为sum=sum+1/i?

指定次数的循环程序设计

指定次数的循环程序设计,一般包含四个部分:

  • 初始化,指定循环起点
    • 给循环变量赋初值,如i=1;
    • 进入循环之前,设置相关变量的初值,如sum=0;
  • 条件控制,如只要i<=100,循环就继续
  • 工作,指重复执行的语句(循环体)
    • 循环体可以是一条语句,可以是复合语句,也可以是空语句,如sum=sum+i;
  • 改变循环变量,在每次循环中改变循环变量的值
    • 如i++,以改变循环条件的真假,一旦i>100,循环就结束

例2-7 求1+2+3+...+n

                            
#include<stdio.h>
int main()
{
    int i, sum;
    sum=0;
    printf("Enter n:");
    scanf("%d", &n);

    for(i=1; i<=n; i++)
    {
        sum=sum+i;
    }
    printf("sum=%d\n", sum);
    return 0 ;
}
                            
                        

求1+1/2+1/3+...+1/n

                            
#include<stdio.h>
int main()
{
    int i;
    double sum;
    sum=0;
    printf("Enter n:");
    scanf("%d", &n);
    for(i=1; i<=n; i++)
    {
        sum=sum+1.0/i;
    }
    printf("sum=%lf\n", sum);
    return 0;
}
                            
                        

求1+1/3+1/5+...的前n项和

求前n项,即循环n次,每次累加1项
循环中可写成sum=sum+item; 而item=1.0/2*(i-1);

                        
#include<stdio.h>
int main()
{
    int i, n;
    double item, sum;

    printf("Enter n:");
    scanf("%d", &n);
    sum=0;
    for(i=1; i<=n; i++)
    {
        item=1.0/(2*i-1);    /* 计算第i项的值 */
        sum=sum+item;        /* 累加第i项的值 */
    }
    printf("sum=%f\n", sum);
    return 0;
}
                            
                        

求1-1/3+1/5-...的前n项和

例2-8. 输入一个正整数n,求1-1/3+1/5-...的前n项和

关键是确定循环体内的结构,item=flat*1.0/2*(i-1); sum=sum+item,item如何表示?

                        
flag=-flag;
denominator=denominator+2;
item=flag*1.0/denominator;

sum=sum+item;
                                
                            

求1-1/3+1/5-...的前n项和

                        
#include<stdio.h>
int main()
{
    int denominator, flag, i, n; /* denominator分母(1,3,5,...), flag(1,-1) */
    double item, sum;

    printf("Enter n:");
    scanf("%d", &n);
    flag=1;
    denominator=1;
    item=1;
    sum=0;
    for(i=1; i<=n; i++)
    {
        sum=sum+item;              /* 累加第i项的值 */
        flag=-flag;                 /* 准备下一次循环 */
        denominator=denominator+2;
        item=flat*1.0/denominator;  /* 计算第i+1项的值 */
    }
    printf("sum=%lf\n", sum);
    return 0;
}
                            
                        

求n!的值

例2-9. 输入一个正整数n,计算n!的值

循环体内的结构:product=product*item(第i项); item=i;

                        
#include<stdio.h>
int main()
{
    int i, n;
    double product;

    printf("Enter n:");
    scanf("%d", &n);
    product=1;              /* 置阶乘product的初始值为1 */
    for(i=1; i<=n; i++)
    {
        product=product*i;   /* 循环重复n次,计算n! */
    }
    printf("product=%.0f\n", product);
    return 0;
}
                            
                        

求$x^n$的值

输入实数$x$和正整数$n$,计算$x^n$的值

循环体内的结构:power=power*item(第i项); item=x;

                        
#include<stdio.h>
int main()
{
    int i, n;
    double x, power;

    printf("Enter x, n:\n");
    scanf("%lf%d", &x, &n);
    power=1;              /* 置power的初始值为1 */
    for(i=1; i<=n; i++)
    {
        power=power*x;   /* 循环重复n次,计算x的n次幂 */
    }
    printf("power=%.0f\n", power);
    return 0;
}
                            
                        

2.5 生成乘方表和阶乘表

例2-10. 输入一个正整数n,生成一张2的乘方表,输出$2^0$到$2^n$的值,可以调用幂函数计算2的乘方

for(i=0; i <=n; i++){
  power=pow(2,n); /* 调用幂函数pow(2,i)计算2的i次方 */
  输出power的值;
}

生成乘方表源程序

                        
#include<stdio.h>
#include<math.h>
int main()
{
    int i, n;
    double power;
    printf("Enter n:");
    scanf("%d", &n);
    for(i=0; i<=n; i++)
    {
        power=pow(2,i);  /* 调用幂函数pow(2,i)计算2的i次方 */
        printf("pow(2,%d)=%.0f\n", i, power);
    }
    return 0;
}
                            
                        

生成阶乘表

例2-11. 输入一个正整数n(n<=16),生成一张阶乘表,输出0!到n!的值。要求定义和调用函数fact(n)计算n!,函数类型是double

                            
for(i=0; i<=n; i++)
{
    product=fact(i);    /* 调用自定义的函数fact(i)计算 */
    printf("%f", product);
}
                            
                        

生成阶乘表源程序

                        
#include<stdio.h>
double fact(int n);    /* 自定义函数的声明 */
int main()
{
    int i, n;
    double result;

    printf("Enter n:");
    scanf("%d", &n);
    for(i=0; i<=n; i++)
    {
        result=fact(i);    /* 调用自定义的耿当fact(i)计算i! */
        printf("%d!=%.0f\n", i, result);
    }
    return 0;
}
double fact(int n)       /* 函数首部 */
{
    int i;
    double product;
    product=1;
    for(i=1; i<=n; i++)
    {
        product=product*i;
    }
    return product;       /* 将函数结果回送主函数 */
}
                            
                        

函数的概念

  • C语言中有两种类型的函数
    • 标准库函数
    • 自定义函数
  • 函数可做到一次定义,多次调用
  • 使用自定义函数的程序框架
                        
/* 声明自定义函数,以分号结束。自定义函数包含函数名、函数参数和函数类型 */
double fact(int n);
int main()
{
    //......
    result=fact(i);    /* 调用自定义函数fact(i)计算i! */
    //......
}

/* 定义求n!的函数 */
double fact(int n)
{
    //......
}