Bootstrap

谭浩强C语言程序设计(第五版)知识点总结(1)

第一章  程序设计和C语言

1.1 什么是计算机程序

        程序的定义:程序是一组计算机能识别和执行的指令,每条指令对应一个特定的操作。

1.2 什么是计算机语言

1、计算机语言发展三阶段及特点对比

维度机器语言(低级语言)汇编语言(低级语言)高级语言
表现形式二进制代码(0/1组合)助记符(如ADD/SUB)自然语言+数学表达式(如PRINT*语句)
硬件依赖性完全依赖特定机器强依赖特定机器弱依赖,跨平台
执行效率最高(直接执行)较高(一对一转换)相对较低(一对多转换)
开发效率极低(需手工穿孔)低(需记忆符号)高(贴近人类思维)
可维护性最差(难以阅读修改)较差(需专业知识)良好(结构清晰)
转换程序无(直接执行)汇编程序编译程序
典型应用早期计算机程序硬件驱动、嵌入式系统通用软件开发

2. 语言分类标准对比

分类维度类型特点代表语言
抽象级别低级语言直接操作硬件,执行效率高,开发效率低机器语言、汇编语言
高级语言贴近人类语言,跨平台,开发效率高FORTRAN、C、Java
编程范式结构化语言基于过程,强调顺序/选择/循环结构C、FORTRAN 77
面向对象语言基于对象,强调封装/继承/多态C++、Java、Python
执行方式编译型语言需编译为机器码后执行C、C++
解释型语言逐行解释执行Python、JavaScript

3. 程序设计方法演进

方法核心思想特点代表语言
非结构化编程无严格流程控制随意使用goto语句,程序可读性差早期BASIC、FORTRAN
结构化编程三大基本结构控制流程禁止goto,代码模块化,易于维护C、Pascal
面向对象编程以对象为基本单位封装数据与操作,支持继承和多态,适合大规模程序C++、Java

4. 关键转换程序对比

转换程序输入语言输出形式转换方式示例
汇编程序汇编语言机器指令一对一转换ADD A,B → 1011011000000000
编译程序高级语言(源程序)目标程序(机器码)整体编译后执行C语言编译为.exe文件
解释程序高级语言(脚本语言)逐行翻译并执行逐行解释不生成目标程序Python解释执行

5. 程序执行流程对比

流程类型步骤特点
编译执行源程序 → 编译 → 目标程序 → 执行执行效率高,需提前编译,跨平台性差
解释执行源程序 → 逐行解释并执行灵活调试,跨平台性强,执行效率较低

6. 语言特性对比

特性机器语言汇编语言高级语言
执行效率最高较高较低
开发效率最低最高
可移植性
学习成本极高

 1.3 C语言的发展和特点

1. 简洁性与灵活性:仅37个关键字、9种控制语句;程序结构自由,多用小写字母;内核精简,无直接I/O语句,依赖库函数实现功能。
2. 运算符丰富性:34种运算符,包含位运算、赋值、类型转换等,支持复杂运算(如自增/自减、逗号表达式)。
3. 数据类型多样性:整型、浮点型、指针、结构体、共用体等;C99新增布尔型、超长整型等;指针为核心,支持链表、栈等数据结构。
4. 结构化编程:支持if-elseswitchwhilefor等控制语句;以函数为模块单位,实现模块化设计。
5. 语法自由度大:不强制检查数组越界;变量类型灵活(如整型与字符型通用);依赖程序员保证正确性。
6. 底层操作能力:可直接访问物理地址、进行位操作,兼具高级语言与汇编特性,适用于系统软件开发。
7. 可移植性高:编译系统简洁,标准库可跨平台移植,源代码无需修改。
8. 高效性:生成的目标代码质量高,执行效率接近汇编语言。

 1.4 最简单的C语言程序

知识点详细解释对应示例与代码片段
1. 主函数结构定义: C程序必须包含main函数作为入口,其类型为int,表示返回整型值。
返回值return 0表示程序正常结束,虽不强制检查但需符合规范。
函数体: 由{}包裹,语句以;结尾。
例1.1
int main() {
printf("This is a C program.\n");
return 0;
}
2. 预处理指令作用: 在编译前插入头文件内容(如stdio.h),提供库函数支持。
语法#include <文件名>,需置于程序开头。
依赖关系: 若未包含stdio.hprintfscanf将无法使用。
例1.1~1.3
#include <stdio.h>
3. printf函数功能: 格式化输出,支持占位符(如%d)和转义符(如\n)。
参数结构printf("格式字符串", 变量)
占位符替换: 如%d被变量值替换,\n换行。
例1.1
printf("This is a C program.\n");
例1.2
printf("sum is %d\n", sum);
4. scanf函数功能: 格式化输入,需用&获取变量地址。
语法scanf("格式符", &变量),如%d对应整型。
注意事项: 输入格式需与代码匹配(例1.3中%d,%d要求逗号分隔输入)。
例1.3
scanf("%d,%d", &a, &b);
5. 变量与赋值声明: 需指定类型(如int a, b, sum;)。
赋值: 通过=运算符(如a=123;)。
运算: 支持算术表达式(如sum=a+b;)。
例1.2
int a, b, sum;
a=123; b=456; sum=a+b;
6. 函数定义与调用定义语法返回类型 函数名(形参列表) { ... }
调用过程: 实参传递给形参(值传递),执行函数体后返回结果。
前置声明: 若函数定义在调用后,需提前声明(如int max(int x, int y);)。
例1.3
int max(int x, int y) { ... }
c = max(a, b);
7. 控制结构if-else逻辑: 根据条件选择执行分支,条件为真执行if块,否则执行else块。
返回值控制: 函数内通过return返回结果(如return z;)。
例1.3
if (x>y) z=x;
else z=y;
return(z);
8. 注释语法单行注释//(C99标准支持)。
多行注释/* ... */(C89标准兼容)。
特殊案例: 注释中的符号(如///* */)若在字符串内则原样输出。
例1.1注释
//这是编译预处理指令
例1.3注释
/*若x>y成立,将x的值赋给z*/
9. 编译器特性编译顺序: 自顶向下编译,函数调用前需声明。
返回值处理main函数的return 0可被操作系统捕获,非必须但推荐保留。
例1.3分析
max定义在main之后,需前置声明int max(int x, int y);,否则编译报错。
10. 输入输出细节格式控制printf%d对应整型,scanf%d严格匹配输入类型。
换行符影响\n控制输出换行,无\n则后续输出紧接当前行。
例1.1输出
This is a C program.后换行。
例1.2输出
sum is 579后换行。

知识点分类详细解释对应代码示例/教材引用
1. 源程序文件组成一个C程序由一个或多个源程序文件组成,每个文件包含:
① 预处理指令(如#include
② 全局声明(函数外的变量声明)
③ 函数定义(如main和其他函数)
例1.3
#include <stdio.h>(预处理)
int max(int x, int y);(全局声明)
int main() { ... }(函数定义)
2. 全局与局部变量全局变量:在函数外声明,整个源文件有效。
局部变量:在函数内声明,仅函数内有效。
未使用全局变量的示例见第7章
例1.2局部变量
int a, b, sum;(声明在main函数内)
3. 函数的作用- C程序由函数构成,main函数为唯一入口。
- 函数分为库函数(如printf)和用户自定义函数(如max)。
- 模块化设计通过多源文件实现,便于编译调试。
例1.3模块化
main调用max函数,函数定义在同一源文件。
4. 函数结构函数包含两部分:
① 函数首部返回类型 函数名(参数类型 参数名)
② 函数体
- 声明部分(变量/函数声明)
- 执行部分(操作语句)
例1.3函数定义
int max(int x, int y) { ... }
函数体内含if-else逻辑和return
5. 程序执行顺序程序始终从main函数开始执行,无论其在文件中的位置(如可置于文件末尾)。例1.1~1.3均以main函数为起点。
6. 语句与分号规则- 操作由C语句实现(如赋值、I/O)。
分号必要性:每条语句必须以分号结尾。
书写自由性:允许一行多语句或一语句多行,但需保证可读性。
例1.2语句
sum = a + b;(分号结尾)
7. 输入输出实现C语言通过库函数(如scanf/printf)实现I/O,不直接提供I/O语句,增强可移植性。例1.1输出
printf("This is a C program.\n");
8. 注释的重要性注释(///* */)用于提高代码可读性,推荐在关键逻辑处添加。教材说明
//这是编译预处理指令(例1.1注释)

1.5 运行C语言程序的步骤和方法

流程阶段详细步骤与工具输入/输出文件
1. 编辑源程序操作:使用IDE(如VS2010)或文本编辑器编写代码,保存为.c文件。
工具:Visual Studio、Code::Blocks
输入:键盘输入的代码
输出:f.c源文件
2. 编译预处理操作:预处理器执行#include指令,替换头文件内容。
工具:预编译器(如cpp
输入:f.c
中间文件:预处理后的临时文件
3. 正式编译操作:编译器检查语法错误,生成目标文件(二进制代码)。
工具:GCC、Clang、MSVC
输入:预处理后的文件
输出:f.obj (Windows)或f.o(Linux)
4. 连接处理操作:链接器合并目标文件与库函数,生成可执行程序。
工具:Linker(如ld或VS的链接器)
输入:f.obj+ 库文件
输出:f.exe (Windows)或a.out (Linux)
5. 运行程序操作:执行可执行文件,验证输出结果。
工具:操作系统命令行或IDE内置终端
输入:f.exe
输出:控制台显示结果

 第二章 算法——程序的灵魂

第三章 最简单的C程序设计——顺序程序设计

3.2 数据的表现形式以及运算

知识点分类详细解释与代码示例注意事项与扩展分析
1. 变量定义与初始化例3.1float f = 64.0, c;
例3.2float p0=1000, r1=0.0036;
作用:声明变量类型并赋初值,明确数据存储形式。
精度警告:VC++会将float视为双精度,可能提示精度损失,但不影响结果(GCC无此警告)。
- 建议:需高精度时使用double
2. 算术表达式计算例3.1公式c = (5.0/9) * (f - 32);
例3.2公式p3 = p0*(1 + r3/2)^2
关键:运算符优先级与类型转换(如5.0/9避免整除误差)。
浮点数陷阱:若写成5/9结果为0,需显式使用浮点常量(如5.0)。
- 幂运算需手动展开(C语言无^运算符)。
3. 输入输出控制例3.1输出printf("f=%f, c=%f\n", f, c);
例3.2输出printf("p1=%f\np2=%f\np3=%f\n", p1, p2, p3);
格式符%f默认保留6位小数。
换行符\n控制输出格式,增强可读性。
- 扩展:%.2f可限制小数位(如17.78)。
4. 顺序结构特性执行流程:按代码书写顺序逐行执行,无分支或循环。
适用场景:公式计算、数据转换等线性问题。
调试要点:可通过插入printf中间变量验证计算步骤(如检查f-32结果)。
5. 程序调试与警告VC++警告:双精度常量赋值给float变量时提示精度损失。
GCC无警告:默认兼容性更高。
解决方案:显式类型转换(如float f = 64.0f;)或改用double
- 实践建议:关注警告信息,避免隐式错误。

 3.2.1常量和变量

一、常量与变量
分类定义与特点示例与注意事项
常量程序运行中不可改变的值,分为字面常量(直接量)与符号常量(宏定义)。- 字面常量:53.14'A'"Hello"
- 符号常量:#define PI 3.1415(预编译替换,无类型、不占内存)
变量程序运行中可改变的值,需声明类型并分配存储空间。int a = 10;
float price = 99.9;
注意:变量名需符合标识符规则,区分大小写。
二、常量类型详解

类型表示形式与规则示例与常见错误
整型常量十进制整数(正负均可),无小数点。123-456
错误12,345(逗号非法)
实型常量1. 小数形式:必须含小数点(整数部分或小数部分可为0)
2. 指数形式aEn(a为基数,n为整数指数)
1. 123.450.78
2. 1.23e5(=123000)
错误e512e3.5(指数必须为整数)
字符常量单引号括起的单个字符,存储ASCII码值。'A'(ASCII 65)
错误'AB'(多字符非法)
字符串常量双引号括起的字符序列,末尾自动添加\0表示结束。"Hello"(存储为H,e,l,l,o,\0
注意"A"'A'占用内存不同(字符串多\0
符号常量使用#define定义,预编译时替换为字面值。#define MAX 100
优点:一改全改、见名知义;缺点:无类型检查,不分配存储空间。
三、常变量与符号常量对比
特性符号常量(#define)常变量(const)
定义方式预编译指令,无分号变量声明,需指定类型和const关键字
存储空间不占用内存,仅文本替换占用内存,具有固定地址
类型检查无类型,替换后可能引发类型错误有明确类型(如const float pi=3.1415;
作用域从定义处到文件结束,或使用#undef取消遵循变量作用域规则(如局部、全局)
兼容性所有C编译器支持C99及以上支持,旧编译器可能不兼容
典型用例全局常量(如数学常数、配置参数)函数内常量(如循环边界、临时计算值)
 四、标识符命名规则
规则合法示例非法示例注意事项
1. 由字母、数字、下划线组成sum_totalStudent13DPrintuser-name首字符必须为字母或下划线
2. 区分大小写sum ≠ Sum ≠ SUMClassclass为不同变量建议变量名全小写,常量名全大写
3. 不可使用关键字intfloat为关键字,不可用作标识符charreturnC语言共有32个关键字(如iffor
4. 长度限制一般支持至少31个有效字符超长部分可能被截断(如this_is_a_very_long_variable_name建议简洁且见名知义(如total_score优于ts
5. 避免歧义性命名student_countmax_valuea1temp推荐使用小写+下划线(蛇形命名法)或驼峰命名法(如studentName

 3.2.2 数据类型

一、C语言数据类型分类与特点
大类子类与典型类型核心特点
基本类型整型charshortintlonglong long
浮点型floatdouble
布尔型_Bool(C99)
- 整型:精确计算,无误差
- 浮点型:近似值,科学计算
- 布尔型:逻辑判断(true/false
枚举类型enum用户自定义整数常量集合(如enum Week {Mon, Tue...};),增强代码可读性。
空类型void表示“无类型”,用于函数无返回值或通用指针(如void*)。
指针类型*(如int*char*存储内存地址,支持动态内存管理与复杂数据结构(如链表、树)。
派生类型数组int arr[5]
结构体struct
共用体union
函数类型int func()
- 数组:同类型数据集合
- 结构体:异构数据封装
- 共用体:内存共享(节省空间)
- 函数类型:描述函数接口

二、数据类型的核心作用
作用具体表现示例与意义
内存分配类型决定变量占用的内存大小(如char占1字节,double占8字节)。优化内存使用(如嵌入式系统中优先选择short而非int)。
运算规则类型决定支持的运算(如浮点型支持小数运算,指针支持地址运算)。避免非法操作(如对void*指针直接算术运算需显式转换)。
数据表示精度浮点型精度有限(如float仅6~7位有效数字),整型无误差但范围受限。科学计算需用double,财务计算可能需高精度库(如GMP)。
类型安全检查编译器检查类型匹配(如int a = "hello";会报错)。减少运行时错误(如误将字符串赋给整型变量)。

三、常见类型的内存占用(以Visual C++为例)
类型字节数取值范围/精度典型用途
char1-128~127 或 0~255ASCII字符、小型整数存储
int4-2,147,483,648 ~ 2,147,483,647通用整数运算(循环计数、数组索引)
float4约6~7位有效数字,范围±3.4e383D图形坐标、一般科学计算
double8约15~16位有效数字,范围±1.8e308高精度计算(如数值分析、物理仿真)
long long8-9×10¹⁸ ~ 9×10¹⁸大整数存储(如时间戳、金融计算)
void*4/8地址空间(32位系统4字节,64位系统8字节)通用指针、动态内存管理

 3.2.3 整型数据

一、整型分类与存储方式
类型分类关键字形式字节数(Visual C++)数值范围存储方式与特性
基本整型(int)int / signed int4有符号:-2,147,483,648 ~ 2,147,483,647
无符号:0 ~ 4,294,967,295
存储补码形式(正数原码=补码;负数补码=原码取反+1),最高位为符号位(0正1负)。
短整型(short)short / signed short2有符号:-32,768 ~ 32,767
无符号:0 ~ 65,535
int存储方式相同,但空间减半,适用于内存敏感场景。
长整型(long)long / signed long4有符号:-2,147,483,648 ~ 2,147,483,647
无符号:0 ~ 4,294,967,295
int在Visual C++中字节数相同,但部分系统可能分配8字节(如Linux 64位)。
双长整型(C99新增)long long / signed long long8有符号:-9×10¹⁸ ~ 9×10¹⁸
无符号:0 ~ 1.8×10¹⁹
支持超大整数运算,适用于金融、时间戳等场景。补码存储规则与其他整型一致。
二、补码存储机制详解
数值示例存储步骤二进制表示(以2字节为例)
正数(+5)直接存储原码的二进制形式。0000 0000 0000 0101(符号位0,数值位5)
负数(-5)1. 取绝对值原码(5的二进制)
2. 按位取反
3. 加1得到补码
原码:0000 0000 0000 0101
取反:1111 1111 1111 1010
加1后补码:1111 1111 1111 1011
符号位作用最高位为符号位(0正1负),其余位为数值位。示例:1xxx xxxx xxxx xxxx表示负数,0xxx xxxx xxxx xxxx表示正数。

三、有符号与无符号整型对比
对比维度有符号整型(signed)无符号整型(unsigned)
符号位最高位为符号位(0正1负)无符号位,全部位表示数值
数值范围(2字节)-32,768 ~ 32,7670 ~ 65,535
溢出行为正溢出变为负数,负溢出变为正数(循环)溢出时从0重新开始(循环)
典型用途需要表示正负数的场景(如温度、坐标)仅需非负数的场景(如计数器、数组索引)

 3.2.4 字符型数据

一、字符型数据基础
分类描述示例与说明
字符与ASCII代码字符以整数形式(ASCII代码)存储,C99将其归类为整型的一种。'A'→65(二进制1000001
'a'→97(二进制1100001
'1'→49(二进制0110001
ASCII字符集范围基本集包含127个字符,用7位二进制表示,存储时占用1字节(8位),最高位固定为0。所有ASCII字符的二进制范围为00000000~01111111(0~127)。
字符分类分为字母、数字、专用符号、空格符、不可显示字符(转义字符)。专用符号:如!#&等29个符号
转义字符:如\n(换行,ASCII 10)、\0(空字符,ASCII 0)。
二、字符存储与编码
存储特性说明示例(以1字节存储)
7位编码机制ASCII码仅需7位,存储时占用1字节(8位),最高位补0。'a'存储为01100001(十进制97)
字符与整数存储差异字符以ASCII码存储(1字节),整数以补码存储(2/4字节)。'1'→ASCII码49(二进制00110001
- 整数1→补码00000000 00000001(2字节)
运算差异字符运算基于ASCII码值,而非实际数值。'1' + '1' = 49 + 49 = 98(对应字符'b'),而非整数2。

三、字符变量与操作
操作类型语法与规则示例与输出
变量定义使用char关键字定义,可赋值为字符或0~127的整数。char c = '?';(等价于char c = 63;
输入输出通过格式符%c(字符)或%d(十进制ASCII码)控制输出形式。printf("%d %c", c, c);→输出63 ?
符号修饰可添加signedunsigned修饰符,影响取值范围。signed char:-128~127
unsigned char:0~255

四、有符号与无符号字符型对比
对比项signed charunsigned char
字节数1字节1字节
取值范围-128 ~ 127(-2⁷ ~ 2⁷-1)0 ~ 255(0 ~ 2⁸-1)
典型用途需要表示正负ASCII扩展字符(如某些系统字符)处理非负数据(如原始字节流、图像像素值)
溢出行为正溢出变为负数,负溢出变为正数(循环)溢出时从0重新开始(循环)

 3.2.5 浮点型数据

一、浮点型数据基础
分类核心定义与特性示例与说明
浮点数名称由来实数以指数形式存储,小数点位置可浮动(通过调整指数值保持数值不变)。如 3.14159 可表示为 3.14159×10⁰ 或 0.0314159×10²,通过指数调整实现小数点“浮动”。
浮点型分类包括 float(单精度)、double(双精度)、long double(长双精度)。float:4字节,6位有效数字
double:8字节,15位有效数字
long double:16字节(VC++中8字节),19位有效数字。
二、存储结构与精度
存储特性说明二进制存储示意图(替代原图3.11)
规范化二进制指数形式浮点数分为小数部分(尾数)和指数部分
- 尾数:二进制小数,首位隐含为1(规范化)
- 指数:2的幂次偏移表示(如IEEE754标准)。
float 存储结构(32位):
1位符号位 + 8位指数(偏移量127) + 23位尾数
示例:3.14159 存储为符号位0,指数偏移10000000,尾数10010010000111111001111
精度与范围关系尾数位数决定有效数字(精度)
指数位数决定数值范围。
float:23位尾数→6位十进制精度
double:52位尾数→15位十进制精度。

三、浮点型分类对比(Visual C++环境)
类型字节数有效数字数值范围(绝对值)典型应用场景
float461.2×10⁻³⁸ ~ 3.4×10³⁸图形处理、低精度传感器数据
double8152.3×10⁻³⁰⁸ ~ 1.7×10³⁰⁸科学计算、金融建模、高精度算法
long double8(VC++)
16(Turbo C)
193.4×10⁻⁴⁹³² ~ 1.1×10⁴⁹³²数学分析、高精度工程仿真(需注意编译器兼容性)
四、关键特性与注意事项
特性规则与风险解决方案
运算类型提升float 参与运算时自动提升为 double(精度更高)。避免混合类型运算,如 float a = 0.1; double b = a;(隐式转换可能导致误差累积)。
精度丢失风险二进制无法精确表示某些十进制小数(如 0.1),导致舍入误差。使用高精度类型(double 或 long double),或引入误差容忍机制(如 if(abs(a-b) < 1e-6))。
极小值存储限制float 无法存储绝对值小于 1.2×10⁻³⁸ 的数(如 1e-40)。改用 double 或科学计数法表示(如 1e-40 存为 1.0×10⁻40)。
编译器差异long double 字节数因编译器而异(VC++ 8字节,Turbo C 16字节)。跨平台代码需显式声明类型长度(如使用 stdint.h 中的固定宽度类型)。

 3.2.6 怎样确定常量的类型

略。

3.3 运算符和表达式

3.3.1 C运算符

一、运算符基础分类与功能概览
运算符类别包含运算符核心功能与运算逻辑典型应用场景
算术运算符+ - * / % ++ --数值计算(加减乘除、取余)、单目自增/自减操作int a = (b + c) * 2;
i++;(循环计数器)
关系运算符> < == >= <= !=比较操作数大小或相等性,返回布尔值(0或1)if (score >= 60)(条件判断)
逻辑运算符`! &&`
位运算符`<< >> ~^ &`直接操作二进制位:移位、取反、位或、位异或、位与
赋值运算符`= += -= *= /= %= &== ^= <<= >>=`赋值与复合运算(先计算后赋值)
二、特殊用途运算符深度解析
运算符类型符号与语法核心特性与规则代码示例与说明
条件运算符?:三目运算:条件 ? 表达式1 : 表达式2(条件为真取表达式1,否则取表达式2)max = (a > b) ? a : b;(替代简单if-else)
逗号运算符,从左到右依次执行表达式,最终结果为最右侧表达式的值int x = (a=3, b=5, a+b); → x=8(多操作串联)
指针运算符* &*:解引用指针
&:取变量地址
int *p = &a;
*p = 10;(通过指针修改变量)
成员访问运算符. ->.:结构体/联合体成员访问
->:通过指针访问结构体成员
student.name<brptr->age (链表操作)
下标运算符[]数组元素访问(等价于指针算术运算:arr[i] ≡ *(arr + i)matrix[2][3] = 10;(二维数组操作)
三、编译时与类型操作关键运算符
运算符类型语法形式功能与底层实现应用场景与注意事项
求字节数运算符sizeof编译时计算操作数所占内存字节数(非函数,返回值类型为size_tmalloc(10 * sizeof(int));(动态内存分配)
sizeof arr(数组总字节数)
强制类型转换(type)显式转换数据类型(可能引发精度丢失或溢出)double d = 3.14; int i = (int)d; → i=3(截断小数)
函数调用运算符()执行函数调用(参数传递与返回值处理)printf("Hello");<brint result = func(a, b);(函数式编程基础)

3.3.2 基本的算术运算符

一、运算符分类与基础特性
运算符类型功能描述示例与运算规则注意事项
+单目/双目运算符- 单目:取正值
- 双目:加法运算
+5 → 5
3 + 2 → 5
单目运算符优先级高于双目运算符。
-单目/双目运算符- 单目:取负值
- 双目:减法运算
-5 → -5
5 - 3 → 2
单目负号可用于常量或变量前(如 -a)。
*双目运算符乘法运算3 * 2 → 6替代数学中的 ×,支持整数、浮点数混合运算。
/双目运算符除法运算(结果类型由操作数决定)5 / 2 → 2(整数除法)
5.0 / 2 → 2.5(浮点除法)
- 整数除法向零取整(如 -5/3 → -1
- 操作数含浮点数则结果为双精度。
%双目运算符求余运算(仅限整数操作数)8 % 3 → 2
-5 % 3 → -2(结果符号与被除数一致)
- 操作数必须为整数
- 结果满足 a = (a / b) * b + (a % b)

二、运算规则与底层实现
规则类型详细说明代码示例底层机制
整数除法截断规则向零取整(Truncate Toward Zero)5 / 3 → 1
-5 / 3 → -1(VC++、GCC等主流编译器)
二进制除法指令直接截断小数部分(如 x86 IDIV 指令)。
浮点数除法精度规则操作数含浮点数时自动提升为双精度计算5.0 / 2 → 2.5
5 / 2.0 → 2.5
编译器隐式转换整数为浮点数(如 int→double),使用浮点寄存器(如 x87 FPU 或 SSE)运算。
求余运算公式a % b = a - (a / b) * b(结果符号与 a 一致)-7 % 3 → -1(因 -7 = (-3)*3 + (-1)通过乘法和减法实现余数计算,依赖整数除法规则。
运算溢出处理整数溢出行为未定义(Undefined Behavior)int a = 2147483647 + 1; → 结果不可预测(32位 int 最大值溢出)编译器不检查溢出,可能产生环绕(如补码表示)或错误值。
类型隐式转换规则运算前自动进行算术提升(Arithmetic Promotion):
char/shortint
floatdouble
char c = 10; short s = 20;
c + s → int 类型结果
float f = 3.14; f + 2 → double 类型结果
编译器在生成中间代码时统一操作数类型,避免精度损失。

三、特殊场景与易错点分析
场景分类典型错误示例正确实现方式原理与规避建议
整数除法精度丢失int avg = (a + b) / 2;(若 a+b 为奇数,结果舍去小数)使用浮点运算:double avg = (a + b) / 2.0;显式引入浮点操作数触发类型提升,保留小数部分。
负数求余方向混淆-5 % 3 结果可能被误判为 1(实际为 -2 或 -1,依赖编译器)明确规则:余数符号与被除数一致(-5 % 3 → -2,因 -5 = (-2)*3 + 1避免依赖负数求余结果实现逻辑,优先使用非负操作数。
浮点比较误差if (0.1 + 0.2 == 0.3) → 条件为假使用误差范围判断:if (fabs(0.1 + 0.2 - 0.3) < 1e-6)二进制浮点数无法精确表示某些十进制小数(如 0.1),累计误差导致比较失败。
混合类型运算陷阱int a = 5; double b = 2;
int c = a / b; → 隐式截断为 2(非四舍五入)
显式四舍五入:int c = (int)(a / b + 0.5);浮点到整数的转换直接截断小数部分,需手动处理舍入。
表达式优先级误判a + b * c 被误读为 (a + b) * c明确优先级:乘法高于加法,等价于 a + (b * c)参考运算符优先级表,必要时使用括号强制顺序。
四、运算符优先级与结合性速查表
优先级运算符结合性示例解析
1+(单目) -(单目)右结合-3 + 4 → (-3) + 4 = 1
2* / %左结合5 * 3 % 2 → (5 * 3) % 2 = 1
3+(双目) -(双目)左结合5 - 3 + 2 → (5 - 3) + 2 = 4
规则说明单目运算符优先级高于双目,乘除余高于加减。复杂表达式建议使用括号明确顺序(如 (a + b) * (c - d))。

3.3.3 自增(++)、自减(--)运算

一、运算符基本规则与语法

分类语法形式功能描述示例与运算逻辑
前置自增(++i)++变量名先对变量值加1,再使用新值

int i=3;

j = ++i; // i=4 → j=4

后置自增(i++)变量名++先使用变量原值,再对变量值加1

int i=3;

j = i++; // j=3 → i=4

前置自减(--i)--变量名先对变量值减1,再使用新值

int i=3;

j = --i; // i=2 → j=2

后置自减(i--)变量名--先使用变量原值,再对变量值减1

int i=3;

j = i--; // j=3 → i=2

 

3.3.4 运算符优先级与结合性

规则类型详细说明示例
优先级单目运算符,优先级高于双目运算符(如 */),低于括号。int a = 3 * ++i; // 等价于 3 * (++i)
结合性右结合(从右向左计算)

int i=3;

int j = -i++; // 等价于 -(i++) → j=-3, i=4

操作数限制仅能作用于变量(左值),不可用于常量或表达式。

5++; // 错误

(a+b)++; // 错误

3.3.5 不同数据类型间的混合运算

 

一、混合运算类型转换规则
运算场景转换规则运算结果类型示例与说明
整型与浮点型混合运算所有 int 和 float 自动提升为 double,再进行运算。double

int i=3;

float f=2.5;

double d = i * f; // i和f转为double,结果7.5(double)

整型/浮点型与字符型运算字符型(char)自动转换为对应ASCII码的 int,再根据另一操作数类型提升为 float 或 doubledouble

char c = 'A';

double x = c + 3.14; // c转为65(int→double),结果68.14(double)

同类型运算但精度不同低精度类型自动提升为高精度类型(int → float → double)。高精度类型

float a = 3.5f;

double b = a + 2; // a转为double,结果5.5(double)

赋值时的隐式类型转换右侧表达式结果类型转换为左侧变量类型,可能丢失精度。左侧变量类型int x = 3.8; // x=3(截断小数)

 

二、表达式求值顺序与优先级
表达式示例运算步骤分解中间结果与类型最终结果
10 + 'a' + i * f - d / 31. 'a'转为ASCII码97(int)→ 10 + 97 = 107(int)
2. i * f转为double→ 3*2.5=7.5
3. 107 + 7.5 = 114.5(double)
4. d/3→ 7.5/3=2.5(double)
5. 114.5 - 2.5 = 112.0(double)
107(int)→7.5(double)→114.5→2.5→112.0112.0(double)
三、常见问题与规避建议
问题类型错误示例修正方案规避建议
精度丢失int x = 3.14; // x=3显式强制类型转换:int x = (int)3.14;避免隐式赋值转换,使用强制类型转换明确意图。
表达式歧义a = c + 10 * 0.5;添加括号明确优先级:a = (c + 10) * 0.5;复杂表达式使用括号分隔操作,避免依赖默认优先级。
字符运算溢出char c = 'Z' + 5; // 非ASCII字符使用模运算限制范围:c = ('Z' - 'A' + 5) % 26 + 'A';对字符运算结果进行范围检查(如ASCII表0~127)。
未初始化的类型转换

float f;

int i = f; // UB

初始化变量:float f = 0.0;禁止使用未初始化变量参与运算,编译器可能返回随机值。

 3.4 C语句

3.4.1 C语句的作用和分类

一、C语句总览
类别定义作用示例
控制语句用于控制程序执行流程的语句(共9种)实现条件判断、循环、跳转等功能if (x>y) max=x; else max=y;
函数调用语句由函数调用加;组成的语句执行特定函数功能(如输入输出、数学运算)printf("Hello");
表达式语句由表达式加;组成的语句完成赋值、运算等操作(任何表达式均可构成语句)a=3;x+y;
空语句仅包含;的语句占位符作用(用于循环体空操作或流程跳转目标);
复合语句{}包裹的多条语句和声明组成的代码块将多条语句合并为单条逻辑单元,常用于条件/循环体{ int a=1; printf("%d",a); }

 

二、控制语句分类详解
控制语句类型语法形式功能描述典型应用场景
条件分支(if-else)if (条件) {语句块1} else {语句块2}根据条件真假选择执行路径数值比较、状态判断
循环(for)for (初始化;条件;增量) {语句块}固定次数的循环执行遍历数组、计数操作
循环(while)while (条件) {语句块}条件满足时持续循环文件读取、动态条件循环
循环(do-while)do {语句块} while (条件);至少执行一次语句块,再进行条件判断用户输入验证、菜单交互
流程控制(break)break;跳出当前switch或循环语句提前终止循环、避免死循环
流程控制(continue)continue;跳过本次循环剩余代码,直接进入下一轮循环过滤特定数据、加速循环处理
多分支(switch)switch (表达式) {case 值: ...}根据表达式值选择不同分支执行状态机、菜单选择
函数返回(return)return 表达式;终止函数执行并返回结果函数结果传递、提前退出函数
跳转(goto)goto 标签;跳转到指定标签位置(不推荐使用)错误处理集中退出(需谨慎)

 3.4.2 最基本的语句——赋值语句

一、赋值运算符与复合赋值运算符
类别定义与规则示例注意事项
基本赋值运算符使用 = 将右侧表达式的值赋给左侧变量。a = 5;(将整数5存入变量a左侧必须为可修改的变量(左值),如 int x; x=3; 合法,5=x 非法。
复合赋值运算符在 = 前加其他运算符(如+*)构成复合运算符,简化表达式。a += 3; → a = a + 3;
x *= y+8; → x = x*(y+8);
复合运算符右侧表达式自动加括号,如 x += y+1 等价于 x = x + (y+1),而非 x = x + y +1

 

二、赋值表达式与左值/右值
类别定义与规则示例注意事项
赋值表达式由变量、赋值运算符和表达式组成,具有计算和赋值的双重功能,值为左侧变量最终值。a = 3*5;(表达式值为15,变量a值也为15)表达式可嵌套,如 a = (b=5); → a=5, b=5
链式赋值自右向左结合,多个变量连续赋值。a = b = c = 5;abc均为5)避免在链式赋值中混合不同数据类型,可能导致隐式类型转换错误。
左值 (lvalue)可出现在赋值左侧的实体,需有可寻址的存储空间(如变量)。int x; x=10;x是左值)常量(如5)和表达式(如a+b)不能作为左值。
右值 (rvalue)只能出现在赋值右侧的实体,可以是常量、变量或表达式。y = x + 5;x+5为右值)左值也可作为右值,如 z = y; 中的 y

 

三、赋值类型转换规则
转换方向规则与示例底层原理潜在风险
浮点型 → 整型舍弃小数部分,直接截断整数。
float f=3.9; int i=f; → i=3
浮点数的二进制表示直接截断为整数格式。数值超出整型范围时结果未定义(如 float f=1e10; int i=f;)。
整型 → 浮点型整数值转为浮点数,可能损失精度。
int i=123456789; float f=i; → 精度丢失
整数转换为浮点格式,超出精度时舍入。大整数转单精度浮点型时精度丢失(如int i=16777217; float f=i; → f=16777216.0)。
字符型 ↔ 整型字符ASCII码与整数值直接转换。
char c=65; → c='A'
int i='B'; → i=66
字符存储为1字节整数,赋值时直接复制内存值。字符范围(0-255)超出目标整型变量范围时可能截断。
长整型 → 短整型截断高位,保留低字节。
int i=289; char c=i; → c=33(ASCII为'!')
长整型低字节直接复制到短整型变量中。数值超出短整型范围时结果不可预测(如 int i=32768; short s=i; → s=-32768)。
double → float双精度舍入为单精度,保留6-7位有效数字。
double d=3.1415926535; float f=d; → 精度降低
64位双精度截断为32位单精度,尾数部分舍入。数值超出单精度范围时溢出(如 double d=1e40; float f=d; → 未定义)。

 

四、赋值语句与表达式区别
类别定义与语法应用场景注意事项
赋值表达式末尾无分号,可嵌入其他表达式或语句中。if ((a=b)>0) { ... }(先赋值再判断)不可在条件语句中使用赋值语句(如 if (a=b;) 错误)。
赋值语句赋值表达式加分号,独立成句。a = 3;
printf("%d", a=5);(输出5并赋值)
分号不可省略,否则编译错误。
五、变量初始化规则
初始化方式语法与示例等价操作常见错误
声明时初始化定义变量时直接赋初值。
int a=3;
float f=3.56;
int a; a=3;(分两步执行)不可链式初始化:int a=b=c=3;(需改为 int a=3, b=3, c=3;)。
部分初始化仅对部分变量赋初值。
int a, b, c=5;(仅c初始化为5)
int a, b, c; c=5;未初始化的变量值为随机数(局部变量),需显式赋值后再使用。
静态变量初始化静态变量(如全局变量)在编译时初始化。
static int x=10;
存储在静态数据区,程序启动时自动赋值。非静态局部变量初始化在运行时执行,每次函数调用重新赋值。

 3.5 数据的输入输出

3.5.2 输入输出的基本概念

一、输入输出基本概念
类别定义与规则示例/说明
输入输出本质以计算机主机为主体:
输出:主机向外部设备(如显示器、打印机)发送数据。
输入:输入设备(如键盘、扫描仪)向主机传递数据。
程序通过函数调用实现与设备的交互,如 printf 输出到屏幕,scanf 从键盘读取数据。
C语言输入输出实现C语言通过标准库函数(非语句)实现输入输出,如 printfscanfgetcharputchar 等。函数库与语言分离,提升可移植性。例如,不同编译系统可自定义输入输出函数,但通用函数(如 printf)保持一致。
二、输入函数 scanf 关键知识点
类别规则与语法示例注意事项
基本用法scanf("格式控制字符串", 变量地址列表);scanf("%lf%lf%lf", &a, &b, &c);(输入三个双精度数赋给 abc- 必须使用地址符 &(如 &a)。
- 输入数据分隔符需与格式字符串匹配(如空格分隔)。
格式控制符常用格式符:
%lf:双精度浮点数
%d:整数
%c:字符
%s:字符串
scanf("%d,%f", &x, &y);(输入 5,3.14,逗号分隔)- 格式符类型需与变量类型一致。
- 输入数据自动转换为目标类型(如输入整数 3 用 %lf 接收会转为 3.0)。
输入数据分隔输入时数据分隔符需与格式字符串中的分隔符一致:
- 空格分隔:"%lf %lf %lf" → 输入 1 3 2
- 逗号分隔:"%lf,%lf" → 输入 1.5,2.5
scanf("%d:%f", &h, &m);(输入 12:30,冒号分隔)错误示例:scanf("%d%d", &a, &b); 但输入 5,6 → 导致 a=5b 未赋值。

 

三、输出函数 printf 关键知识点
类别规则与语法示例注意事项
基本用法printf("格式控制字符串", 输出列表);printf("x1=%.2f\nx2=%.2f\n", x1, x2);(输出保留两位小数的根)- 格式符与输出项类型需匹配(如 %f 对应浮点数)。
格式修饰符宽度控制%7.2f → 输出占7列,小数2位。
对齐:默认右对齐,%-7.2f 左对齐。
printf("%-7.2f", 3.1415); → 输出 3.14 (左对齐,末尾补空格)- 宽度不足时按实际位数输出(如 %5.2f 输出 123.45 会突破5列)。
特殊字符\n:换行
\t:水平制表符(对齐输出)
\\:输出反斜杠
%%:输出百分号
printf("Name:\tAlice\nAge:\t20"); → 输出对齐的两列数据\t 通常占4或8个空格,具体取决于终端设置。

 

四、头文件与预处理指令
类别规则与语法示例/说明注意事项
头文件作用包含标准库函数的声明和宏定义,如 stdio.h 提供 printfscanf 等函数的声明。#include <stdio.h>(包含标准输入输出函数)未包含头文件会导致编译错误(如 warning: implicit declaration of function 'printf')。
#include 指令形式尖括号 < >:从系统目录查找头文件(标准库)。
双引号 " ":优先从用户目录查找,再系统目录。
#include "myheader.h"(包含用户自定义头文件)
#include <math.h>(包含数学库)
自定义头文件建议用双引号,标准库用尖括号。
预处理过程编译前将头文件内容插入源代码中,替换 #include 行。若 stdio.h 包含 printf 函数声明,预处理后程序可直接调用 printf头文件内容应为函数声明、宏定义等,避免包含可执行代码。

 

五、扩展输入输出函数
函数功能与用法示例
getchar()从标准输入读取单个字符。char c = getchar();(读取用户输入的字符)
putchar()向标准输出写入单个字符。putchar('A');(输出字符'A')
gets() 与 puts()gets(str) 读取字符串(已弃用,因缓冲区溢出风险),puts(str) 输出字符串并自动换行。char str[20]; gets(str); puts(str);(不安全,建议用 fgets 替代)

 (续)

;