分类: 理论课

  • 第 6 讲:让计算机做复杂的事情——循环应用

    一、循环结构回顾

    1. 循环四要素

    • 循环体:循环中重复执行的核心操作。
    • 循环初始条件:循环控制变量的初始化。
    • 循环控制表达式:构建循环控制条件。
    • 循环控制变量的修改:构建循环退出机制。

    2. 三种循环语句

    • for循环for(E1; E2; E3) 语句S;
    • while循环while(E2) { 语句S; E3; }
    • do...while循环do { 语句S; E3; } while(E2);

    3. 循环结构与选择结构的区别

    • 循环结构:用于重复执行某段代码。
    • 选择结构:用于根据条件选择执行不同的代码。

    4. 多重循环的执行过程

    • 外层循环每执行一次,内层循环从头执行一遍。
    • 循环嵌套时,内层循环是外层循环体中的一条语句。

    二、灵活退出循环:breakcontinue

    1. break语句

    • 功能:强制中断循环,立即退出当前循环。

    • 语法

      while(表达式1) {
          语句1;
          if(表达式2) break;
      }
      
    • 注意事项

      • 只能用于循环语句和switch语句中。
      • 在多重循环中,break只能跳出一层循环

    2. continue语句

    • 功能:跳过本次循环中剩余语句,直接进入下一次循环。

    • 语法

      while(表达式1) {
          语句1;
          if(表达式2) continue;
          语句2;
      }
      
    • 区别

      • break:终止整个循环。
      • continue:终止本次循环,继续下一次循环。

    三、枚举法(穷举法)

    1. 概念

    • 枚举法是指对问题域中所有可能的解进行穷举搜索,并根据条件筛选出符合要求的解。

    2. 基本模式

    while (在搜索空间内) {
        if (满足判决条件) {
            输出解;
        }
        更新可能的解;
    }
    

    3. 示例:韩信点兵问题

    • 问题描述:士兵人数满足以下条件:
      1. x % 5 == 1
      2. x % 6 == 5
      3. x % 7 == 4
      4. x % 11 == 10
    • 解法:从1开始逐一枚举,直到找到满足所有条件的数。

    四、枚举法的优化策略

    1. 启发式搜索

    • 利用问题信息引导搜索,减少搜索范围。
    • 示例:韩信点兵问题中,利用x % 5 == 1,可令x每次增加5,而不是1。
    • 优化效果
      • 原始搜索:10000次循环。
      • 优化1(增加5):2111次循环。
      • 优化2(增加11):423次循环。
      • 优化3(增加55):192次循环。

    2. 优化思路

    • 根据约束条件,调整搜索步长,减少无效枚举。
    • 示例:结合多个约束条件,选择最大公约数或最小公倍数作为步长。

    五、综合应用:百钱百鸡问题

    1. 问题描述

    • 鸡翁一值钱五,鸡母一值钱三,鸡雏三值钱一。
    • 百钱买百鸡,问鸡翁、鸡母、鸡雏各几何?

    2. 解法思路

    • 使用三重循环枚举鸡翁、鸡母、鸡雏的数量。
    • 约束条件:
      • 5 * cock + 3 * hen + chick / 3 == 100
      • cock + hen + chick == 100
      • chick % 3 == 0
    • 优化:根据约束减少循环次数。

    六、总结

    1. 循环应用要点

    • 熟练使用breakcontinue控制循环流程。
    • 掌握枚举法的基本思想与实现方式。
    • 学会通过优化搜索策略提高程序效率。

    2. 核心思想

    • 循环 + 条件判断是解决枚举问题的基本模式。
    • 启发式优化是提高枚举效率的关键。
    • 编程不仅是实现功能,更是精益求精的过程。

    七、思考题

    回顾用数学方法和循环求解“物不知数”、“韩信点兵”等问题的过程,思考还有哪些问题适合用循环求解?如何结合数学知识优化枚举过程?

  • 第 5 讲:让计算机做复杂的事情——循环结构

    一、循环结构概述

    1. 为什么需要循环结构

    • 用于处理规律性的重复计算或操作
    • 避免代码冗余,提高代码简洁性和功能性。
    • 例如:输入1000名学生的身高并计算平均身高。

    2. 循环结构的四要素

    1. 循环体:重复执行的核心操作。
    2. 循环初始条件:循环控制变量的初始化。
    3. 循环控制条件:决定是否继续循环的表达式。
    4. 循环控制变量的修改:使循环能正常退出,避免死循环。

    二、三种循环语句

    1. while 循环

    • 语法形式

      while (表达式) {
          循环体;
      }
      
    • 执行流程

      1. 判断表达式是否为真(非0)。
      2. 若为真,执行循环体,返回步骤1;否则退出循环。
    • 特点

      • 先判断后执行。
      • 循环体执行次数:0到多次
      • 循环体可以是空语句、表达式语句、函数调用、控制语句或复合语句。
    • 注意事项

      • 必须有修改循环控制变量的语句。
      • 避免死循环。

    2. do-while 循环

    • 语法形式

      do {
          循环体;
      } while (表达式);
      
    • 执行流程

      1. 先执行一次循环体。
      2. 判断表达式是否为真。
      3. 若为真,继续执行;否则退出。
    • 特点

      • 先执行后判断。
      • 循环体至少执行1次
    • 适用场景:适用于初始条件不易确定,且至少需执行一次的情况。

    3. for 循环

    • 语法形式

      for (表达式1; 表达式2; 表达式3) {
          循环体;
      }
      
    • 执行流程

      1. 执行表达式1(初始化)。
      2. 判断表达式2(控制条件)。
      3. 若为真,执行循环体,再执行表达式3(更新),返回步骤2;否则退出。
    • 特点

      • 结构紧凑,适合已知循环次数的情况。
      • 循环体执行次数:0到多次
    • 灵活用法

      • 可以省略表达式1、表达式2或表达式3(但分号不能省略)。
      • 表达式1和表达式3可以是逗号表达式。
      • 循环体可为空语句,操作可移至表达式3中。

    三、循环嵌套

    1. 概念

    • 一个循环体内包含另一个循环,称为循环嵌套
    • 外层循环每执行一次,内层循环从头执行一遍。
    • 常见有二重循环、三重循环等。

    2. 嵌套类型

    • 控制变量无交叉:内层循环次数固定。
    • 控制变量有交叉:内层循环次数依赖于外层循环变量。

    3. 示例:打印图形

    • 打印5×5星号矩阵:

      for (i = 0; i < 5; i++) {
          for (j = 0; j < 5; j++) {
              printf("* ");
          }
          printf("\n");
      }
      
    • 打印右三角形星号:

      for (i = 1; i <= 5; i++) {
          for (j = 1; j <= i; j++) {
              printf("*");
          }
          printf("\n");
      }
      

    四、循环应用实例

    1. 累加求和(1到1/100)

    • 使用 whiledo-whilefor 实现。

    • 核心代码:

      sum = 0;
      for (n = 1; n <= 100; n++) {
          sum += 1.0 / n;
      }
      

    2. 求最大值与最小值

    • 思路:将第一个输入的数作为初始最大值和最小值,后续输入逐一比较更新。

    • 代码示例:

      max = min = d;  // d为第一个输入的数
      for (i = 2; i <= 10; i++) {
          scanf("%d", &d);
          if (d > max) max = d;
          if (d < min) min = d;
      }
      

    3. 计算平均分

    • 循环输入多个成绩并累加,最后计算平均值。

    五、重点与难点

    重点

    • 循环结构的构建方法。
    • whiledo-whilefor 语句的使用。
    • 循环嵌套的程序设计。

    难点

    • 循环条件的正确设置与更新,避免死循环。
    • 嵌套循环的逻辑理解与编写。
    • 循环与选择结构的结合使用。

    六、思考题

    1. 选择结构与循环结构的区别是什么?
    2. whiledo-while 如何等价转换?
  • 第 4 讲:让计算机做复杂的事情 – 选择结构

    一、核心概念:选择结构的作用

    选择结构是程序三大基本结构(顺序、选择、循环)之一,用于实现“根据条件执行不同操作”的逻辑,让计算机具备“判断决策”能力。

    二、二分支选择结构(二选一)

    二分支结构根据条件真假,从两个操作中选择一个执行,核心实现方式为if语句和条件运算符。

    1. if语句实现二分支

    (1)基本格式

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

    (2)执行逻辑

    • 计算“表达式”的值,C语言中非0为真,0为假
    • 若表达式为真(非0),执行语句1后退出选择结构;若为假(0),执行语句2后退出。

    (3)常见条件表达式类型

    • 关系表达式:if(x != 0)(x不等于0时为真)、if(a >= b)(a大于等于b时为真)。
    • 逻辑表达式:if(x > 0 && y > 0)(x和y都大于0时为真)。
    • 算术表达式:if(x + 3.5)(x+3.5不等于0时为真)。
    • 变量/常量:if(x)(x非0为真)、if(1)(常量非0为真)、if(0)(常量0为假)。

    (4)示例1:求两个整数的最大值

    #include<stdio.h>
    int main() {
        int a, b, max;
        printf("Input a,b:\n");
        scanf("%d,%d", &a, &b);
        if(a >= b) max = a;  // 条件真时执行
        else max = b;        // 条件假时执行
        printf("max=%d", max);
        return 0;
    }
    

    (5)示例2:求解一元二次方程ax²+bx+c=0的根

    #include<stdio.h>
    #include<math.h>  // 调用平方根函数sqrt需引入
    int main() {
        double a, b, c, disc, x1, x2, p, q;
        scanf("%lf%lf%lf", &a, &b, &c);
        disc = b*b - 4*a*c;  // 计算判别式
        if(disc < 0)
            printf("This equation hasn't real roots.");  // 无实根
        else {
            p = -b/(2.0*a);
            q = sqrt(disc)/(2.0*a);
            x1 = p + q;
            x2 = p - q;
            printf("real roots:\nx1=%7.2lf\nx2=%7.2lf", x1, x2);  // 输出两个实根
        }
        return 0;
    }
    

    2. 条件运算符实现二分支

    (1)基本格式

    表达式1 ? 表达式2 : 表达式3;
    

    (2)执行逻辑

    • 表达式1为真(非0)时,结果为表达式2的值;为假(0)时,结果为表达式3的值。
    • 条件运算符是三目运算符,需搭配3个操作对象,可简化简单的二分支逻辑。

    (3)示例:大写字母转小写字母

    #include<stdio.h>
    int main() {
        char ch;
        scanf("%c", &ch);
        ch = (ch >= 'A' && ch <= 'Z') ? (ch + 32) : ch;  // 是大写则+32转小写,否则不变
        printf("%c", ch);
        return 0;
    }
    

    三、多分支选择结构(多选一)

    多分支结构根据条件的多种结果,从多个操作中选择一个执行,核心实现方式为if嵌套和switch语句。

    1. if嵌套实现多分支

    (1)基本格式

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

    (2)关键规则

    • else总是与上方“最近的未配对if”配对,可通过花括号{}强制指定配对关系。
    • 多个if-else if依次判断,满足一个条件后执行对应语句,不再判断后续条件。

    (3)示例1:成绩等级评定(优秀/良好/及格/不及格)

    #include<stdio.h>
    int main() {
        float score;
        printf("Please input a score:\n");
        scanf("%f", &score);
        if(score >= 85) printf("优秀");
        else if(score >= 75) printf("良好");
        else if(score >= 60) printf("及格");
        else printf("不及格");
        return 0;
    }
    

    (4)示例2:分段函数计算(y根据x的范围取不同值)

    // 函数定义:y = -1(x<0);y=0(x=0);y=1(x>0)
    #include<stdio.h>
    int main() {
        int x, y;
        scanf("%d", &x);
        if(x < 0) y = -1;
        else if(x == 0) y = 0;
        else y = 1;
        printf("y=%d\n", y);
        return 0;
    }
    

    2. switch语句实现多分支

    (1)基本格式

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

    (2)核心规则

    • 表达式需为整数类型(int、char等),case后常量需与表达式类型一致,且不能重复。
    • 执行逻辑:找到与表达式值匹配的case,执行对应语句;若无匹配case,执行default语句(若有)。
    • break语句用于跳出switch结构,若无break,会继续执行后续case语句(穿透现象)。
    • 多个case可共用一组执行语句(无break分隔),case顺序不影响结果。

    (3)示例:根据成绩等级输出分数段

    #include<stdio.h>
    int main() {
        char grade;
        printf("Your score:");
        scanf("%c", &grade);
        switch(grade) {
            case 'A': printf("85~100\n"); break;
            case 'B': printf("75~84\n"); break;
            case 'C': printf("60~74\n"); break;
            case 'D': printf("<60\n"); break;
            default: printf("enter data error\n");  // 输入无效等级时执行
        }
        return 0;
    }
    

    (4)共用语句示例

    // A、B、C等级均输出“60分以上”,D等级输出“60分以下”
    switch(grade) {
        case 'A':
        case 'B':
        case 'C': printf("60分以上"); break;
        case 'D': printf("60分以下"); break;
        default: printf("输入错误");
    }
    

    四、综合案例:判断闰年

    1. 闰年规则

    • 能被4整除但不能被100整除,或能被400整除的年份为闰年,否则为平年。

    2. 程序实现

    #include<stdio.h>
    int main() {
        int year, leap = 0;  // leap为标记变量,0表示平年,1表示闰年
        printf("enter year:");
        scanf("%d", &year);
        if(year % 4 == 0) {
            if(year % 100 == 0) {
                if(year % 400 == 0) leap = 1;  // 能被400整除
                else leap = 0;                 // 能被100整除但不能被400整除
            } else leap = 1;                   // 能被4整除但不能被100整除
        } else leap = 0;                       // 不能被4整除
        if(leap) printf("%d is a leap year.", year);
        else printf("%d is not a leap year.", year);
        return 0;
    }
    

    五、核心要求与注意事项

    1. 核心要求

    • 灵活使用if语句解决二分支问题,用if嵌套解决多分支问题。
    • 读懂并合理使用switch语句,理解break的作用和穿透现象。

    2. 注意事项

    • 区分“真”“假”:C语言中无专门布尔类型,非0值(正数、负数、非0小数)为真,0为假。
    • if嵌套中注意if-else配对关系,必要时用{}明确代码块。
    • switch语句中表达式必须为整数类型,case常量不可重复。

    六、思考题

    • C语言中如何表示“真”和“假”?
    • 系统如何判断一个量的“真”和“假”?
  • 第 3 讲:与计算机面对面地交流

    一、案例引入与核心问题

    • 关键变量定义:编号(code,字符型)、尺寸(length/width/height,浮点型)、速度(speed,整型)、乘员数(passengers,整型)。
    • 两种交流方式:临时交互(键盘+显示器,不保存数据)、持久交互(内存+硬盘,保存数据)。

    二、标准输入输出(键盘与显示器交互)

    (一)scanf语句(数据输入)

    • 功能:通过键盘向变量输入数据,语法为scanf(格式控制字符串, 变量地址列表)
    • 核心要求:变量需加地址符&,指针变量可直接作为参数(无需&)。
    • 常用格式控制符
      • 整型:%d(有符号十进制)、%u(无符号十进制)、%o(八进制)、%x/X(十六进制)。
      • 字符/字符串:%c(单个字符)、%s(字符串)。
      • 实型:%f(小数/指数形式)、%e/E(指数形式)、%g/G(自动选最短格式)。
    • 附加格式符:l(长整型/双精度)、h(短整型)、域宽(指定输入宽度)、*(读入不赋值)。

    (二)printf语句(数据输出)

    • 功能:将变量、常量或表达式的值输出到显示器,语法为printf(格式控制字符串, 输出数据列表)
    • 常用格式控制符:与scanf基本一致,实型%f默认输出6位小数。
    • 附加格式符:m(指定最小输出宽度)、.n(指定小数位数/字符串截取长度)、-(左对齐)。
    • 示例:输出三角形可通过%ms(指定字符串域宽)实现对齐。

    三、文件输入输出(硬盘持久化交互)

    (一)文件基础概念

    • 分类:文本文件(可读字符形式)、二进制文件(二进制数据形式)。
    • 核心类型:FILE(文件类型标识符),通过文件指针(FILE *fp)操作文件。

    (二)文件操作基本流程

    1. 包含头文件:#include <stdio.h>
    2. 定义文件指针:FILE *文件指针名
    3. 打开文件:使用fopen函数,语法为fp = fopen("文件名", "打开方式")
    4. 读写操作:文本文件用fscanf(读)、fprintf(写),用法与scanf/printf类似,多一个文件指针参数。
    5. 关闭文件:fclose(文件指针),避免数据丢失或资源占用。

    (三)fopen打开方式说明

    打开方式 作用 文件不存在时的处理
    “r”(只读) 读取已存在的文本文件 出错
    “w”(只写) 输出数据到文本文件 创建新文件
    “a”(追加) 向文件尾部添加数据 创建新文件
    “r+”(读写) 读写已存在的文本文件 出错
    “w+”(读写) 新建文件并读写 创建新文件
    “a+”(读写) 读写文件,尾部追加 创建新文件

    四、文件读取示例

    • 核心任务:从指定文本文件读取数据并输出到显示器。
    • 关键步骤:定义变量→定义文件指针→打开文件(指定路径)→fscanf读取数据→printf输出→关闭文件。
    • 示例代码逻辑:读取文件中“整数,浮点数,字符”格式数据,分别赋值给对应类型变量并输出。

    五、重点与难点

    (一)重点

    • 标准输入输出:scanfprintf的格式控制符使用规则。
    • 文件操作:文件概念、“打开-读写-关闭”流程及fopenfscanffprintffclose函数用法。

    (二)难点

    • 输入输出缓冲区的理解。
    • 文件操作函数的正确调用(路径、打开方式、指针管理)。

    六、思考题

    1. 如何判断读取的文件是否存在,程序能否自动处理文件不存在的情况?
    2. 若需合并上千个文件,应设计何种解决方案?
  • 第 2 讲:让计算机学会运算

    一、变量与常量

    (一)变量

    1. 定义:存储数值可改变的量,需指定数据类型,占用固定内存空间(如int型占4字节)。
      • 一般形式:数据类型 变量名称1, 变量名称2, ..., 变量名称n;
      • 示例:int count;(定义存储常服数量的整型变量count)
    2. 初始化:定义时为变量赋予初始值,避免使用未初始化变量(会导致运行错误)。
      • 一般形式:数据类型 变量名称 = 初始值;
      • 示例:
        • float cj = 90;(定义浮点型变量cj,初始值90.0)
        • int x = 1, y, z;(x初始值1,y、z未初始化,值为随机数)

    (二)常量

    1. 分类及定义
      类型 说明 示例 注意事项
      整型常量 整数,默认int型存储 sum = sum + 357 可指定类型/进制:<br>- 92LL(long long型)、92U(无符号整型)<br>- 07(八进制)、0X1F(十六进制)
      浮点型常量 小数或指数形式,默认double型 十进制小数:0.123123.0<br>指数形式:1.2e-27E0 可指定类型:<br>- 3.14F(float型)、3.14L(long double型)<br>- 十进制小数必须含小数点,指数形式e前后需有数
      字符常量 单撇号括起的1个字符,值为ASCII码 普通字符:'a'(97)、'0'(48)<br>转义字符:'\n'(换行,10)、'\x62'(‘b’) 不可用'ab'表示2个字符,需分开写'a''b'
      字符串常量 双撇号括起的字符序列,末尾自动加'\0'作为结束标志 "China"(内存存储:C h i n a \0)、"中国" 与字符常量区别:'a'占1字节,"a"占2字节(含'\0'
      符号常量 用标识符表示常量,需用#define定义 #define PI 3.14(PI代表3.14) 定义后不可修改,通常大写,增强代码可读性

    二、指针变量

    (一)核心概念

    指针变量存储的是其他变量的内存地址,通过地址可间接访问目标变量,类比“通过房间号找房间内物品”。

    (二)定义与初始化

    1. 定义:需指定基类型(与目标变量类型一致),*表示指针类型。
      • 一般形式:数据类型 *变量名称;
      • 示例:
        • float *p3;(定义指向float型变量的指针p3)
        • double *p4, *p5;(定义2个指向double型变量的指针)
        • 注意:double *p1, p2;中p2是普通double变量,非指针
    2. 初始化:初始值为已定义变量的地址(&取地址运算符)或空指针(0)。
      • 一般形式:数据类型 *变量名称 = 初始值;
      • 示例:
        • char a, *p1 = &a;(p1存储变量a的地址,指向a)
        • int *p2 = 0;(p2为空指针,不指向任何变量)

    (三)变量访问方式

    访问方式 说明 示例
    直接访问 通过变量名访问 short cj = 92;(直接给cj赋值92)
    间接访问 通过指针变量访问(*指针运算符,表“指向的变量”) *p1 = 90;(通过p1修改其指向的变量a的值为90)

    三、运算符和表达式

    (一)运算符分类及规则

    1. 核心运算符汇总

      类别 运算符 含义 优先级 结合性 示例 结果
      算术运算符 +(单目) 正号 右结合 +5 5
      -(单目) 负号 右结合 -5 -5
      ++ 自增 右结合 i=5; ++i 6
      -- 自减 右结合 i=5; --i 4
      * 乘法 左结合 5*3 15
      / 除法 左结合 5/3(整型)、5/3.0(浮点型) 1、1.666…
      % 取余 左结合 5%3 2
      +(双目) 加法 中低 左结合 5+3 8
      -(双目) 减法 中低 左结合 5-3 2
      关系运算符 <<=>>= 比较大小 左结合 5>2 1(真)
      == 等于 左结合 5==2 0(假)
      != 不等于 左结合 5!=2 1(真)
      逻辑运算符 ! 逻辑非 右结合 !0 1(真)
      && 逻辑与 左结合 1&&0 0(假)
      ` ` 逻辑或 左结合
      赋值运算符 = 赋值 最低 右结合 a = 5 将5赋给a
    2. 表达式计算规则

      • 先按优先级执行(如先乘除后加减,先逻辑非后逻辑与/或);
      • 优先级相同时,按结合性执行(如算术运算符左结合,单目运算符右结合);
      • 不可省略乘号(如a*b不可写ab),可加小括号强制改变顺序(如(a+b)*c)。

    (二)特殊情形

    1. 短路运算:逻辑表达式确定最终值后,后续分量不再计算。
      • 示例:a=0, b=10时,c=(a>=1 && (b=5))中,a>=1为假,直接确定结果为假,b=5不执行,最终b=10
    2. 数据类型转换
      • 自动转换:赋值时低精度→高精度(如char→short→int→long long),可能丢失数据(如char a=127; a=a+1;后a=-128,溢出);
      • 强制转换:用(目标类型)强制转换,优先级最高。
      • 示例:(char)12.5(将12.5转为char型12)、(int)x + y(先转x为int型,再与y相加)。

    四、处理简单问题(程序编写)

    (一)基本步骤

    1. 编写main()函数(程序入口);
    2. 定义与初始化变量;
    3. 输入数据(如scanf);
    4. 编写算法语句(核心逻辑);
    5. 输出结果(如printf)。

    (二)示例

    1. 华氏温度转摄氏温度
      • 公式:c = 5.0/9 * (f - 32)(用5.0避免整型除法);
      • 代码:
      #include <stdio.h>
      int main() {
          float c, f = 64;  // 初始化华氏温度f=64
          c = 5.0/9 * (f - 32);  // 计算摄氏温度
          printf("摄氏温度: %.1f\n", c);  // 输出结果(如17.8)
          return 0;
      }
      
    2. 三角形面积计算(海伦公式)
      • 公式:p=(a+b+c)/2s=sqrt(p*(p-a)*(p-b)*(p-c))(需包含math.h);
      • 代码:
      #include <stdio.h>
      #include <math.h>  // 调用sqrt函数需包含
      int main() {
          float a=6, b=7, c=8, p, s;  // 初始化三边长
          p = (a + b + c) / 2;  // 计算半周长
          s = sqrt(p * (p - a) * (p - b) * (p - c));  // 计算面积
          printf("三角形面积: %.2f\n", s);  // 输出结果(如20.33)
          return 0;
      }
      
    3. 大写字母转小写字母
      • 原理:小写字母ASCII码 = 大写字母ASCII码 + 32;
      • 代码:
      #include <stdio.h>
      int main() {
          char u_l = 'B';  // 定义大写字母变量
          u_l = u_l + 32;  // 转为小写('B'+32='b')
          printf("小写字母: %c\n", u_l);  // 输出'b'
          return 0;
      }
      

    五、重点与难点

    1. 重点
      • 变量的定义、初始化与使用;
      • 常量(尤其是符号常量、转义字符)的定义与使用;
      • 算术、关系、逻辑运算符的优先级与表达式计算。
    2. 难点
      • 指针变量的定义、初始化及间接访问;
      • 数据类型自动转换的溢出问题与强制转换的正确使用。

    六、思考题

    1. 符号常量与其他常量(整型、浮点型等)的区别:符号常量用标识符表示,无类型;其他常量有明确类型。符号常量与变量的区别:符号常量定义后不可修改,变量值可改变。
    2. 程序运行结果错误的排查方法:检查变量是否初始化、数据类型是否匹配、运算符优先级是否正确、公式逻辑是否有误、是否存在数据溢出等。
  • 第 1 讲:程序设计基本概念

    一、人类的助手:计算机核心概念

    1. 程序与指令

    • 指令:计算机可直接执行、不可再分割的命令,是计算机操作的最小单位。
    • 程序:一组计算机能够识别和执行的指令集合,用于完成特定任务。
    • 程序设计(编程):将人类解决问题的思路转化为程序,进而转换为计算机可执行指令的过程。

    二、与计算机对话:计算机语言体系

    计算机语言按抽象程度分为三级,核心作用是实现“人类意图→计算机执行”的转换。

    1. 机器语言(最低级)

    • 本质:二进制代码(0和1)组成的机器指令集合,是计算机唯一能直接理解和执行的语言。
    • 结构:每条指令包含“操作码”(指定操作类型,如存储、加法)和“操作数”(指定操作对象,如寄存器地址、数值)。
    • 示例
      • 存储指令:1 001 10(将数据存入地址为10的寄存器)
      • 加法指令:2 002 10 00000010(将十进制2与寄存器10中的数相加并存储)
    • 缺点:可读性极差,难以记忆和编写,依赖具体硬件。

    2. 汇编语言(低级)

    • 本质:用符号(如MOV、ADD)替代二进制指令的“符号语言”,仍依赖特定硬件架构。

    • 优势:相比机器语言更易理解,降低编程复杂度。

    • 示例:“1+2”的汇编实现

      指令序号 操作码 操作数1 操作数2 指令含义
      1 MOV A 将十进制“1”存入寄存器A
      2 ADD A 2 十进制“2”与寄存器A中的数相加,结果存回A
    • 局限性:仍需了解硬件细节,未完全脱离机器依赖。

    3. 高级语言(最高级)

    • 核心特点:独立于特定计算机系统,语法接近人类自然语言,可读性和通用性强。
    • 执行流程:需通过“编译器”将高级语言编写的源程序(如.c文件)转换为目标程序(如.obj文件),再经“链接程序”生成可执行程序(如.exe文件)。
    • 主流语言:根据IEEE Spectrum 2023排行榜,热门语言包括Python、C++、C、Java等。

    4. 重点:C语言

    • 发展背景:20世纪70年代由美国贝尔实验室的D.M.Ritchie设计,用于开发UNIX系统。

    • 语言结构:类比人类语言的层级关系,形成清晰的语法体系

      类别 结构
      人类语言 字 → 词 → 句子 → 段落 → 文章
      C语言 标识符 → 表达式 → 语句 → 函数 → 程序
    • 基础示例:输出“I love China!”的C程序

      #include <stdio.h>  // 引入标准输入输出库
      int main() {         // 主函数,程序入口(C程序必须有且仅有一个main函数)
          printf("I love China!");  // 输出语句
          return 0;        // 主函数返回值,标识程序正常结束
      }
      

    (1)C语言核心组成单元

    • 标识符:用于命名变量、函数等的符号,规则如下:

      • 由英文字母(A-Z、a-z)、数字(0-9)、下划线(_)组成;
      • 不能以数字开头;
      • 区分大小写(如Word3word3是不同标识符);
      • 不能与“关键字”重名。
    • 关键字:C语言预定义的特殊标识符,具有固定含义,不可自定义

      常用关键字 功能说明
      int、char、double 数据类型声明
      if、else、while、for 流程控制
      return、break、continue 程序跳转
      void、static、const 存储类型/修饰符
    • 表达式:用运算符连接运算对象的式子,用于计算或判断

      运算符类型 符号示例 功能说明
      算术运算符 +、-、*、/、%、++ 加减乘除、取余、自增
      关系运算符 >、<、==、!=、>=、<= 比较大小关系
      逻辑运算符 !(非)、&&(与)、
      赋值运算符 =、+=、-=、*= 变量赋值及扩展赋值
      其他 sizeof(求字节数)、(类型)(强制转换) 数据操作辅助
    • 语句:C语言的基本执行单位,一条语句对应一个或多个机器指令,如:

      • 赋值语句:sum = 1 + 2;
      • 输出语句:printf("Hello");
      • 分支语句:if (sunny == 1) fly_kite = 1; else stay_home = 1;
    • 函数:C程序的基本功能单位,实现代码模块化,示例:两数交换函数

      #include <stdio.h>
      // 自定义函数swap:通过指针交换两个整数的值
      void swap(int *a, int *b) {
          int temp = *a;  // 临时变量存储*a的值
          *a = *b;        // 将*b的值赋给*a
          *b = temp;      // 将临时变量的值赋给*b
      }
      int main() {
          int num1 = 2, num2 = 3;
          swap(&num1, &num2);  // 调用swap函数,传入变量地址
          printf("交换后的两个数: %d %d", num1, num2);  // 输出结果:3 2
          return 0;
      }
      

    三、从问题到程序:程序设计完整流程

    程序设计需遵循标准化步骤,确保逻辑清晰、可维护性强。

    1. 核心步骤

    1. 分析问题:明确问题需求(如“计算1到100的和”“找出三个数中的最大值”),确定输入、输出和处理逻辑。

    2. 设计算法

      • 算法定义:解决问题的具体方法和步骤,需满足“有穷性”“确定性”“可行性”。
      • 表示方法
        • 自然语言:如“计算1+2+…+100”的步骤:
          1. 令sum=0(累加结果)、augend=1(累加项);
          2. sum = sum + augend;
          3. augend = augend + 1;
          4. 若augend ≤ 100,跳转至步骤2;否则执行步骤5;
          5. 输出sum的值。
        • 流程图:用图形符号表示算法,常用符号包括
          • 开始/结束框(椭圆形)、执行框(矩形)、选择框(菱形)、输入输出框(平行四边形)、流程线(箭头)。
      • 经典结构:顺序结构(按步骤执行)、选择结构(if-else,根据条件分支)、循环结构(while/for,重复执行)。
    3. 编写程序

      • 按算法逻辑,用选定的高级语言(如C语言)编写源程序;
      • 注意语法规范(如语句结尾加;、括号配对)。
    4. 测试程序

      • 编译:检查语法错误,生成目标程序;
      • 运行:测试功能正确性(如输入边界值、异常值),修复逻辑错误。
    5. 编写文档:记录程序关键信息,便于维护和使用,文档内容示例

      文档明细 具体内容 备注
      程序文件名称 FindTallestMan.c 源文件
      程序功能描述 找出三个数中最大的数及位置
      输入数据格式 小数,小数,小数 示例:1.9,1.8,1.7
      输出数据格式 身高最高的是第X人,他的身高是Y米 X、Y由程序计算输出

    四、让计算机认识世界:数据表示方式

    计算机仅能识别数字,需将各类信息(整数、小数、字符)转换为二进制形式存储。

    1. 整数表示

    • 存储单位:字节(1字节=8位二进制),字节有唯一地址(内存地址)。

    • 表示方法

      • 无符号整数:仅表示非负数,1字节范围为0~255(2⁸-1)。
      • 有符号整数:用最高位(符号位)表示正负(0为正,1为负),采用补码存储(解决“+0”与“-0”重复问题):
        • 正整数:补码=原码(二进制本身);
        • 负整数:补码=原码(除符号位外)按位取反 + 1。
    • C语言整数类型

      数据类型 字节数 是否有符号 取值范围
      unsigned short 2 0~65535(2¹⁶-1)
      signed short 2 -32768~32767(-2¹⁵~2¹⁵-1)
      unsigned int/long 4 0~4294967295(2³²-1)
      signed int/long 4 -2147483648~2147483647(-2³¹~2³¹-1)
      unsigned long long 8 0~18446744073709551615(2⁶⁴-1)
      signed long long 8 -9223372036854775808~9223372036854775807(-2⁶³~2⁶³-1)

    2. 小数表示(浮点数)

    • 特点:位数不固定,采用“指数形式”存储(类似科学计数法),如十进制19.625=二进制10011.101=1.0011101×2⁴。

    • 存储结构(以4字节float为例):1位符号位 + 8位指数位 + 23位尾数位。

    • C语言浮点类型

      数据类型 字节数 有效数位 数值范围(绝对值)
      float 4 6~7位 0 及 1.2×10⁻³⁸~3.4×10³⁸
      double 8 15~16位 0 及 2.3×10⁻³⁰⁸~1.7×10³⁰⁸
      long double 16 18~19位 0 及 3.4×10⁻⁴⁹³²~1.1×10⁴⁹³²
    • 注意:浮点数存在精度误差(如0.1无法用二进制精确表示),需避免直接用“==”比较。

    3. 字符表示

    • 编码标准

      • 英文字符/数字:采用ASCII码(1字节),如’A’=65(十进制)=1000001(二进制),‘a’=97,‘0’=48。
      • 中文字符:采用GB2312编码(2字节),解决ASCII码无法表示中文的问题。
    • C语言字符类型

      类型 字节数 取值范围 说明
      char(有符号) 1 -128~127 存储ASCII码或窄字符
      unsigned char(无符号) 1 0~255 存储扩展ASCII码
    • 表示方式:字符常量需用单引号包裹,如'A'(字符)与A(标识符)、"A"(字符串)区分。

    五、思考题

    • 如何区分十进制数与八进制(以0开头,如012=10十进制)、十六进制数(以0x开头,如0xA=10十进制)?
    • 为什么字符需要用单引号引起来?(区分字符常量与标识符、字符串)