C语言学习笔记
一.零零碎碎
1. A、用机器语言编写的源程序就是目标程序
B、用汇编语言编写的源程序需要经过汇编程序汇编为目标程序
C、用C语言编写的源程序需要经过编译程序编译为目标程序
D、C语言与Pascal等其他高级语言的编译器是不一样的
2. A、一个 C 源程序可由一个或多个函数组成
B、一个 C 源程序必须包含一个 main 函数
C、C 程序的基本组成单位是函数
D、在 C 程序中,自定义函数的定义不能在主函数 main 体内定义
3.”程序存储思想“的提出者是John Von Neumann
4.计算机直接能识别的是二进制的代码
5. A.计算机存储的都是二进制信息,信息存储的最小单位是二进制位
B.连续8个位组成的一个字节,是内存的基本度量单位和存储单元
6.度量单位的转换
1B=8 bits
1KB=1024B=2^10B
1MB=2^10KB=2^20B
1GB=2^10MB=2^20KB=2^30B
1TB=2^10GB=2^20MB=2^30KB=2^40B
1PB=2^10TB=2^20GB=2^30MB=2^40KB=2^50B
1EB=2^10PB=2^20TB=2^30GB =2^40MB=2^50KB =2^60B
1ZB=2^10EB=2^20PB=2^30TB=2^40GB=2^50MB =2^60KB =2^70B
1YB=2^10ZB=2^20EB=2^30PB=2^40TB=2^50GB =2^60MB =2^70KB =2^80B
7.进制
(1)十六进制:1 2 3 4 5 6 7 8 9 A~10 B~11 C~12 D~13 E~14 F~15
(2)进制转换
A.N进制转十进制:“按权求和” 例(101)2 =1*2^2+0*2^1+1*2^0 =5
B. 十进制转N进制:“除N取余” 记得逆序输出余数
8. %f是针对float类型的格式符,如果代码中y是double类型。scanf中读取double类型的浮点数 应该用%lf,如果用%f会导致输入解析错误,y无法正确获取值,从而输出不确定的随机数。
9. A:外部变量(全局变量)作用域是从定义处到整个程序结束,并非 “整个程序”
B:extern是声明外部变量,不是 “重新定义”,定义只能有一次。
C:全局外部变量可在多个模块使用,extern的作用是声明该变量已在其他模块定义,不是重 新定义
D:静态外部变量(static修饰的全局变量)作用于本模块,可用于模块内数据隐藏,有实用 价值
10.优先级 char < float < short < int < double
11.C语言开发的4个步骤是:编辑、编译、链接、运(执)行
12.一般情况下,在C语言中定义但未初始化的变量的值为不确定的随机数
13.用scanf输入1个double型变量时,需要使用格式转换说明符 %lf,并且要使用取址运&算符取得该 变量的地址。
14.一个C语言程序由若干个函数组成,其中必须有一个main函数。
15.定义函数时,若缺省函数类型标识符,函数返回值类型为 int
16.书写格式自由,一条语句可以写在多行上
17.运算符不能出现在变量名上
18.
二.基本格式
每一行结束时必须加;
#include <stdio.h>
int maun()
{
return 0;
}
三.常量
一、常量的分类及定义
1. 字面常量(直接常量)
直接以字面形式出现的常量,无需声明,直接使用。
(1)整数常量(整型常量)
- 十进制:由 0-9 组成,不能以 0 开头(除 0 本身)。示例:
0、123、-456 - 八进制:以
0开头,由 0-7 组成。示例:012(对应十进制 10)、077(对应十进制 63) - 十六进制:以
0x或0X开头,由 0-9、a-f(或 A-F)组成。示例:0x1a(对应十进制 26)、0X3F(对应十进制 63) - 二进制(C99 及以上支持):以
0b或0B开头,由 0-1 组成。示例:0b101(对应十进制 5)
(2)实数常量(浮点型常量)
表示带小数的数值,有两种表示形式:
- 十进制小数形式:由整数部分、小数点、小数部分组成(整数或小数部分可省略,但小数点不能省)。示例:
3.14、0.5、5.(等价于 5.0)、.6(等价于 0.6) - 指数形式:由尾数、
e或E、指数组成(格式:尾数E指数,表示 “尾数 ×10^ 指数”)。示例:3.14e2(即 3.14×10²=314)、2.5E-3(即 2.5×10⁻³=0.0025)
注意:浮点型常量默认是
double类型,若需表示float类型,需在末尾加f或F(如3.14f)。
(3)字符常量
- 普通字符:用单引号''括起来的单个字符。示例:
'a'、'0'、'+'本质:存储的是字符对应的 ASCII 码值(整数),如'A'的 ASCII 码为 65。 - 转义字符:以反斜杠
\开头,表示特殊含义的字符(无法直接输入的字符)。常用转义字符:转义字符 含义 ASCII 码(十进制) \n换行 10 \t水平制表(Tab) 9 \'单引号 39 \"双引号 34 \\反斜杠 92 \0空字符(字符串结束符) 0
(4)字符串常量
用双引号""括起来的字符序列(可包含 0 个或多个字符)。示例:"hello"、"123"、""(空字符串)
注意:
- 字符串常量末尾会自动添加一个
\0作为结束标志(计算长度时不包含\0)。- 字符常量
'a'与字符串常量"a"不同:前者占 1 字节,后者占 2 字节('a' + '\0')。
2. 符号常量(宏定义常量)
用#define定义的常量,本质是 “替换”,在预处理阶段会被替换为对应的值。
定义格式:
#define 标识符 常量值 // 末尾无分号
例
#include <stdio.h>
#define PI 3.14159 // 定义符号常量PI
#define MAX 100 // 定义符号常量MAX
int main() {
printf("PI = %f\n", PI); // 预处理后替换为3.14159
int arr[MAX]; // 替换为int arr[100];
return 0;
}
特点:
- 标识符通常用大写字母(区分变量)。
- 无数据类型,仅做文本替换(可能存在类型隐患)。
- 作用域从定义处到文件结束(可通过
#undef终止作用域)。
3. const 修饰的常量(常变量)
用const关键字修饰的变量,其值在定义后不能被修改(具有常量属性)。
定义格式:
const 数据类型 标识符 = 常量值;
例
#include <stdio.h>
int main() {
const int a = 10; // 定义常变量a,值为10
// a = 20; // 错误:常变量的值不能修改
printf("a = %d\n", a);
return 0;
}
特点:
- 有明确的数据类型,编译器会进行类型检查。
- 本质是 “只读变量”,仍占用内存空间(与符号常量的 “替换” 不同)。
- 作用域与普通变量一致(块级、函数级等)。
二、常量的使用注意事项
-
类型匹配:常量的类型需与上下文匹配,例如:
- 整数常量默认是
int类型,超出范围会自动转为long(可加l/L显式指定long,如123L)。 - 浮点型常量默认是
double,若用于float变量需加f(如float x = 3.14f;)。
- 整数常量默认是
-
符号常量 vs const 常量:
- 符号常量(
#define)无类型,仅文本替换,可能导致意想不到的错误(如#define N 2+3,N*N会被替换为2+3*2+3)。 const常量有类型,更安全,推荐优先使用。
- 符号常量(
-
字符串常量的存储:相同的字符串常量在内存中通常只存储一份(编译器优化),例如:
char* s1 = "abc";
char* s2 = "abc";
// s1和s2指向同一块内存地址
三、总结
| 常量类型 | 定义方式 | 特点 | 示例 |
|---|---|---|---|
| 字面常量 | 直接书写 | 无标识符,直接使用 | 123、3.14、'a' |
| 符号常量 | #define 标识符 值 | 无类型,预处理替换,作用域到文件结束 | #define PI 3.14 |
| const 常量 | const 类型 标识符=值 | 有类型,只读,作用域与变量一致 | const int MAX=100 |
四.变量 (遵循 “先定义,后使用” 的原则)
一、变量的定义及初始化
1. 变量的定义
定义变量的本质是向编译器申请一块内存空间,指定其数据类型(决定空间大小和存储格式)和变量名(用于标识该空间)。
定义格式:
数据类型 变量名;
说明:
- 数据类型:决定变量的存储方式和取值范围(如
int、float、char等,详见 “数据类型补充”)。 - 变量名:需遵循标识符规则(字母、数字、下划线组成,首字符非数字,区分大小写,不使用关键字)。
示例:
int age; // 定义int型变量age(存储整数)
float score; // 定义float型变量score(存储单精度小数)
char gender; // 定义char型变量gender(存储字符)
批量定义:
同一类型的变量可同时定义,用逗号分隔:
int a, b, c; // 同时定义3个int型变量a、b、c
float x, y; // 同时定义2个float型变量x、y
2. 变量的初始化
变量定义时赋予初始值称为 “初始化”(未初始化的变量值为随机值,不可控)。
初始化格式:
数据类型 变量名 = 初始值; // 定义时直接赋值
示例:
int num = 10; // int型变量num初始化为10
float pi = 3.14f; // float型变量pi初始化为3.14(加f表示float类型,否则默认double)
char ch = 'A'; // char型变量ch初始化为字符'A'(本质是ASCII码65)
int x = 5, y = 10; // 批量定义并初始化
注意:
- 初始化与赋值的区别:
- 初始化:仅在定义时执行一次(如
int a = 5;)。 - 赋值:变量定义后修改其值(可多次执行,如
a = 10;)。
- 初始化:仅在定义时执行一次(如
- 不同类型的初始值需匹配:
- 整数不能直接赋值给
float(需隐式转换,可能丢失精度),如float f = 10;(合法,但 10 会转为 10.0f)。 - 字符变量可赋值为字符(
'A')或 ASCII 码(65),效果相同。
- 整数不能直接赋值给
数据类型补充(常用基本类型)
| 类型 | 关键字 | 占用空间(32 位系统) | 取值范围(示例) | 初始化示例 |
|---|---|---|---|---|
| 基本整型 | int | 4 字节 | -2147483648 ~ 2147483647 | int a = 100; |
| 单精度浮点型 | float | 4 字节 | ±3.4×10^-38 ~ ±3.4×10^38 | float f = 3.14f; |
| 双精度浮点型 | double | 8 字节 | ±1.7×10^-308 ~ ±1.7×10^308 | double d = 3.1415926; |
| 字符型 | char | 1 字节 | -128 ~ 127(有符号) | char ch = 'B'; 或 66; |
二、变量的输入(从键盘读取数据)
变量的输入通过标准库函数scanf()实现,功能是从键盘读取数据并存储到变量中。需包含头文件#include <stdio.h>。
1. scanf()函数格式:
scanf("格式控制字符串", &变量1, &变量2, ...);
说明:
- 格式控制字符串:包含格式占位符(指定输入数据的类型)和普通字符(需原样输入)。
&运算符:取变量的内存地址(scanf()需要知道数据存储的位置,普通变量必须加&,数组名除外)。
2. 常用格式占位符
| 变量类型 | 格式占位符 | 示例 |
|---|---|---|
int | %d | scanf("%d", &a); |
float | %f | scanf("%f", &f); |
double | %lf | scanf("%lf", &d); |
char | %c | scanf("%c", &ch); |
3. 输入示例
(1)单个变量输入:
#include <stdio.h>
int main() {
int age;
printf("请输入年龄:"); // 提示用户输入
scanf("%d", &age); // 读取整数到age
printf("你输入的年龄是:%d\n", age);
return 0;
}
(2)多个变量输入:
#include <stdio.h>
int main() {
float height, weight;
printf("请输入身高(米)和体重(kg),用空格分隔:");
// 格式字符串中的空格表示任意空白字符(空格、回车、Tab)
scanf("%f %f", &height, &weight);
printf("身高:%.2f米,体重:%.1fkg\n", height, weight);
return 0;
}
(3)带普通字符的输入:
#include <stdio.h>
int main() {
int year, month, day;
printf("请输入日期(格式:年-月-日):");
// 格式字符串中的'-'需原样输入
scanf("%d-%d-%d", &year, &month, &day);
printf("你输入的日期是:%d年%d月%d日\n", year, month, day);
return 0;
}
4. 输入注意事项
- 类型匹配:输入数据类型必须与格式占位符一致,否则会导致数据错误。例如:用
%d读取小数,会只取整数部分(如输入 3.14,变量接收 3)。 double的特殊处理:double变量必须用%lf(long float),若用%f会导致数据错误。- 空白字符处理:
scanf()会自动跳过输入中的空白字符(空格、回车、Tab),但%c除外(会读取空白字符)。例如:输入A B后用%c读取,第一个%c得到'A',第二个%c得到空格(而非'B')。解决方法:在%c前加空格跳过空白,如scanf(" %c", &ch);(格式字符串中的空格会跳过所有空白)。 - 非占位符的普通字符(如字母、符号)必须被原样输入
三、变量的输出(向屏幕打印数据)
变量的输出通过标准库函数printf()实现,功能是将变量的值按指定格式打印到屏幕。需包含头文件#include <stdio.h>。
1. printf()函数格式:
printf("格式控制字符串", 变量1, 变量2, ...);
说明:
- 格式控制字符串:包含格式占位符(指定输出数据的类型和格式)和普通字符(原样输出)。
- 变量列表:需输出的变量(无需加
&,直接写变量名)。
2. 常用格式占位符及扩展格式
| 变量类型 | 格式占位符 | 扩展格式(示例) | 说明 |
|---|---|---|---|
int | %d | %5d(占 5 位,右对齐)、%-5d(左对齐) | 控制输出宽度 |
float/double | %f | %.2f(保留 2 位小数)、%6.2f(宽 6 位,2 位小数) | 控制小数位数和总宽度 |
char | %c | %c | 输出字符(按 ASCII 码对应字符) |
| (通用) | %o/%x | %o(八进制)、%x(十六进制小写) | 整数的进制转换输出 |
3. 输出示例
(1)基本输出:运行
#include <stdio.h>
int main() {
int a = 100;
float b = 3.1415f;
char c = 'Z';
printf("整数:%d,小数:%f,字符:%c\n", a, b, c);
// 输出:整数:100,小数:3.141500,字符:Z
return 0;
}
(2)格式控制(小数位数和宽度):
#include <stdio.h>
int main() {
double pi = 3.1415926535;
// %.2f:保留2位小数;%8.2f:总宽度8位(含小数点),右对齐
printf("pi = %.2f\n", pi); // 输出:pi = 3.14
printf("pi = %8.2f\n", pi); // 输出:pi = 3.14(前面补4个空格)
return 0;
}
(3)整数进制转换:
#include <stdio.h>
int main() {
int num = 26;
printf("十进制:%d\n", num); // 输出:十进制:26
printf("八进制:%o\n", num); // 输出:八进制:32(26的八进制)
printf("十六进制:%x\n", num); // 输出:十六进制:1a(26的十六进制)
return 0;
}
4. 输出注意事项
float与double的统一:printf()中%f可同时用于float和double(float会自动转为double)。- 格式占位符与变量的对应:数量和类型必须一一对应,否则会输出乱码。例如:
printf("%d %f", a);(少一个变量)或printf("%d", b);(b是float类型)都会导致错误。 - 转义字符的使用:在格式字符串中可加入转义字符(如
\n换行、\t制表符)控制输出格式。
四、综合示例(定义、初始化、输入、输出结合)
#include <stdio.h>
int main() {
// 定义变量并部分初始化
char name[20]; // 字符数组(用于存储字符串)
int age;
float score = 0.0f; // 初始化成绩为0
// 输入数据
printf("请输入姓名:");
scanf("%s", name); // 字符串输入无需加&(数组名即地址)
printf("请输入年龄:");
scanf("%d", &age);
printf("请输入成绩:");
scanf("%f", &score);
// 输出数据
printf("\n--- 个人信息 --- \n");
printf("姓名:%s\n", name);
printf("年龄:%d岁\n", age);
printf("成绩:%.1f分\n", score); // 保留1位小数
return 0;
}
运行结果示例:
请输入姓名:张三
请输入年龄:18
请输入成绩:95.5
--- 个人信息 ---
姓名:张三
年龄:18岁
成绩:95.5分
五、总结
| 操作 | 核心函数 / 格式 | 关键注意事项 |
|---|---|---|
| 定义 | 数据类型 变量名; | 先定义后使用,变量名遵循标识符规则 |
| 初始化 | 数据类型 变量名 = 初始值; | 初始值需与类型匹配,未初始化变量值为随机值 |
| 输入 | scanf("格式", &变量); | 加&(数组除外),double用%lf,注意类型匹配 |
| 输出 | printf("格式", 变量); | 格式占位符与变量一一对应,float/double用%f |
五.转义字符
C 语言转义字符存储规则表
| 转义字符类型 | 格式示例 | 存储字节数 | 核心说明 |
|---|---|---|---|
| 普通转义字符 | '\n'、'\t'、'\\' | 1 字节 | 单个转义字符(如换行、制表符),本质是对应 ASCII 码值,存储占 1 字节。 |
| 八进制转义字符 | '\141'(对应 'a') | 1 字节 | 格式为\+1~3 位八进制数字(0-7),表示单个字符,存储占 1 字节。 |
| 十六进制转义字符 | '\x5d'(对应 ']') | 1 字节 | 格式为\x+1~2 位十六进制数字(0-9、a-f/A-F),表示单个字符,存储占 1 字节。 |
| 字符串中的转义字符 | "\\n"、"\x41" | 2 字节 | 字符串常量末尾自动加\0结束符,如"\x41"是字符 'A' + \0,共 2 字节。 |
| 空字符转义符 | '\0' | 1 字节 | ASCII 码值为 0,作为字符串结束标志,单独存储占 1 字节。 |
补充注意事项
- 转义字符无论格式多么复杂(如
\x7f),只要是 “字符常量”(单引号括起),均只占 1 字节。 - 字符串中的转义字符,字节数 = 转义字符实际代表的字符数 + 1(
\0结束符),若字符串含多个转义字符,需累加实际字符数(如"\n\t"是 2 个字符 +\0,共 3 字节)。 - 八进制转义字符最多 3 位数字,超出部分按普通字符处理(如
'\1234'中\123是转义字符,4是普通字符)。
六.带修饰符的基本数据类型的汇总表(背)
| 数据类型(带修饰符) | 关键字写法 | 占用内存大小(字节) | 取值范围 |
|---|---|---|---|
| 字符型 | |||
| 有符号字符型 | signed char | 1 | -128 ~ 127 |
| 无符号字符型 | unsigned char | 1 | 0 ~ 255 |
| 短整型 | |||
| 有符号短整型 | short / short int / signed short / signed short int | 2 | -32768 ~ 32767 |
| 无符号短整型 | unsigned short / unsigned short int | 2 | 0 ~ 65535 |
| 基本整型 | |||
| 有符号基本整型 | int / signed / signed int | 4 | -2147483648 ~ 2147483647 |
| 无符号基本整型 | unsigned / unsigned int | 4 | 0 ~ 4294967295 |
| 长整型 | |||
| 有符号长整型 | long / long int / signed long / signed long int | 4 | -2147483648 ~ 2147483647 |
| 无符号长整型 | unsigned long / unsigned long int | 4 | 0 ~ 4294967295 |
| 双长整型(C99) | VS2010 支持 long long(C99 特性) | ||
| 有符号双长整型 | long long / long long int / signed long long | 8 | -9223372036854775808 ~ 9223372036854775807 |
| 无符号双长整型 | unsigned long long / unsigned long long int | 8 | 0 ~ 18446744073709551615 |
| 浮点型 | 浮点型无 signed/unsigned 修饰符(默认有符号) | ||
| 单精度浮点型 | float | 4 | ±3.4×10^-38 ~ ±3.4×10^38(约 6~7 位有效数字) |
| 双精度浮点型 | double | 8 | ±1.7×10^-308 ~ ±1.7×10^308(约 15~17 位有效数字) |
| 长双精度浮点型 | long double | 8(VS2010 中) | 与 double 相同(±1.7×10^-308 ~ ±1.7×10^308) |
七.数据类型
C 语言允许的基本数据类型(核心考点)
-
整型(整数类型)
- 用于存储整数,包括
int(基本整型)、short(短整型)、long(长整型)等,支持unsigned(无符号)修饰。 - 是 C 语言原生支持的基础类型。
- 用于存储整数,包括
-
实型(浮点类型)
- 用于存储带小数的数据,包括
float(单精度浮点型)和double(双精度浮点型)。 - 注意:C 语言中 “实型” 即 “浮点型”,二者等价。
- 用于存储带小数的数据,包括
-
字符型(
char)- 用于存储单个字符(本质是 ASCII 码值,属于整数类型的一种)。
- 支持
unsigned char(无符号字符型)和signed char(有符号字符型)。
-
空类型(
void)- 表示 “无类型”,用于声明无返回值的函数(如
void func())、无类型指针(void*)等。 - 不能用于定义变量(无实际存储意义)。
- 表示 “无类型”,用于声明无返回值的函数(如
C 语言基础数据类型表
| 类型类别 | 具体类型 / 关键字 | 说明 |
|---|---|---|
| 基本类型 | 整型(int等) | 存储整数,支持符号修饰 |
| 基本类型 | 实型(float、double) | 存储小数,单 / 双精度之分 |
| 基本类型 | 字符型(char) | 存储字符(本质为 ASCII 码整数) |
| 特殊类型 | 空类型(void) | 表示无类型,用于函数返回值或指针 |
| 构造类型 | 结构体、数组、枚举等 | 由基本类型组合而成(非基础类型) |
| 指针类型 | 类型*(如int*) | 存储内存地址(派生类型) |
八.运算符优先级
1.优先级口诀:括号成员最高级,单目算术紧随其后,移位关系按位算,逻辑三目赋值低,逗号运算最低级。
一、最高优先级(单目运算符)
| 运算符 | 含义 | 结合性 | 示例 |
|---|---|---|---|
() | 圆括号(函数调用) | 从左到右 | (a + b) * c |
[] | 数组下标 | 从左到右 | arr[0] |
-> / . | 结构体成员访问 | 从左到右 | p->name / s.age |
++ / -- | 后缀自增 / 自减(先传递,后加加) | 从左到右 | a++ / b-- |
! | 逻辑非 | 从右到左 | !a |
~ | 按位取反 | 从右到左 | ~x |
+ / - | 正号 / 负号(单目) | 从右到左 | +3 / -5 |
++ / -- | 前缀自增 / 自减(先++,后传递) | 从右到左 | ++a / --b |
* | 指针取值 | 从右到左 | *p |
& | 取地址 | 从右到左 | &a |
sizeof | 计算类型 / 变量大小 | 从右到左 | sizeof(int) |
(类型) | 强制类型转换 | 从右到左 | (float)a |
说明:单目运算符仅对一个操作数生效,前缀自增 / 自减的优先级高于后缀(但后缀自增 / 自减的结合性更特殊)。
二、算术运算符(双目)
| 运算符 | 含义 | 结合性 | 示例 |
|---|---|---|---|
* / / / % | 乘 / 除 / 取余 | 从左到右 | a * b / c |
+ / - | 加 / 减(双目) | 从左到右 | a + b - c |
说明:
- 取余运算符
%仅用于整数,结果符号与被除数一致(如5 % 3 = 2,-5 % 3 = -2)。 - 除法
/若操作数为整数,结果自动截断小数(如5 / 2 = 2)。
三、移位运算符
| 运算符 | 含义 | 结合性 | 示例 |
|---|---|---|---|
<< | 左移 | 从左到右 | a << 2(左移 2 位) |
>> | 右移 | 从左到右 | b >> 1(右移 1 位) |
说明:移位运算针对二进制位,左移等价于乘以 2 的 n 次方,右移等价于除以 2 的 n 次方(需注意符号位处理)。
四、关系运算符
| 运算符 | 含义 | 结合性 | 示例 |
|---|---|---|---|
< / > / <= / >= | 小于 / 大于 / 小于等于 / 大于等于 | 从左到右 | a < b / c >= d |
== | 等于 | 从左到右 | a == b |
!= | 不等于 | 从左到右 | x != y |
说明:关系运算结果为整数(1表示真,0表示假),注意==(等于)与=(赋值)的区别。
若同时出现,先算==
五、按位运算符
| 运算符 | 含义 | 结合性 | 示例 |
|---|---|---|---|
& | 按位与 | 从左到右 | a & b |
^ | 按位异或 | 从左到右 | x ^ y |
| | 按位或 | 从左到右 | m | n |
说明:按位运算针对操作数的二进制位逐位计算,仅用于整数类型。
六、逻辑运算符
| 运算符 | 含义 | 结合性 | 示例 |
|---|---|---|---|
&& | 逻辑与(短路) | 从左到右 | a && b |
|| | 逻辑或(短路) | 从左到右 | x || y |
说明:
- 逻辑与
&&:左侧为假时,右侧不再执行。 - 逻辑或
\|\|:左侧为真时,右侧不再执行。
逻辑运算规则:
- 非 0 值视为 “真”(逻辑值为 1),0 视为 “假”(逻辑值为 0)。
&&(逻辑与):两边都为真则结果为真(1),否则为假(0)。||(逻辑或):两边至少一个为真则结果为真(1),否则为假(0)。!(逻辑非):真变假(0),假变真(1)
德摩根定律
德摩根定律是逻辑运算中的重要规律,适用于两种等价形式:
!(A && B) 等价于 !A || !B!(A || B) 等价于 !A && !B
简单来说:“对逻辑与的否定,等价于否定的逻辑或;对逻辑或的否定,等价于否定的逻辑与”。
七、条件运算符(三目)
| 运算符 | 含义 | 结合性 | 示例 |
|---|---|---|---|
?: | 条件运算 | 从右到左 | a > b ? a : b |
说明:格式为表达式1 ? 表达式2 : 表达式3,若表达式 1 为真则执行表达式 2,否则执行表达式 3,是唯一的三目运算符。(对取左,错取右)
八、赋值运算符
| 运算符 | 含义 | 结合性 | 示例 |
|---|---|---|---|
= | 简单赋值 | 从右到左 | a = b |
+= / -= | 加 / 减后赋值 | 从右到左 | a += 3(等价于a = a + 3) |
*= / /= / %= | 乘 / 除 / 取余后赋值 | 从右到左 | b *= 2(等价于b = b * 2) |
<<= / >>= | 左移 / 右移后赋值 | 从右到左 | c <<= 1 |
&= / ^= / |= | 按位与 / 异或 / 或后赋值 | 从右到左 | d &= 0x0f |
说明:赋值运算符优先级较低,通常最后执行,结合性为从右到左(如a = b = c等价于a = (b = c))。
九、逗号运算符
| 运算符 | 含义 | 结合性 | 示例 |
|---|---|---|---|
, | 逗号运算 | 从左到右 | a = 1, b = 2, a + b |
说明:逗号运算符优先级最低,用于分隔多个表达式,整体结果为最后一个表达式的值(如(a=1, b=2, a+b)结果为3)。
九.switch语句
switch 语句是 C 语言中用于多分支选择的流程控制语句,适用于判断条件为整型或字符型表达式的场景,比嵌套 if-else 语句更简洁高效。
一、switch 语句的基本格式
switch (表达式) {
case 常量表达式1:
语句块1;
[break;]
case 常量表达式2:
语句块2;
[break;]
...
case 常量表达式n:
语句块n;
[break;]
default:
语句块n+1;
[break;]
}
各部分说明:
-
表达式:必须是整型或字符型(包括
int、char、short、long及枚举类型等,不能是浮点型、字符串等)。示例:switch (a)、switch (ch - '0')(字符转整数)。 -
case 常量表达式:
case后必须跟常量表达式(值在编译期可确定,如5、'A'、3+2,不能是变量或函数调用)。- 多个
case的常量值不能重复(否则编译报错)。
-
break 语句:
- 用于跳出当前 switch 结构,若省略,会继续执行后续 case 的语句(称为 “穿透” 现象)。
-
default 子句:
- 可选,当所有 case 的常量值都不匹配表达式时执行。
- 位置灵活(可在任意 case 之间或末尾),若在中间,需加 break 避免穿透。
二、执行流程
- 计算
switch后表达式的值(整型或字符型)。 - 依次与各
case后的常量表达式比较,找到第一个匹配的值:- 从该 case 的语句块开始执行。
- 若遇到
break,立即跳出 switch 语句,执行后续代码。 - 若未遇到
break,会继续执行下一个 case 的语句(穿透),直到遇到 break 或 switch 结束。
- 若所有 case 都不匹配,且存在
default,则执行 default 的语句块;若没有 default,直接跳出 switch。
三、示例解析
示例 1:基本用法(带 break)
#include <stdio.h>
int main() {
int day = 3;
switch (day) {
case 1:
printf("星期一\n");
break;
case 2:
printf("星期二\n");
break;
case 3:
printf("星期三\n"); // 匹配成功,执行此句
break; // 跳出switch
case 4:
printf("星期四\n");
break;
default:
printf("其他星期\n");
}
return 0;
}
输出:星期三(执行流程:表达式day=3匹配case 3,执行打印后 break 跳出。)
示例 2:穿透现象(省略 break)
#include <stdio.h>
int main() {
char grade = 'B';
switch (grade) {
case 'A':
printf("优秀\n");
case 'B':
printf("良好\n"); // 匹配成功,执行此句
case 'C':
printf("及格\n"); // 穿透执行
default:
printf("加油\n"); // 继续穿透
}
return 0;
}
输出:
良好
及格
加油
(原因:case 'B'后无 break,导致后续 case 和 default 被依次执行。)
示例 3:利用穿透实现多 case 共享代码
#include <stdio.h>
int main() {
int month = 2;
switch (month) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
printf("31天\n"); // 1/3/5/7/8/10/12月共享此代码
break;
case 4:
case 6:
case 9:
case 11:
printf("30天\n");
break;
case 2:
printf("28或29天\n");
break;
default:
printf("无效月份\n");
}
return 0;
}
输出:28或29天(多个 case 共用一个语句块,通过穿透实现简洁逻辑。)
四、注意事项
-
表达式类型限制:
- 必须是整型或字符型(
char本质是整数),不能是浮点型(如3.14)、字符串(如"abc")。 - 错误示例:
switch (3.14)(编译报错)、switch ("abc")(编译报错)。
- 必须是整型或字符型(
-
case 常量表达式要求:
- 必须是编译期可确定的常量(如
5、'A'、宏定义常量#define NUM 10),不能是变量或函数调用。 - 错误示例:
case a(a 是变量)、case get_num()(函数调用)。
- 必须是编译期可确定的常量(如
-
break 的必要性:
- 若需每个 case 独立执行,必须加
break,否则会发生穿透(除非有意利用穿透)。 default后建议加break(即使在末尾,养成习惯可避免后续添加 case 时出错)。
- 若需每个 case 独立执行,必须加
-
case 值的唯一性:
- 多个 case 不能有相同的常量值,否则编译报错(如
case 1:和case 1:冲突)。
- 多个 case 不能有相同的常量值,否则编译报错(如
-
与 if-else 的选择:
- switch 适合判断条件为离散的整型 / 字符型值(如星期、等级)。
- if-else 适合范围判断(如
x > 10)、浮点型判断等场景,灵活性更高。
五、常见错误案例
错误 1:使用浮点型表达式
float score = 90.5;
switch (score) { // 错误:表达式不能是浮点型
case 90: printf("优秀"); break;
default: printf("其他");
}
错误 2:case 后使用变量
int num = 5;
switch (10) {
case num: printf("匹配"); break; // 错误:case后不能是变量
}
错误 3:遗漏 break 导致逻辑错误
int x = 2;
switch (x) {
case 1: printf("1");
case 2: printf("2"); // 执行此句
case 3: printf("3"); // 穿透执行,意外输出3
break;
}
// 输出:23(而非预期的2)
六、总结
| 核心要点 | 说明 |
|---|---|
| 适用场景 | 多分支选择,条件为整型 / 字符型离散值 |
| 执行逻辑 | 匹配 case 后顺序执行,遇 break 则跳出,否则穿透 |
| 关键语法 | 表达式为整型 / 字符型,case 后是常量,break 控制分支结束,default 处理默认情况 |
| 常见陷阱 | 浮点型表达式、case 用变量、遗漏 break 导致穿透 |
十.if语句
一、if 语句的三种基本形式
1. 单分支 if 语句(if)
格式:
if (表达式) {
语句块; // 表达式为真时执行
}
说明:
- 表达式:必须是逻辑表达式或关系表达式(结果为 “真”(非 0)或 “假”(0))。
- 语句块:若为单条语句,可省略
{};多条语句必须用{}包裹(建议始终加{},增强可读性)。
示例:
int a = 5;
if (a > 3) {
printf("a大于3\n"); // a=5>3为真,执行此句
}
// 输出:a大于3
2. 双分支 if 语句(if-else)
格式:
if (表达式) {
语句块1; // 表达式为真时执行
} else {
语句块2; // 表达式为假时执行
}
说明:
- 二选一执行:表达式为真则执行语句块 1,否则执行语句块 2,两者必选其一。
示例:
int score = 85;
if (score >= 60) {
printf("及格\n"); // 85>=60为真,执行此句
} else {
printf("不及格\n");
}
// 输出:及格
3. 多分支 if 语句(if-else if-else)
格式:
if (表达式1) {
语句块1; // 表达式1为真时执行
} else if (表达式2) {
语句块2; // 表达式1为假、表达式2为真时执行
} else if (表达式3) {
语句块3; // 前两个表达式为假、表达式3为真时执行
}
...
else {
语句块n; // 所有表达式为假时执行(可选)
}
说明:
- 按顺序判断:从第一个表达式开始,一旦某个表达式为真,执行对应语句块后跳出整个结构;若所有表达式为假,执行 else 语句块(若存在)。
- else 可选:若省略 else,则所有表达式为假时不执行任何语句块。
示例:
int grade = 8;
if (grade >= 9) {
printf("优秀\n");
} else if (grade >= 7) {
printf("良好\n"); // 8>=7为真,执行此句
} else if (grade >= 6) {
printf("及格\n");
} else {
printf("不及格\n");
}
// 输出:良好
二、if 语句的嵌套
if 语句内部可以包含另一个 if 语句(单分支、双分支或多分支),称为嵌套 if 语句,用于处理更复杂的条件判断。
格式示例:
if (表达式1) {
if (表达式2) {
语句块1; // 表达式1和表达式2均为真时执行
} else {
语句块2; // 表达式1为真、表达式2为假时执行
}
} else {
语句块3; // 表达式1为假时执行
}
示例:判断一个数是否为正偶数
int num = 4;
if (num > 0) { // 先判断是否为正数
if (num % 2 == 0) { // 再判断是否为偶数
printf("正偶数\n"); // 4>0且4%2==0,执行此句
} else {
printf("正奇数\n");
}
} else {
printf("非正数\n");
}
// 输出:正偶数
注意:嵌套时建议使用{}明确语句块范围,避免因缩进错误导致逻辑混乱(C 语言不依赖缩进判断结构)。
三、关键注意事项
1. 表达式的真假判断
- C 语言中,“真” 指表达式值为非 0(包括正数、负数、字符常量等),“假” 指表达式值为0。
- 示例:
if (5) { ... } // 5为非0,视为真 if (-3) { ... } // -3为非0,视为真 if ('a') { ... } // 'a'的ASCII码为97(非0),视为真 if (0) { ... } // 0为假,不执行
2. 悬空 else 问题
else 始终与最近的未配对 if结合,与缩进无关,可能导致逻辑错误。
反例:
int a = 1, b = 0;
if (a == 0)
if (b == 0)
printf("a=0且b=0\n");
else // 实际与内层if配对,而非外层if
printf("a≠0\n");
// 预期:a≠0时输出,但实际因外层if为假,不执行任何语句
解决方法:加{}明确配对关系
int a = 1, b = 0;
if (a == 0) {
if (b == 0)
printf("a=0且b=0\n");
} else { // 明确与外层if配对
printf("a≠0\n"); // 执行此句
}
// 输出:a≠0
3. 赋值运算符与等于运算符的区别
=是赋值运算符,==是等于运算符,在 if 表达式中易混淆。- 错误示例:
if (a = 5)实际是将 5 赋值给 a,表达式值为 5(真),导致逻辑错误。 - 正确写法:
if (a == 5)(判断 a 是否等于 5)。
4. 表达式的简化
- 逻辑表达式可简化,例如:
if (a != 0)可简化为if (a)(非 0 即真)。if (a == 0)可简化为if (!a)(0 的非为真)。
四、if 语句与 switch 语句的对比
| 特性 | if 语句 | switch 语句 |
|---|---|---|
| 适用场景 | 范围判断(如x > 10)、任意类型表达式 | 离散值判断(如整数、字符) |
| 条件类型 | 可处理浮点型、逻辑表达式等 | 仅支持整型或字符型表达式 |
| 灵活性 | 更高,可嵌套复杂逻辑 | 较低,仅匹配常量值 |
| 代码简洁性 | 多分支时嵌套多,代码冗长 | 多分支时更简洁,避免嵌套 |
选择建议:
- 简单范围判断或少量分支 → 用 if 语句。
- 多分支且条件为离散整型 / 字符型 → 用 switch 语句
更多推荐



所有评论(0)