
01_C语言-基础篇
本文最后更新于 2025-03-11,学习久了要注意休息哟
第一章 C语言入门基础
1.1 开发环境搭建
1.1.1 gcc
安装
略
1.1.2 gdb
安装
略
1.1.3 vscode
安装
略
1.2 基本语法元素
📌 核心三要素
1、关键字
- C语言预定义的32个保留字(不可用作标识符)
- 常用关键字速查表:
auto break case char const continue default do double else enum extern float for goto if int long register return short signed sizeof static struct switch typedef union unsigned void volatile while
- ⚠️ 易混点:
sizeof
是运算符,不是函数const
定义的是只读变量,非常量
2、标识符
- 命名规则:
- 由字母/数字/下划线组成
- 不能以数字开头(如
2num
非法) - 区分大小写(
sum
与Sum
不同)
- 行业规范:
类型 命名风格 示例 变量 小驼峰 studentAge
常量 全大写+下划线 MAX_SIZE
函数 动词+名词 calculateSum
3、注释
- 单行注释:
// 注释内容
int sum = 0; // 初始化累加器
- 多行注释:
/* 注释内容 */
/* * 函数:计算阶乘 * 参数:n - 输入整数 */
- ⚠️ 注释规范:
- 禁止嵌套多行注释(
/* /* 内层 */ */
错误) - 重要算法必须添加注释
- 避免无意义的注释(如
i++; // i加1
)
- 禁止嵌套多行注释(
4、分号
- 语句终止符:所有表达式语句必须以
;
结尾 - 常见错误:
if(a > b); // ❌ 空语句导致逻辑错误 { printf("a更大"); }
1.3 输入输出基础
🖨️ 输出函数
1、printf()
格式输出
基本格式:
printf("格式字符串", 参数列表);
格式说明符:
格式符 | 说明 | 示例 | 输出结果 |
---|---|---|---|
%d | 十进制整数 | printf("%d", 25) | 25 |
%f | 浮点数(默认6位小数) | printf("%f", 3.14) | 3.140000 |
%c | 单个字符 | printf("%c", 'A') | A |
%s | 字符串 | printf("%s", "Hello") | Hello |
%p | 指针地址 | printf("%p", &a) | 0x7ffe3b |
格式控制进阶:
printf("%-8d", 100); // 左对齐,占8位 → "100 "
printf("%08d", 100); // 补前导0 → "00000100"
printf("%.2f", 3.1415); // 保留2位小数 → "3.14"
转义字符:
转义符 | 功能 | 示例 |
---|---|---|
\n | 换行 | printf("Hello\nWorld"); |
\t | 水平制表符 | printf("Name:\tJohn"); |
\\ | 输出反斜杠 | printf("路径:C:\\"); |
%% | 输出百分号 | printf("占比:%d%%", 80); |
2、字符/ 字符串输出
// 头文件
#include <stdio.h>
// 输出字符到文件
int fputc(int c, FILE *stream);
// 输出字符串到文件
int fputs(const char *s, FILE *stream);
// 输出字符到文件
int putc(int c, FILE *stream);
// 输出字符到终端
int putchar(int c);
// 输出字符串到终端
int puts(const char *s);
⌨️ 输入函数
1、scanf()
格式输入
基本用法:
int age;
scanf("%d", &age); // 必须用&获取变量地址
多数据输入:
float height, weight;
scanf("%f%f", &height, &weight); // 输入用空格分隔
缓冲区问题:
char ch;
scanf("%c", &ch); // 可能读取到上次输入的换行符
// 解决方案:
scanf(" %c", &ch); // 添加空格跳过空白字符
输入验证:
int num;
while(1){
printf("输入1-100的数:");
if(scanf("%d", &num) == 1 && num>=1 && num<=100){
break;
}
while(getchar() != '\n'); // 清空输入缓冲区
}
2、字符/字符串输入
// 头文件
#include <stdio.h>
// 从文件中获取一个字符
int fgetc(FILE *stream);
// 从文件中获取一个字符串
char *fgets(char *s, int size, FILE *stream);
// 从终端获取一个字符
int getc(FILE *stream);
// 从终端获取一个字符
int getchar(void);
// 回退字符
int ungetc(int c, FILE *stream);
综合案例:BMI计算器
#include <stdio.h>
int main() {
float height, weight;
printf("请输入身高(米):");
scanf("%f", &height);
printf("请输入体重(千克):");
scanf("%f", &weight);
float bmi = weight / (height * height);
printf("\nBMI值:%.1f\n", bmi);
printf("====================\n");
printf("18.5以下:偏瘦\n");
printf("18.5~24:正常\n");
printf("24以上:超重\n");
return 0;
}
运行效果:
请输入身高(米):1.75
请输入体重(千克):68
BMI值:22.2
====================
18.5以下:偏瘦
18.5~24:正常
24以上:超重
🚨 常见错误诊断表
错误现象 | 原因分析 | 解决方案 |
---|---|---|
程序输出乱码 | 格式符与参数类型不匹配 | 检查%d /%f 等是否正确 |
scanf 读取错误 | 忘记& 符号 | 确保变量前加& (数组除外) |
输入字符被跳过 | 缓冲区残留换行符 | 用%*c 或getchar() 清理 |
浮点数精度显示问题 | 未指定小数位数 | 使用%.2f 格式控制 |
📚 复习要点
- 标识符命名三原则:非数字开头、无特殊符号、不重复关键字
- 注释的双刃剑:良好的注释提升可读性,过度注释增加维护成本
- 输入输出黄金法则:
printf
格式符与参数类型严格对应scanf
必须使用地址运算符&
(数组名除外)- 处理输入缓冲区防止意外错误
第二章 数据类型与运算符
2.1 基本数据类型
📌 四大基础类型详解
类型 | 字节数 | 格式符 | 取值范围/精度 | 示例 |
---|---|---|---|---|
char | 1 | %c | -128 ~ 127 或 0 ~ 255 (无符号) | 'A' '\n' 65 |
int | 4 | %d | -2,147,483,648 ~ 2,147,483,647 | 100 -5 0x1A |
float | 4 | %f | ±3.4e-38 ~ ±3.4e38(6位有效数字) | 3.14f -0.5f |
double | 8 | %lf | ±1.7e-308 ~ ±1.7e308(15位有效数字) | 3.1415926 |
🚨 特殊类型补充
_Bool (C99标准)
_Bool flag = 1; // 只能存储0或1
枚举类型
enum Week {Mon, Tue, Wed}; // Mon=0, Tue=1...
💡 内存布局演示
char c = 'A'; // 内存值:0x41
int n = 0x12345678; // 小端存储:78 56 34 12
float f = 3.14f; // IEEE754编码:0x4048f5c3
2.2 类型转换机制
🔄 隐式转换规则
-
算术运算转换
char → short → int → unsigned → long → float → double
示例:
int a = 5; double b = 3.14; double result = a + b; // a自动转为double
-
赋值转换
int n = 3.14; // n=3(截断小数部分) float f = 10; // f=10.0f
⚠️ 显式强制转换
int a = 5, b = 2;
double quotient = (double)a / b; // → 2.5
风险提示:
double d = 3.99;
int n = (int)d; // n=3(直接截断,非四舍五入)
2.3 运算符全解
📊 运算符表
运算符类别 | 运算符 |
---|---|
算术运算符 | +,-,*,/,% |
赋值运算符 | =,+=,-=,*=,/=,%= |
关系运算符 | == , ! = , > , < ,> = ,< = |
逻辑运算符 | &&,|| ,! |
位运算符 | &,|,^,~,<<,>> |
条件运算符 | ? : |
自增自减运算符 | ++,-- |
逗号运算符 | , |
指针运算符 | * & |
sizeof运算符 | sizeof |
📊 运算符优先级表
优先级 | 运算符 | 结合性 |
---|---|---|
1 | () [] . | 从左到右 |
2 | ! ~ ++ -- sizeof typeid | 从右到左 |
3 | * / % | 从左到右 |
4 | + - | 从左到右 |
5 | << >> | 从左到右 |
6 | < <= > >= | 从左到右 |
7 | == != | 从左到右 |
8 | & | 从左到右 |
9 | ^ | 从左到右 |
10 | ` | ` |
11 | && | 从左到右 |
12 | ` | |
13 | ?: | 从右到左 |
14 | = += -= *= /= %= <<= >>= &= ^= ` | =` |
15 | , | 从左到右 |
[]
()
.
:这些运算符用于数组下标、函数调用和成员访问。!
~
++
--
:逻辑非、按位取反、自增自减运算符,通常是前缀形式。\*
/
%
:乘法、除法和求余运算符,优先级相对较高。+
-
:加法和减法运算符。<<
>>
:位移运算符,处理二进制位的移位操作。&
^
|
:按位与、按位异或和按位或运算符。&&
||
:逻辑与、逻辑或运算符。?:
:三元运算符,是条件表达式的一部分。=
+=
-=
等:赋值运算符,赋值和复合赋值的操作符。
这个优先级表适用于 C 语言,能帮助理解不同运算符的计算顺序。
🛠️ 重点运算符详解
1. 算术运算符
int a = 7, b = 3;
printf("%d\n", a / b); // 2(整数除法)
printf("%f\n", 7.0 / 3); // 2.333333
printf("%d\n", a % b); // 1
2. 关系运算符
if(5 == 5.0) { ... } // 成立(值相等)
if(5 === 5.0) { ... } // ❌ C语言无===运算符
3. 逻辑运算符
短路特性:
int a = 0;
if(a != 0 && 10/a > 1) { // 避免除零错误
// 不会执行右侧判断
}
4. 位运算符
unsigned char flags = 0x0A; // 0000 1010
flags |= 0x01; // 0000 1011 → 设置最低位
flags &= ~0x08; // 0000 0011 → 清除第4位
5. 复合赋值运算符
int x = 5;
x += 3; // x=8
x <<= 1; // x=16
🚨 常见错误诊断室
错误代码 | 问题分析 | 解决方案 |
---|---|---|
int a = 3.14; | 隐式转换丢失精度 | 显式强制转换或修改变量类型 |
if(a = 5) | 赋值替代比较 | 改为if(5 == a) |
10 % 3.5 | 浮点数取模非法 | 使用fmod() 函数 |
i++ + ++i | 未定义行为 | 避免同一变量多次修改 |
📚 综合案例:单位转换器
#include <stdio.h>
int main() {
int choice;
double input;
printf("1. 英寸→厘米\n2. 磅→千克\n选择:");
scanf("%d", &choice);
if(choice == 1) {
printf("输入英寸:");
scanf("%lf", &input);
printf("%.2f英寸 = %.2f厘米\n", input, input*2.54);
} else if(choice == 2) {
printf("输入磅:");
scanf("%lf", &input);
printf("%.2f磅 = %.2f千克\n", input, input*0.4535924);
} else {
printf("无效选择!\n");
}
return 0;
}
运行效果:
1. 英寸→厘米
2. 磅→千克
选择:1
输入英寸:10
10.00英寸 = 25.40厘米
知识巩固练习
- 计算表达式
5 + 3 * 2 / (7 - 4)
的值 - 写出将变量
a
的第3位设置为1的位运算表达式 - 分析以下代码的输出:
int a = 3, b = 5; printf("%d", a++ + ++b);
答案:
5 + 3*2/3 = 5+2 = 7
a |= (1 << 2);
3 + 6 = 9
(执行后a=4, b=6)
第三章 流程控制基础
3.1 选择结构
📌 核心语法
1、单分支结构
if(条件) {
// 条件为真时执行
}
示例:
if(score >= 60) {
printf("及格!🎉");
}
2、双分支结构
if(条件) {
// 真分支
} else {
// 假分支
}
示例:
if(temperature > 30) {
printf("开启空调❄️");
} else {
printf("保持通风🌬️");
}
3、多分支结构
if(条件1) {
// 情况1
} else if(条件2) {
// 情况2
} else {
// 默认情况
}
示例:
if(score >= 90) {
grade = 'A';
} else if(score >= 70) {
grade = 'B';
} else {
grade = 'C';
}
🚨 常见错误
错误代码 | 问题分析 | 解决方案 |
---|---|---|
if(a = 5) | 赋值替代比较 | 改为if(5 == a) |
if(1 < a < 5) | 逻辑表达式错误 | 改为a>1 && a<5 |
else 匹配错误 | 未正确缩进 | 使用大括号明确作用域 |
3.2 循环结构
🔄 三大循环对比
循环类型 | 语法 | 执行特点 | 适用场景 |
---|---|---|---|
while | while(条件){...} | 先判断后执行 | 不确定循环次数 |
do-while | do{...}while(条件); | 先执行一次后判断 | 至少执行一次 |
for | for(初始化;条件;更新){...} | 精确控制循环次数 | 已知循环范围 |
💡 实战案例
1、while循环
int count = 0;
while(count < 5) {
printf("%d ", count);
count++;
}
// 输出:0 1 2 3 4
2、for循环
for(int i=0; i<5; i++) {
printf("★"); // 打印五角星
}
3、do-while循环
char choice;
do {
printf("是否继续?(Y/N): ");
scanf(" %c", &choice);
} while(choice == 'Y');
第四章 函数初步
4.1 函数定义与调用
📌 函数三要素
1、函数声明
// 声明(告诉编译器函数存在)
int add(int a, int b);
2、函数定义
// 定义(实现功能)
int add(int a, int b) {
return a + b;
}
3、函数调用
int result = add(3, 5); // result = 8
🔄 参数传递机制
-
值传递:函数内修改形参不影响实参
void swap(int a, int b) { int temp = a; a = b; b = temp; // ❌ 无法改变外部变量的值 }
4.2 常用库函数
📚 标准库速查
库文件 | 常用函数 | 功能说明 |
---|---|---|
stdio.h | printf() , scanf() | 输入输出 |
math.h | sqrt() , pow(x,y) | 数学运算 |
string.h | strlen() , strcpy() | 字符串处理 |
stdlib.h | rand() , malloc() | 随机数/内存管理 |
💡 案例:生成随机数
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
srand(time(0)); // 初始化随机种子
int num = rand() % 100; // 生成0-99的随机数
printf("随机数:%d", num);
return 0;
}
第五章 数组基础
5.1 一维数组
📌 定义与初始化
int arr1[5]; // 声明未初始化
int arr2[3] = {1, 2, 3}; // 完全初始化
int arr3[] = {1,2,3,4}; // 自动推断长度
🚨 数组越界风险
int arr[5] = {0};
arr[5] = 10; // ❌ 越界访问!可能引发段错误
🔄 数组遍历
for(int i=0; i<5; i++) {
printf("%d ", arr[i]);
}
5.2 字符数组
📌 字符串存储
char str1[] = {'H', 'e', 'l', 'l', 'o', '\0'};
char str2[] = "Hello"; // 自动添加'\0'
⚠️ 常见错误
错误代码 | 问题分析 | 解决方案 |
---|---|---|
char str[5] = "Hello"; | 长度不足(需6字节) | 改为str[6] |
str1 = str2; | 数组不能直接赋值 | 使用strcpy() |
💡 字符串操作函数
char s1[20] = "Hello";
char s2[] = "World";
strcat(s1, s2); // s1 → "HelloWorld"
int len = strlen(s1); // len = 10
综合案例:成绩统计系统
#include <stdio.h>
#define MAX 50
int main() {
int scores[MAX], sum = 0;
int n;
printf("输入学生人数:");
scanf("%d", &n);
for(int i=0; i<n; i++) {
printf("输入第%d个成绩:", i+1);
scanf("%d", &scores[i]);
sum += scores[i];
}
printf("平均分:%.2f", (float)sum / n);
return 0;
}
🚨 高频错误总结
-
循环变量越界:
for(int i=0; i<=5; i++) // 当数组大小为5时越界
-
函数未声明:
add(3,5); // ❌ 若未提前声明add函数
-
字符串未终止:
char str[5] = {'H','e','l','l','o'}; // 缺少'\0'
- 感谢你赐予我前进的力量
赞赏者名单
因为你们的支持让我意识到写文章的价值🙏
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 小道士