前置知识: 入门指南

程序设计基础

9 minBeginner2026/6/14

算法流程图、控制结构、编译与解释、数据类型、运算符与表达式求值。

1. 算法流程

流程是用形符号表示算法步骤的直观工具。

1.1 基本符号

符号名称形状功能示例用途
起止框圆角矩形表示算法的开始或结束开始 / 结束
处理框矩形表示一个处理步骤sum = sum + i
判断框菱形表示条件判断i > 100?
输入输出框平行四边形表示数据的输入或输出输入n / 输出sum
流程线箭头表示执行方向→ ↓ ← ↑

1.2 流程示例:求1到N的和

    ┌───────┐
    │ 开始  │
    └───┬───┘

  ┌──────────┐
  │ 输入 N   │
  └────┬─────┘

  ┌──────────┐
  │ sum = 0  │
  │ i = 1    │
  └────┬─────┘

  ┌───────────┐
  │ i <= N ?  │──── 否 ──► ┌──────────┐
  └─────┬─────┘            │ 输出 sum │
    是  ▼                  └────┬─────┘
  ┌──────────────┐              ▼
  │ sum = sum + i│         ┌───────┐
  │ i = i + 1    │         │ 结束  │
  └──────┬───────┘         └───────┘

         └───► (回到判断框)

1.3 用代码对应流程

// 上述流程图对应的C语言代码
#include <stdio.h>

int main() {
    int N;
    scanf("%d", &N);      // 输入 N

    int sum = 0;
    int i = 1;
    while (i <= N) {       // 判断框: i <= N ?
        sum = sum + i;     // 处理框
        i = i + 1;         // 处理框
    }

    printf("%d\n", sum);   // 输出框
    return 0;
}

2. 三种基本控制结构

任何复杂程序都可以由三种基本控制结构组合而成,这被称为结构化程序设计的理论基础。

2.1 顺序结构

语句按书写顺序依次执行,是最基本的控制结构。

// 顺序结构:交换两个变量的值
int a = 3, b = 5;
int temp;

temp = a;   // 第1步
a = b;      // 第2步
b = temp;   // 第3步

printf("a=%d, b=%d\n", a, b);  // a=5, b=3

2.2 选择结构

根据条件选择不同的执行路径。

if-else 语句:

// 判断奇偶
int num = 7;
if (num % 2 == 0) {
    printf("%d 是偶数\n", num);
} else {
    printf("%d 是奇数\n", num);
}

多重 if-else:

// 成绩等级判定
int score = 85;

if (score >= 90) {
    printf("优秀\n");
} else if (score >= 80) {
    printf("良好\n");
} else if (score >= 70) {
    printf("中等\n");
} else if (score >= 60) {
    printf("及格\n");
} else {
    printf("不及格\n");
}

switch-case 语句:

// 根据运算符执行计算
char op = '+';
int a = 10, b = 3;

switch (op) {
    case '+': printf("%d\n", a + b); break;
    case '-': printf("%d\n", a - b); break;
    case '*': printf("%d\n", a * b); break;
    case '/':
        if (b != 0) printf("%d\n", a / b);
        else        printf("除数不能为0\n");
        break;
    default: printf("不支持的运算符\n"); break;
}

switch 中的 break 不能省略,否则会穿透执行后续所有 case,直到遇到 break 或 switch 结束。

2.3 循环结构

重复执行某段代码,直到条件不满足为止。

while 循环(先判断后执行):

// 计算1+2+3+...+100
int sum = 0, i = 1;
while (i <= 100) {
    sum += i;
    i++;
}
printf("sum = %d\n", sum);  // 5050

do-while 循环(先执行后判断,至少执行一次):

// 猜数字游戏(至少猜一次)
int secret = 42;
int guess;
do {
    printf("请输入猜测的数字: ");
    scanf("%d", &guess);
    if (guess > secret) printf("太大了\n");
    else if (guess < secret) printf("太小了\n");
} while (guess != secret);
printf("猜对了!\n");

for 循环(计数型循环):

// 打印九九乘法表
for (int i = 1; i <= 9; i++) {
    for (int j = 1; j <= i; j++) {
        printf("%d×%d=%-4d", j, i, i * j);
    }
    printf("\n");
}

break 与 continue:

// break: 跳出整个循环
for (int i = 0; i < 10; i++) {
    if (i == 5) break;    // i=5时跳出循环
    printf("%d ", i);      // 输出: 0 1 2 3 4
}

// continue: 跳过本次迭代,继续下一次
for (int i = 0; i < 10; i++) {
    if (i % 2 == 0) continue;  // 跳过偶数
    printf("%d ", i);          // 输出: 1 3 5 7 9
}

2.4 三种循环对比

特性whiledo-whilefor
执行次数可能0次至少1次可能0次
适用场景不确定次数至少执行一次已知循环次数
初始化位置循环外循环外for语句内

3. 程序编译与解释

高级语言需要转换为机器码才能执行,有两种主要方式:编译和解释。

3.1 编译(Compilation)

将源代码一次性翻译为机器码(目标文件),然后执行。

源代码(.c) → [编译器] → 目标文件(.o) → [链接器] → 可执行文件(.exe)
// hello.c
#include <stdio.h>
int main() {
    printf("Hello, World!\n");
    return 0;
}
# 编译过程
gcc -E hello.c -o hello.i     # 预处理:展开宏和头文件
gcc -S hello.i -o hello.s     # 编译:生成汇编代码
gcc -c hello.s -o hello.o     # 汇编:生成目标文件
gcc hello.o -o hello          # 链接:生成可执行文件
./hello                       # 执行

3.2 解释(Interpretation)

逐行读取源代码并即时执行,不生成独立的可执行文件。

源代码(.py) → [解释器] → 逐行执行
# hello.py
print("Hello, World!")
# 直接运行
python hello.py

3.3 编译与解释对比

特性编译型语言解释型语言
执行方式先编译后执行边解释边执行
执行速度快(直接运行机器码)慢(需要实时翻译)
跨平台性需要为不同平台编译只要有解释器即可运行
调试体验修改后需重新编译修改后直接运行
错误发现编译时发现语法错误运行时才发现错误
典型语言C, C++, Go, RustPython, JavaScript, Ruby

3.4 混合方式

许多现代语言采用编译+解释的混合方式:

Java:   源代码(.java) → 字节码(.class) → JVM解释/JIT编译执行
C#:     源代码(.cs) → IL字节码 → CLR解释/JIT编译执行
Python: 源代码(.py) → 字节码(.pyc) → Python虚拟机执行

JIT(Just-In-Time)编译在程序运行时将热点代码编译为机器码,兼顾了启动速度和执行效率。

4. 变量命名规则

4.1 通用命名规则

规则合法示例非法示例
由字母、数字、下划线组成score, max_valmy-name, 2nd
不能以数字开头val22val
不能使用关键字my_intint
区分大小写Namename

4.2 命名风格

风格格式适用语言示例
驼峰命名(小驼峰)首单词小写,后续首字母大写Java, JS, C#studentName
帕斯卡命名(大驼峰)每个单词首字母大写C#, StudentName
蛇形命名单词间用下划线连接C, Python, Ruststudent_name
全大写蛇形命名+全大写常量MAX_SIZE
// C语言命名示例
int student_count;       // 蛇形命名:变量
#define MAX_SIZE 100     // 全大写:常量
void calculate_sum();    // 蛇形命名:函数
// JavaScript命名示例
let studentName; // 小驼峰:变量
const MAX_SIZE = 100; // 全大写:常量
function calculateSum() {
  // 小驼峰:函数
  // ...
}

4.3 命名原则

  • 见名知义agea 好,studentCountsc
  • 避免缩写temperaturetemp 好(除非是通用缩写如 idurl
  • 布尔变量用 is/has 前缀isValidhasPermission
  • 函数名用动词开头getNamesetDatacalculateTotal

5. 基本数据

5.1 四种基本数据

关键字占用空间取值范围示例
整型int4字节(通常)-2³¹ ~ 2³¹-142, -7
浮点型float/double4/8字节见IEEE 754章节3.14, -0.5
字符型char1字节-128127 或 0255'A', '0'
布尔型bool1字节true/falsetrue, false

5.2 整型的不同大小

#include <stdio.h>
#include <limits.h>

int main() {
    // 各整型的大小和范围
    printf("char:    %zu字节, 范围: %d ~ %d\n",
           sizeof(char), CHAR_MIN, CHAR_MAX);
    printf("short:   %zu字节, 范围: %d ~ %d\n",
           sizeof(short), SHRT_MIN, SHRT_MAX);
    printf("int:     %zu字节, 范围: %d ~ %d\n",
           sizeof(int), INT_MIN, INT_MAX);
    printf("long:    %zu字节, 范围: %ld ~ %ld\n",
           sizeof(long), LONG_MIN, LONG_MAX);

    return 0;
}

典型输出(64位系统):

字节数范围
char1-128 ~ 127
short2-32,768 ~ 32,767
int4-2,147,483,648 ~ 2,147,483,647
long4/8取决于平台
long long8-9.2×10¹⁸ ~ 9.2×10¹⁸

5.3 有符号与无符号

signed char   sc = -1;     // 范围: -128 ~ 127
unsigned char uc = 255;    // 范围: 0 ~ 255

// 无符号整型:只有正数,范围翻倍
unsigned int ui = 4294967295U;  // 范围: 0 ~ 4,294,967,295

// 注意:无符号数不会变负
unsigned int x = 0;
x = x - 1;  // 不是-1,而是4294967295(回绕)

5.4 型转换

// 隐式转换:小类型 → 大类型(安全)
int i = 42;
double d = i;    // int → double,值不变

// 隐式转换:大类型 → 小类型(可能丢失数据)
double pi = 3.14159;
int n = pi;      // double → int,n = 3(小数部分被截断)

// 显式转换(强制类型转换)
double result = (double)1 / 2;  // 0.5(而非整数除法的0)

6. 常量与字面量

6.1 字面量

字面量是源代码中直接写出的固定值:

42          // 整型字面量
3.14        // 浮点型字面量(默认double)
3.14f       // 浮点型字面量(float)
'A'         // 字符字面量
"Hello"     // 字符串字面量
true        // 布尔字面量

不同进制的整型字面量:

int dec = 255;      // 十进制
int oct = 0377;     // 八进制(前缀0)
int hex = 0xFF;     // 十六进制(前缀0x)
int bin = 0b11111111; // 二进制(C23标准,前缀0b)

6.2 常量

常量是程序运行期间不可修改的值:

// 方式1: const 关键字(推荐)
const double PI = 3.14159265;
const int MAX_STUDENTS = 50;

// 方式2: 宏定义(C语言传统方式)
#define PI 3.14159265
#define MAX_STUDENTS 50

// 区别:
// const: 有类型检查,占用内存,调试时可查看
// #define: 无类型检查,文本替换,调试时不可见
// 枚举常量
enum Color {
    RED,     // 0
    GREEN,   // 1
    BLUE     // 2
};

enum Weekday {
    MON = 1,
    TUE = 2,
    WED = 3,
    THU = 4,
    FRI = 5,
    SAT = 6,
    SUN = 7
};

7. 运算符优先级与结合性

7.1 常用运算符

运算符示例
算术+ - * / %a + b, x % 3
自增自减++ —i++, --j
关系> < >= <= == !=a > b, x == 0
逻辑&& || !a && b, !flag
位运算& | ^ ~ << >>a & 0xFF
赋值= += -= *= /= %=x += 1
条件? :a > b ? a : b
逗号,a = 1, b = 2

7.2 优先级表(从高到低)

优先级运算符结合性说明
1() [] -> .左→右最高优先级
2! ~ ++ — + - * &右→左单目运算符
3* / %左→右乘除取余
4+ -左→右加减
5<< >>左→右移位
6< <= > >=左→右关系
7== !=左→右相等性
8&左→右按位与
9^左→右按位异或
10|左→右按位或
11&&左→右逻辑与
12||左→右逻辑或
13? :右→左条件
14= += -= *= /= %= 等右→左赋值
15,左→右逗号

记忆口诀:单目(2) > 算术(3-4) > 移位(5) > 关系(6-7) > 位运算(8-10) > 逻辑(11-12) > 条件(13) > 赋值(14) > 逗号(15)

7.3 易混淆的优先级陷阱

// 陷阱1: & 优先级低于 ==
int flags = 5;
if (flags & 0x1 == 1) { }   // 错!等价于 flags & (0x1 == 1)
if ((flags & 0x1) == 1) { } // 对!先位与再比较

// 陷阱2: * 优先级高于 +
int a = 2, b = 3, c = 4;
int result = a + b * c;      // 2 + 12 = 14,不是 5 * 4 = 20

// 陷阱3: ++ 优先级高于 *
int arr[] = {10, 20, 30};
int *p = arr;
int val = *p++;   // 先取 *p (=10),再 p++。val = 10
// vs
int val2 = (*p)++; // 先取 *p,再 (*p)++。val2 = 10, arr[0] = 11

8. 表达式求值与短路求值

8.1 表达式求值

表达式由运算符和操作数组成,求值时遵循优先级和结合性规则:

int a = 2, b = 3, c = 4;

// 步骤分解: a + b * c - a / b
// 1. b * c = 12      (* 优先级高于 +)
// 2. a / b = 0       (/ 优先级高于 +,整数除法 2/3=0)
// 3. a + 12 = 14     (从左到右)
// 4. 14 - 0 = 14     (最终结果)

8.2 短路求值

逻辑运算符 &&|| 具有短路求值特性:当结果已经可以确定时,不再计算后续表达式。

逻辑与(&&)的短路:

// 如果第一个条件为假,整个表达式必为假,不再计算第二个条件
int x = 0;
if (x != 0 && 10 / x > 1) {   // x != 0 为假,10/x 不会执行
    printf("不会执行\n");       // 避免了除零错误
}

逻辑或(||)的短路:

// 如果第一个条件为真,整个表达式必为真,不再计算第二个条件
int* ptr = NULL;
if (ptr == NULL || *ptr > 0) {  // ptr == NULL 为真,*ptr 不会执行
    printf("指针为空\n");        // 避免了空指针解引用
}

8.3 短路求值的实际应用

// 应用1: 安全地访问可能为空的指针
if (ptr != NULL && ptr->value > 0) {
    // 只有ptr非空时才访问ptr->value
}

// 应用2: 数组越界保护
if (index >= 0 && index < size && arr[index] == target) {
    // 先检查范围,再访问数组
}

// 应用3: 简洁的条件赋值
// 如果文件打开失败,不执行读取
FILE* fp = fopen("data.txt", "r");
if (fp && fscanf(fp, "%d", &value) == 1) {
    printf("读取成功: %d\n", value);
}

8.4 注意:避免在短路表达式中使用副作用

int i = 0;

// 危险!如果 a > 0 为真,i++ 不会执行
if (a > 0 || i++) {
    // i 的值取决于 a > 0 的结果
}

// 安全写法:将副作用分离
i++;
if (a > 0 || i > 1) {
    // 行为可预测
}

8.5 逗号表达式

逗号运算符按从左到右顺序依次求值,整个表达式的值是最后一个子表达式的值:

int a, b, c;
c = (a = 1, b = 2, a + b);  // a=1, b=2, c=3

// 常用于 for 循环
for (int i = 0, j = 10; i < j; i++, j--) {
    printf("i=%d, j=%d\n", i, j);
}

9. 小结

| 主题 | 核心要点 | | ------------ | ---------------------------------------------- | --- | -------------------- | | 流程 | 起止框/处理框/判断框/输入输出框/流程线 | | 控制结构 | 顺序、选择(if/switch)、循环(while/for) | | 编译与解释 | 编译一次执行多次 vs 边解释边执行 | | 变量命名 | 见名知义,统一风格,避免缩写 | | 数据型 | 整型/浮点型/字符型/布尔型,注意范围和转换 | | 常量与字面量 | const(推荐)vs #define,枚举常量 | | 运算符优先级 | 单目 > 算术 > 关系 > 逻辑 > 赋值,有疑问加括号 | | 短路求值 | && 遇假即停, | | 遇真即停,注意副作用 |

掌握程序设计基础是编写正确代码的前提。优先级记不清时就加括号,短路求值要善用但不要滥用副作用。