C语言基础学习文档

C语言基础学习文档

目录

  1. C语言简介
  2. 开发环境搭建
  3. 基本语法
  4. 数据类型
  5. 变量和常量
  6. 运算符
  7. 控制结构
  8. 函数
  9. 数组
  10. 指针
  11. 字符串
  12. 结构体和联合体
  13. 文件操作
  14. 内存管理
  15. 预处理器
  16. 实战项目
  17. 最佳实践

C语言简介

什么是编程语言?

在学习C语言之前,我们先来理解什么是编程语言。想象一下,你想让计算机帮你做一件事情,比如计算1+1等于多少。但是计算机只能理解0和1(二进制),而我们人类习惯用自然语言交流。编程语言就像是人类和计算机之间的"翻译官",它让我们能够用接近人类思维的方式来指挥计算机工作。

什么是C语言?

C语言是一种编程语言,就像英语、中文是人类的语言一样。它由美国贝尔实验室的Dennis Ritchie在1972年发明。你可以把C语言想象成一套"指令手册",通过这套手册,我们可以告诉计算机:

  • 如何存储数据(比如记住一个人的年龄)
  • 如何处理数据(比如计算两个数的和)
  • 如何做出决定(比如判断一个人是否成年)
  • 如何重复做某件事(比如打印100遍"Hello")

为什么要学习C语言?

1. 简单易学

C语言的语法相对简单,就像学习汉语拼音一样,掌握了基本规则后就能组合出复杂的内容。

2. 基础重要

学会C语言就像学会了编程的"基本功",以后学习其他编程语言(如Java、Python)会变得容易很多。

3. 应用广泛

C语言被广泛应用在:

  • 操作系统:Windows、Linux的核心部分都是用C语言写的
  • 嵌入式设备:手机、智能家电、汽车电子系统
  • 游戏开发:很多游戏引擎使用C语言
  • 科学计算:天气预报、医学影像处理等

学习C语言需要什么基础?

答案是:几乎不需要任何编程基础!

你只需要:

  • 会使用电脑(开机、关机、打开文件)
  • 具备小学数学水平(加减乘除)
  • 有一点点逻辑思维(比如理解"如果…那么…"的概念)
  • 有耐心和坚持学习的决心

C语言学习路线图

第1周:环境搭建 + 第一个程序
第2周:变量和数据类型
第3周:运算符和表达式
第4周:条件判断(if-else)
第5周:循环(for、while)
第6周:函数基础
第7周:数组
第8周:指针入门
第9-10周:字符串处理
第11-12周:结构体和文件操作
第13-14周:综合项目实战

开发环境搭建

Windows环境

# 1. 安装MinGW-w64
# 下载地址:https://www.mingw-w64.org/

# 2. 配置环境变量
# 将MinGW的bin目录添加到PATH

# 3. 验证安装
gcc --version

Linux环境

# Ubuntu/Debian
sudo apt update
sudo apt install gcc build-essential

# CentOS/RHEL
sudo yum install gcc gcc-c++ make

# 验证安装
gcc --version

推荐IDE和编辑器

  • Code::Blocks:跨平台C/C++ IDE
  • Dev-C++:Windows下轻量级IDE
  • Visual Studio Code:配合C/C++扩展
  • CLion:JetBrains出品的专业IDE
  • Vim/Emacs:命令行编辑器

基本语法

第一个C程序 - 详细解释

让我们从最简单的程序开始。这个程序的作用是在屏幕上显示"Hello, World!":

#include 

int main() {
    printf("Hello, World!\n");
    return 0;
}
逐行解释:

第1行:#include

  • 这行代码告诉计算机:“我需要使用一些预先写好的功能”
  • stdio.h 是一个"工具箱",里面包含了输入输出功能
  • 就像你要画画时需要先准备画笔一样,要使用printf就需要先包含stdio.h
  • #include 的意思是"包含",<> 表示这是系统提供的工具箱

第3行:int main()

  • main 是"主要"的意思,这是程序的入口
  • 就像一本书的第一页,程序从这里开始执行
  • int 表示这个函数会返回一个整数
  • () 表示这是一个函数(暂时可以理解为一个"任务")

第4行:{

  • 大括号表示一个代码块的开始
  • 就像一个盒子的开口,里面装着要执行的指令

第5行:printf("Hello, World!\n");

  • printf 是"打印"的意思,用来在屏幕上显示文字
  • "Hello, World!" 是要显示的内容,双引号表示这是文字
  • \n 是换行符,让光标移到下一行
  • ; 是语句结束符,就像中文的句号

第6行:return 0;

  • return 表示"返回"
  • 0 表示程序正常结束(就像考试交卷时说"我做完了")

第7行:}

  • 大括号表示代码块的结束

程序是如何工作的?

想象程序执行就像按照菜谱做菜:

  1. 准备工具#include ):拿出需要的锅碗瓢盆
  2. 开始做菜int main() {):开始按照菜谱步骤操作
  3. 具体步骤printf(...)):切菜、炒菜等具体动作
  4. 完成return 0;):菜做好了,收工
  5. 结束}):清理厨房

编译和运行 - 详细步骤

什么是编译?

编译就像"翻译"的过程:

  • 我们写的C代码是给人看的(源代码)
  • 计算机只能理解机器语言(0和1)
  • 编译器就是"翻译官",把我们的代码翻译成计算机能理解的语言
具体步骤:

步骤1:写代码
用记事本或代码编辑器创建一个文件,命名为hello.c,输入上面的代码。

步骤2:编译

gcc hello.c -o hello

解释:

  • gcc 是编译器的名字
  • hello.c 是我们写的源代码文件
  • -o hello 表示生成的可执行文件叫hello

步骤3:运行

./hello        # Linux/Mac系统
hello.exe      # Windows系统

如果成功,你会看到:

Hello, World!

注释 - 给代码写"备注"

注释就像给代码写备注,帮助我们记住代码的作用:

// 这是单行注释,用两个斜杠开头
// 编译器会忽略这些文字,它们只是给人看的

/*
 * 这是多行注释
 * 可以写很多行
 * 用于详细说明
 */

#include   // 包含输入输出功能

int main() {
    // 在屏幕上显示欢迎信息
    printf("欢迎学习C语言!\n");

    /*
     * 返回0表示程序正常结束
     * 这是一个好习惯
     */
    return 0;
}

常见错误和解决方法

错误1:忘记分号
printf("Hello")  // 错误:缺少分号
printf("Hello"); // 正确:有分号
错误2:大括号不匹配
int main() {
    printf("Hello");
    // 错误:缺少右大括号 }
错误3:拼写错误
#include 
int main() {
    print("Hello");  // 错误:应该是printf
    return 0;
}

练习题

  1. 修改程序:让程序显示你的名字而不是"Hello, World!"
  2. 添加内容:让程序显示两行文字
  3. 加注释:给你的程序添加注释说明每行代码的作用

数据类型

什么是数据类型?

在现实生活中,我们会遇到不同类型的信息:

  • 整数:年龄(25岁)、人数(100人)
  • 小数:身高(175.5cm)、体重(65.8kg)
  • 文字:姓名(“张三”)、地址(“北京市”)
  • 是否:是否成年(是/否)

在C语言中,我们也需要告诉计算机我们要存储什么类型的数据,这就是数据类型的作用。

基本数据类型详解

1. 整数类型(int)

用途:存储整数,比如年龄、数量、分数等

#include 

int main() {
    // 声明整数变量
    int age = 25;           // 年龄
    int student_count = 30; // 学生人数
    int score = 95;         // 考试分数

    // 显示这些数据
    printf("年龄: %d 岁\n", age);
    printf("学生人数: %d 人\n", student_count);
    printf("考试分数: %d 分\n", score);

    return 0;
}

解释

  • int 是整数类型的关键字
  • %d 是整数的占位符,用于printf中显示整数
  • 整数可以是正数、负数或零
2. 小数类型(float 和 double)

用途:存储带小数点的数字,比如身高、体重、价格等

#include 

int main() {
    // float:单精度小数(精度较低,占用内存少)
    float height = 175.5;    // 身高
    float price = 29.99;     // 价格

    // double:双精度小数(精度较高,占用内存多)
    double pi = 3.141592653589793;  // 圆周率
    double distance = 384400.0;     // 地球到月球的距离(公里)

    // 显示这些数据
    printf("身高: %.1f cm\n", height);        // %.1f 表示显示1位小数
    printf("价格: %.2f 元\n", price);         // %.2f 表示显示2位小数
    printf("圆周率: %.10f\n", pi);            // %.10f 表示显示10位小数
    printf("地球到月球距离: %.0f 公里\n", distance); // %.0f 表示不显示小数

    return 0;
}

float vs double 的区别

  • float:精度约6-7位有效数字,占用4字节内存
  • double:精度约15-16位有效数字,占用8字节内存
  • 一般情况下推荐使用double
3. 字符类型(char)

用途:存储单个字符,比如字母、数字字符、符号等

#include 

int main() {
    // 存储单个字符
    char grade = 'A';        // 成绩等级
    char gender = 'M';       // 性别(M表示男性,F表示女性)
    char symbol = '@';       // 符号
    char digit = '5';        // 数字字符(注意:这是字符'5',不是数字5)

    // 显示字符
    printf("成绩等级: %c\n", grade);   // %c 是字符的占位符
    printf("性别: %c\n", gender);
    printf("符号: %c\n", symbol);
    printf("数字字符: %c\n", digit);

    // 字符实际上是数字(ASCII码)
    printf("字符'A'的ASCII码: %d\n", grade);  // 用%d显示字符的数字值

    return 0;
}

重要概念

  • 字符用单引号包围:'A''5''@'
  • 字符'5'和数字5是不同的!
  • 每个字符都有对应的数字编码(ASCII码)
4. 数据类型大小和范围
#include 

int main() {
    printf("=== 数据类型占用的内存大小 ===\n");
    printf("char:   %zu 字节\n", sizeof(char));
    printf("int:    %zu 字节\n", sizeof(int));
    printf("float:  %zu 字节\n", sizeof(float));
    printf("double: %zu 字节\n", sizeof(double));

    printf("\n=== 为什么要关心大小? ===\n");
    printf("1. 内存使用:大的数据类型占用更多内存\n");
    printf("2. 精度:大的类型通常精度更高\n");
    printf("3. 范围:大的类型能存储更大的数值\n");

    return 0;
}

如何选择数据类型?

决策树:
需要存储什么?
├── 整数(年龄、数量、分数)
│   └── 使用 int
├── 小数(身高、体重、价格)
│   ├── 精度要求不高 → 使用 float
│   └── 精度要求高 → 使用 double
└── 单个字符(等级、性别)
    └── 使用 char

实际例子:学生信息

#include 

int main() {
    // 一个学生的完整信息
    char name_initial = 'Z';    // 姓名首字母
    int age = 20;               // 年龄
    float height = 175.5;       // 身高(厘米)
    double gpa = 3.85;          // 平均绩点(需要精确)
    char grade = 'A';           // 总体等级

    // 显示学生信息
    printf("=== 学生信息 ===\n");
    printf("姓名首字母: %c\n", name_initial);
    printf("年龄: %d 岁\n", age);
    printf("身高: %.1f cm\n", height);
    printf("平均绩点: %.2f\n", gpa);
    printf("总体等级: %c\n", grade);

    return 0;
}

常见错误和注意事项

错误1:混淆字符和数字
char digit = 5;     // 错误:应该是 '5'
char digit = '5';   // 正确:字符5
int number = 5;     // 正确:数字5
错误2:小数精度丢失
float pi = 3.141592653589793;  // 精度会丢失
double pi = 3.141592653589793; // 精度保持较好
错误3:整数除法
int result = 5 / 2;        // 结果是2(整数除法)
double result = 5.0 / 2.0; // 结果是2.5(小数除法)

练习题

  1. 声明变量:为你自己创建变量存储年龄、身高、姓名首字母
  2. 计算练习:计算圆的面积(π × 半径²)
  3. 类型转换:尝试把整数赋值给小数变量,观察结果

类型修饰符

// 符号修饰符
signed int si = -100;      // 有符号整数(默认)
unsigned int ui = 100;     // 无符号整数

// 存储修饰符
short int si = 100;        // 短整型
long int li = 100000L;     // 长整型
long long int lli = 100000LL; // 长长整型

// 组合使用
unsigned long ul = 100000UL;
unsigned long long ull = 100000ULL;

枚举类型

// 基本枚举
enum Color {
    RED,      // 0
    GREEN,    // 1
    BLUE      // 2
};

// 指定值的枚举
enum Status {
    SUCCESS = 1,
    ERROR = -1,
    PENDING = 0
};

// 使用枚举
int main() {
    enum Color myColor = RED;
    enum Status status = SUCCESS;
    
    printf("颜色: %d\n", myColor);
    printf("状态: %d\n", status);
    
    return 0;
}

变量和常量

什么是变量?

想象变量就像是一个有标签的盒子

  • 盒子:用来存放东西(数据)
  • 标签:盒子的名字,方便我们找到它
  • 内容:盒子里装的东西可以更换

例如:

  • 有一个标签为"年龄"的盒子,里面装着数字"25"
  • 有一个标签为"姓名"的盒子,里面装着文字"张三"
  • 我们可以随时更换盒子里的内容

变量的基本操作

1. 声明变量(准备盒子)
#include 

int main() {
    // 声明变量就像准备空盒子
    int age;        // 准备一个叫"age"的盒子,用来装整数
    float height;   // 准备一个叫"height"的盒子,用来装小数
    char grade;     // 准备一个叫"grade"的盒子,用来装字符

    printf("变量已声明,但还没有值\n");
    return 0;
}
2. 赋值(往盒子里放东西)
#include 

int main() {
    // 先声明变量
    int age;
    float height;
    char grade;

    // 再赋值(往盒子里放东西)
    age = 25;           // 把数字25放进"age"盒子
    height = 175.5;     // 把小数175.5放进"height"盒子
    grade = 'A';        // 把字符'A'放进"grade"盒子

    // 显示盒子里的内容
    printf("年龄: %d\n", age);
    printf("身高: %.1f\n", height);
    printf("等级: %c\n", grade);

    return 0;
}
3. 声明并初始化(准备盒子的同时放入东西)
#include 

int main() {
    // 一步完成:准备盒子并放入初始内容
    int age = 25;           // 准备"age"盒子,立即放入25
    float height = 175.5;   // 准备"height"盒子,立即放入175.5
    char grade = 'A';       // 准备"grade"盒子,立即放入'A'

    printf("年龄: %d\n", age);
    printf("身高: %.1f\n", height);
    printf("等级: %c\n", grade);

    return 0;
}

变量命名规则

好的变量名(推荐):
int student_age = 20;        // 学生年龄
float book_price = 29.99;    // 书的价格
char exam_grade = 'B';       // 考试等级
int total_score = 450;       // 总分
不好的变量名(不推荐):
int a = 20;          // 不知道a代表什么
float x = 29.99;     // 不知道x是什么
char c = 'B';        // 不知道c的含义
int num = 450;       // 太模糊,什么数字?
命名规则:
  1. 只能包含:字母、数字、下划线
  2. 不能以数字开头2age❌,age2
  3. 区分大小写Ageage是不同的变量
  4. 不能使用关键字intfloatif等是保留字

变量的修改

#include 

int main() {
    int money = 100;        // 初始有100元
    printf("初始金额: %d 元\n", money);

    money = money + 50;     // 赚了50元
    printf("赚钱后: %d 元\n", money);

    money = money - 30;     // 花了30元
    printf("花钱后: %d 元\n", money);

    // 更简洁的写法
    money += 20;            // 等同于 money = money + 20
    printf("再赚20元后: %d 元\n", money);

    return 0;
}

多个变量的声明

#include 

int main() {
    // 方法1:分别声明
    int math_score = 95;
    int english_score = 88;
    int science_score = 92;

    // 方法2:同时声明多个同类型变量
    int chinese_score = 90, history_score = 85, total_score = 0;

    // 计算总分
    total_score = math_score + english_score + science_score + chinese_score + history_score;

    printf("=== 成绩单 ===\n");
    printf("数学: %d 分\n", math_score);
    printf("英语: %d 分\n", english_score);
    printf("科学: %d 分\n", science_score);
    printf("语文: %d 分\n", chinese_score);
    printf("历史: %d 分\n", history_score);
    printf("总分: %d 分\n", total_score);
    printf("平均分: %.1f 分\n", total_score / 5.0);

    return 0;
}

什么是常量?

常量就像是贴了封条的盒子

  • 一旦放入内容,就不能再更改
  • 用于存储不会变化的值,比如圆周率、一年的天数等
使用 #define 定义常量
#include 

// 在程序开头定义常量
#define PI 3.14159          // 圆周率
#define DAYS_IN_YEAR 365    // 一年的天数
#define MAX_STUDENTS 30     // 班级最大学生数

int main() {
    float radius = 5.0;
    float area = PI * radius * radius;  // 使用常量PI

    printf("半径为 %.1f 的圆面积: %.2f\n", radius, area);
    printf("一年有 %d 天\n", DAYS_IN_YEAR);
    printf("班级最多容纳 %d 名学生\n", MAX_STUDENTS);

    return 0;
}
使用 const 关键字定义常量
#include 

int main() {
    const float PI = 3.14159;           // 常量圆周率
    const int MAX_SCORE = 100;          // 最高分
    const char GRADE_A = 'A';           // A等级

    float radius = 3.0;
    float area = PI * radius * radius;

    printf("圆面积: %.2f\n", area);
    printf("满分: %d 分\n", MAX_SCORE);
    printf("最高等级: %c\n", GRADE_A);

    // PI = 3.14;  // 错误!常量不能修改

    return 0;
}

实际应用例子:计算器

#include 

#define TAX_RATE 0.08  // 税率8%

int main() {
    // 商品信息
    float item_price = 99.99;      // 商品价格
    int quantity = 3;              // 购买数量

    // 计算
    float subtotal = item_price * quantity;           // 小计
    float tax = subtotal * TAX_RATE;                  // 税费
    float total = subtotal + tax;                     // 总计

    // 显示购物清单
    printf("=== 购物清单 ===\n");
    printf("商品单价: %.2f 元\n", item_price);
    printf("购买数量: %d 件\n", quantity);
    printf("小计: %.2f 元\n", subtotal);
    printf("税费 (%.0f%%): %.2f 元\n", TAX_RATE * 100, tax);
    printf("总计: %.2f 元\n", total);

    return 0;
}

常见错误

错误1:使用未初始化的变量
int age;                    // 声明但未初始化
printf("年龄: %d\n", age);  // 错误:age的值是未知的
错误2:尝试修改常量
const int MAX_SCORE = 100;
MAX_SCORE = 90;  // 错误:常量不能修改
错误3:变量名冲突
int score = 95;
int score = 88;  // 错误:变量名重复

练习题

  1. 个人信息:创建变量存储你的姓名首字母、年龄、身高,并显示
  2. 简单计算:计算矩形的面积(长×宽)
  3. 购物计算:计算买3本书的总价(每本25.5元)
  4. 常量练习:定义一周天数的常量,计算一个月(30天)有多少周

变量作用域

#include 

// 全局变量
int global_var = 100;

void function() {
    // 局部变量
    int local_var = 200;
    
    // 静态局部变量
    static int static_var = 300;
    static_var++;
    
    printf("局部变量: %d\n", local_var);
    printf("静态变量: %d\n", static_var);
}

int main() {
    // 局部变量
    int local_var = 50;
    
    printf("全局变量: %d\n", global_var);
    printf("主函数局部变量: %d\n", local_var);
    
    function();
    function(); // 静态变量保持值
    
    // 块作用域
    {
        int block_var = 400;
        printf("块变量: %d\n", block_var);
    }
    // block_var在此处不可访问
    
    return 0;
}

常量定义

#include 

// 宏定义常量
#define PI 3.14159
#define MAX_SIZE 100
#define SQUARE(x) ((x) * (x))

int main() {
    // const关键字
    const int MAX_STUDENTS = 50;
    const float GRAVITY = 9.8f;
    const char* MESSAGE = "Hello, World!";
    
    // 使用常量
    printf("圆周率: %.5f\n", PI);
    printf("最大尺寸: %d\n", MAX_SIZE);
    printf("最大学生数: %d\n", MAX_STUDENTS);
    printf("重力加速度: %.1f\n", GRAVITY);
    printf("消息: %s\n", MESSAGE);
    
    // 使用宏函数
    int num = 5;
    printf("%d的平方: %d\n", num, SQUARE(num));
    
    return 0;
}

运算符

什么是运算符?

运算符就像数学中的加减乘除符号,用来对数据进行各种操作。在C语言中,运算符可以帮我们:

  • 进行数学计算(+、-、*、/)
  • 比较大小(>、<、==)
  • 做逻辑判断(&&、||、!)

算术运算符 - 数学计算

基本算术运算
#include 

int main() {
    // 准备两个数字做演示
    int a = 10;
    int b = 3;

    printf("=== 基本算术运算演示 ===\n");
    printf("a = %d, b = %d\n\n", a, b);

    // 加法 +
    int sum = a + b;
    printf("加法: %d + %d = %d\n", a, b, sum);

    // 减法 -
    int difference = a - b;
    printf("减法: %d - %d = %d\n", a, b, difference);

    // 乘法 *
    int product = a * b;
    printf("乘法: %d * %d = %d\n", a, b, product);

    // 除法 /(注意:整数除法)
    int quotient = a / b;
    printf("除法: %d / %d = %d\n", a, b, quotient);

    // 取模 %(求余数)
    int remainder = a % b;
    printf("取模: %d %% %d = %d\n", a, b, remainder);

    return 0;
}

运行结果:

=== 基本算术运算演示 ===
a = 10, b = 3

加法: 10 + 3 = 13
减法: 10 - 3 = 7
乘法: 10 * 3 = 30
除法: 10 / 3 = 3
取模: 10 % 3 = 1
重要概念:整数除法 vs 小数除法
#include 

int main() {
    printf("=== 整数除法 vs 小数除法 ===\n");

    // 整数除法:结果只保留整数部分
    int int_a = 10, int_b = 3;
    int int_result = int_a / int_b;
    printf("整数除法: %d / %d = %d\n", int_a, int_b, int_result);

    // 小数除法:结果保留小数部分
    float float_a = 10.0f, float_b = 3.0f;
    float float_result = float_a / float_b;
    printf("小数除法: %.1f / %.1f = %.2f\n", float_a, float_b, float_result);

    // 混合运算:整数和小数
    float mixed_result = 10 / 3.0f;  // 有一个是小数,结果就是小数
    printf("混合运算: 10 / 3.0 = %.2f\n", mixed_result);

    return 0;
}
取模运算的实际应用
#include 

int main() {
    printf("=== 取模运算的实际应用 ===\n");

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

    // 时间转换:秒转换为分钟和秒
    int total_seconds = 125;
    int minutes = total_seconds / 60;
    int seconds = total_seconds % 60;
    printf("%d 秒 = %d 分 %d 秒\n", total_seconds, minutes, seconds);

    // 循环计数(比如每5个一组)
    for (int i = 1; i <= 12; i++) {
        printf("%d ", i);
        if (i % 5 == 0) {  // 每5个数字换行
            printf("\n");
        }
    }

    return 0;
}

自增和自减运算符

基本概念
#include 

int main() {
    printf("=== 自增自减运算符 ===\n");

    int count = 5;
    printf("初始值: count = %d\n", count);

    // 自增 ++(加1)
    count++;  // 等同于 count = count + 1
    printf("执行 count++ 后: count = %d\n", count);

    // 自减 --(减1)
    count--;  // 等同于 count = count - 1
    printf("执行 count-- 后: count = %d\n", count);

    return 0;
}
前缀 vs 后缀的区别
#include 

int main() {
    printf("=== 前缀 vs 后缀的区别 ===\n");

    int a = 5, b = 5;

    // 前缀自增:先加1,再使用
    printf("前缀自增:\n");
    printf("a = %d\n", a);
    printf("++a = %d\n", ++a);  // 先变成6,再打印6
    printf("现在 a = %d\n", a);

    printf("\n");

    // 后缀自增:先使用,再加1
    printf("后缀自增:\n");
    printf("b = %d\n", b);
    printf("b++ = %d\n", b++);  // 先打印5,再变成6
    printf("现在 b = %d\n", b);

    return 0;
}

赋值运算符

基本赋值
#include 

int main() {
    printf("=== 赋值运算符 ===\n");

    int score = 80;  // 基本赋值
    printf("初始分数: %d\n", score);

    // 复合赋值运算符(简化写法)
    score += 10;  // 等同于 score = score + 10
    printf("加10分后: %d\n", score);

    score -= 5;   // 等同于 score = score - 5
    printf("减5分后: %d\n", score);

    score *= 2;   // 等同于 score = score * 2
    printf("乘以2后: %d\n", score);

    score /= 3;   // 等同于 score = score / 3
    printf("除以3后: %d\n", score);

    score %= 10;  // 等同于 score = score % 10
    printf("对10取模后: %d\n", score);

    return 0;
}

比较运算符

#include 

int main() {
    printf("=== 比较运算符 ===\n");

    int age1 = 18, age2 = 20;
    printf("age1 = %d, age2 = %d\n\n", age1, age2);

    // 各种比较
    printf("age1 == age2 (相等): %d\n", age1 == age2);      // 0表示假
    printf("age1 != age2 (不等): %d\n", age1 != age2);      // 1表示真
    printf("age1 < age2  (小于): %d\n", age1 < age2);       // 1表示真
    printf("age1 > age2  (大于): %d\n", age1 > age2);       // 0表示假
    printf("age1 <= age2 (小于等于): %d\n", age1 <= age2);  // 1表示真
    printf("age1 >= age2 (大于等于): %d\n", age1 >= age2);  // 0表示假

    // 实际应用:判断是否成年
    printf("\n=== 实际应用 ===\n");
    if (age1 >= 18) {
        printf("age1 (%d岁) 已成年\n", age1);
    } else {
        printf("age1 (%d岁) 未成年\n", age1);
    }

    return 0;
}

逻辑运算符

#include 

int main() {
    printf("=== 逻辑运算符 ===\n");

    int age = 20;
    int score = 85;

    printf("年龄: %d, 分数: %d\n\n", age, score);

    // 逻辑与 &&(两个条件都要满足)
    if (age >= 18 && score >= 80) {
        printf("逻辑与: 既成年又成绩优秀,可以获得奖学金!\n");
    }

    // 逻辑或 ||(满足其中一个条件即可)
    if (age >= 18 || score >= 90) {
        printf("逻辑或: 要么成年,要么成绩特别好,可以参加活动!\n");
    }

    // 逻辑非 !(取反)
    int is_weekend = 0;  // 0表示不是周末
    if (!is_weekend) {
        printf("逻辑非: 不是周末,需要上学!\n");
    }

    return 0;
}

运算符优先级

#include 

int main() {
    printf("=== 运算符优先级 ===\n");

    // 没有括号的情况
    int result1 = 2 + 3 * 4;  // 先算乘法,再算加法
    printf("2 + 3 * 4 = %d\n", result1);  // 结果是14,不是20

    // 使用括号改变优先级
    int result2 = (2 + 3) * 4;  // 先算括号内的加法,再算乘法
    printf("(2 + 3) * 4 = %d\n", result2);  // 结果是20

    // 复杂表达式
    int a = 10, b = 5, c = 2;
    int result3 = a + b * c - 3;  // 10 + (5*2) - 3 = 10 + 10 - 3 = 17
    printf("10 + 5 * 2 - 3 = %d\n", result3);

    // 建议:复杂表达式使用括号让意图更清楚
    int result4 = a + (b * c) - 3;  // 意图明确
    printf("10 + (5 * 2) - 3 = %d\n", result4);

    return 0;
}

实际应用:成绩计算器

#include 

int main() {
    printf("=== 成绩计算器 ===\n");

    // 输入各科成绩
    float math, english, science;
    printf("请输入数学成绩: ");
    scanf("%f", &math);
    printf("请输入英语成绩: ");
    scanf("%f", &english);
    printf("请输入科学成绩: ");
    scanf("%f", &science);

    // 计算总分和平均分
    float total = math + english + science;
    float average = total / 3;

    printf("\n=== 成绩报告 ===\n");
    printf("数学: %.1f 分\n", math);
    printf("英语: %.1f 分\n", english);
    printf("科学: %.1f 分\n", science);
    printf("总分: %.1f 分\n", total);
    printf("平均分: %.1f 分\n", average);

    // 判断等级
    if (average >= 90) {
        printf("等级: A (优秀)\n");
    } else if (average >= 80) {
        printf("等级: B (良好)\n");
    } else if (average >= 70) {
        printf("等级: C (中等)\n");
    } else if (average >= 60) {
        printf("等级: D (及格)\n");
    } else {
        printf("等级: F (不及格)\n");
    }

    // 判断是否需要补考
    if (math < 60 || english < 60 || science < 60) {
        printf("提醒: 有科目不及格,需要补考!\n");
    } else {
        printf("恭喜: 所有科目都及格了!\n");
    }

    return 0;
}

常见错误和注意事项

错误1:赋值和比较混淆
int a = 5;
if (a = 10) {  // 错误:这是赋值,不是比较
    printf("这总是会执行\n");
}

if (a == 10) {  // 正确:这是比较
    printf("a等于10\n");
}
错误2:整数除法的陷阱
int a = 5, b = 2;
float result = a / b;  // 错误:结果是2.0,不是2.5
printf("%.1f\n", result);

float result2 = (float)a / b;  // 正确:结果是2.5
printf("%.1f\n", result2);
错误3:取模运算的限制
int a = 10;
float b = 3.0;
// int result = a % b;  // 错误:取模运算只能用于整数
int result = a % 3;     // 正确

练习题

  1. 基础计算:编写程序计算圆的面积和周长(π取3.14159)
  2. 时间转换:输入总秒数,转换为小时、分钟、秒
  3. 温度转换:摄氏度转华氏度(公式:F = C * 9/5 + 32)
  4. 成绩判断:输入成绩,判断等级(A: 90-100, B: 80-89, C: 70-79, D: 60-69, F: <60)
  5. 奇偶判断:输入一个数字,判断是奇数还是偶数

关系运算符

#include 

int main() {
    int a = 10, b = 20;

    printf("a = %d, b = %d\n", a, b);
    printf("a == b: %d\n", a == b);  // 等于
    printf("a != b: %d\n", a != b);  // 不等于
    printf("a > b: %d\n", a > b);    // 大于
    printf("a < b: %d\n", a < b);    // 小于
    printf("a >= b: %d\n", a >= b);  // 大于等于
    printf("a <= b: %d\n", a <= b);  // 小于等于

    return 0;
}

逻辑运算符

#include 

int main() {
    int a = 1, b = 0, c = 1;

    printf("a = %d, b = %d, c = %d\n", a, b, c);
    printf("a && b: %d\n", a && b);  // 逻辑与
    printf("a || b: %d\n", a || b);  // 逻辑或
    printf("!a: %d\n", !a);          // 逻辑非

    // 短路求值
    printf("短路求值示例:\n");
    if (a && (b = 5)) {
        printf("b = %d\n", b);
    }

    return 0;
}

位运算符

#include 

void printBinary(int num) {
    for (int i = 31; i >= 0; i--) {
        printf("%d", (num >> i) & 1);
        if (i % 4 == 0) printf(" ");
    }
    printf("\n");
}

int main() {
    int a = 12;  // 1100 in binary
    int b = 10;  // 1010 in binary

    printf("a = %d: ", a);
    printBinary(a);
    printf("b = %d: ", b);
    printBinary(b);

    printf("a & b = %d: ", a & b);   // 按位与
    printBinary(a & b);

    printf("a | b = %d: ", a | b);   // 按位或
    printBinary(a | b);

    printf("a ^ b = %d: ", a ^ b);   // 按位异或
    printBinary(a ^ b);

    printf("~a = %d: ", ~a);         // 按位取反
    printBinary(~a);

    printf("a << 2 = %d: ", a << 2); // 左移
    printBinary(a << 2);

    printf("a >> 2 = %d: ", a >> 2); // 右移
    printBinary(a >> 2);

    return 0;
}

赋值运算符

#include 

int main() {
    int a = 10;

    printf("初始值 a = %d\n", a);

    a += 5;  // a = a + 5
    printf("a += 5: %d\n", a);

    a -= 3;  // a = a - 3
    printf("a -= 3: %d\n", a);

    a *= 2;  // a = a * 2
    printf("a *= 2: %d\n", a);

    a /= 4;  // a = a / 4
    printf("a /= 4: %d\n", a);

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

    // 位运算赋值
    a = 12;
    a &= 10;  // a = a & 10
    printf("a &= 10: %d\n", a);

    a |= 5;   // a = a | 5
    printf("a |= 5: %d\n", a);

    a ^= 3;   // a = a ^ 3
    printf("a ^= 3: %d\n", a);

    a <<= 1;  // a = a << 1
    printf("a <<= 1: %d\n", a);

    a >>= 2;  // a = a >> 2
    printf("a >>= 2: %d\n", a);

    return 0;
}

控制结构

条件语句

#include 

int main() {
    int score;
    char grade;

    printf("请输入分数: ");
    scanf("%d", &score);

    // if-else语句
    if (score >= 90) {
        grade = 'A';
    } else if (score >= 80) {
        grade = 'B';
    } else if (score >= 70) {
        grade = 'C';
    } else if (score >= 60) {
        grade = 'D';
    } else {
        grade = 'F';
    }

    printf("分数: %d, 等级: %c\n", score, grade);

    // 三元运算符
    char* result = (score >= 60) ? "及格" : "不及格";
    printf("结果: %s\n", result);

    // switch语句
    int day;
    printf("请输入星期几(1-7): ");
    scanf("%d", &day);

    switch (day) {
        case 1:
            printf("星期一\n");
            break;
        case 2:
            printf("星期二\n");
            break;
        case 3:
            printf("星期三\n");
            break;
        case 4:
            printf("星期四\n");
            break;
        case 5:
            printf("星期五\n");
            break;
        case 6:
            printf("星期六\n");
            break;
        case 7:
            printf("星期日\n");
            break;
        default:
            printf("无效输入\n");
            break;
    }

    return 0;
}

循环语句

#include 

int main() {
    int i, n, sum;

    // for循环
    printf("for循环 - 1到10的数字:\n");
    for (i = 1; i <= 10; i++) {
        printf("%d ", i);
    }
    printf("\n");

    // while循环
    printf("while循环 - 计算1到100的和:\n");
    i = 1;
    sum = 0;
    while (i <= 100) {
        sum += i;
        i++;
    }
    printf("1到100的和: %d\n", sum);

    // do-while循环
    printf("do-while循环 - 输入正数(输入0结束):\n");
    do {
        printf("请输入一个数: ");
        scanf("%d", &n);
        if (n > 0) {
            printf("您输入的正数是: %d\n", n);
        }
    } while (n != 0);

    // 嵌套循环 - 打印乘法表
    printf("\n九九乘法表:\n");
    for (i = 1; i <= 9; i++) {
        for (int j = 1; j <= i; j++) {
            printf("%d*%d=%d\t", j, i, i*j);
        }
        printf("\n");
    }

    // break和continue
    printf("\nbreak和continue示例:\n");
    for (i = 1; i <= 10; i++) {
        if (i == 5) {
            continue;  // 跳过5
        }
        if (i == 8) {
            break;     // 在8处停止
        }
        printf("%d ", i);
    }
    printf("\n");

    return 0;
}

函数

函数基础

#include 

// 函数声明
int add(int a, int b);
void greet(char* name);
int factorial(int n);
void swap(int* a, int* b);

int main() {
    // 调用函数
    int result = add(10, 20);
    printf("10 + 20 = %d\n", result);

    greet("张三");

    int fact = factorial(5);
    printf("5! = %d\n", fact);

    int x = 10, y = 20;
    printf("交换前: x = %d, y = %d\n", x, y);
    swap(&x, &y);
    printf("交换后: x = %d, y = %d\n", x, y);

    return 0;
}

// 函数定义
int add(int a, int b) {
    return a + b;
}

void greet(char* name) {
    printf("你好, %s!\n", name);
}

// 递归函数
int factorial(int n) {
    if (n <= 1) {
        return 1;
    }
    return n * factorial(n - 1);
}

// 通过指针交换值
void swap(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

函数参数传递

#include 

// 值传递
void changeValue(int x) {
    x = 100;
    printf("函数内部: x = %d\n", x);
}

// 指针传递
void changePointer(int* x) {
    *x = 100;
    printf("函数内部: *x = %d\n", *x);
}

// 数组传递
void printArray(int arr[], int size) {
    printf("数组元素: ");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

void modifyArray(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        arr[i] *= 2;
    }
}

int main() {
    // 值传递示例
    int num = 10;
    printf("调用前: num = %d\n", num);
    changeValue(num);
    printf("调用后: num = %d\n", num);

    printf("\n");

    // 指针传递示例
    printf("调用前: num = %d\n", num);
    changePointer(&num);
    printf("调用后: num = %d\n", num);

    printf("\n");

    // 数组传递示例
    int arr[] = {1, 2, 3, 4, 5};
    int size = sizeof(arr) / sizeof(arr[0]);

    printf("原始数组: ");
    printArray(arr, size);

    modifyArray(arr, size);
    printf("修改后数组: ");
    printArray(arr, size);

    return 0;
}

数组

一维数组

#include 

int main() {
    // 数组声明和初始化
    int numbers[5] = {1, 2, 3, 4, 5};
    int scores[] = {85, 92, 78, 96, 88};  // 自动确定大小
    int grades[10];  // 未初始化数组

    // 访问数组元素
    printf("第一个数字: %d\n", numbers[0]);
    printf("最后一个数字: %d\n", numbers[4]);

    // 修改数组元素
    numbers[2] = 30;
    printf("修改后的第三个数字: %d\n", numbers[2]);

    // 遍历数组
    printf("所有数字: ");
    for (int i = 0; i < 5; i++) {
        printf("%d ", numbers[i]);
    }
    printf("\n");

    // 计算数组大小
    int size = sizeof(scores) / sizeof(scores[0]);
    printf("scores数组大小: %d\n", size);

    // 数组求和和平均值
    int sum = 0;
    for (int i = 0; i < size; i++) {
        sum += scores[i];
    }
    double average = (double)sum / size;
    printf("总分: %d, 平均分: %.2f\n", sum, average);

    // 查找最大值和最小值
    int max = scores[0], min = scores[0];
    for (int i = 1; i < size; i++) {
        if (scores[i] > max) max = scores[i];
        if (scores[i] < min) min = scores[i];
    }
    printf("最高分: %d, 最低分: %d\n", max, min);

    return 0;
}

二维数组

#include 

int main() {
    // 二维数组声明和初始化
    int matrix[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    };

    // 部分初始化
    int table[2][3] = {{1, 2}, {4, 5, 6}};

    // 访问二维数组元素
    printf("matrix[1][2] = %d\n", matrix[1][2]);

    // 遍历二维数组
    printf("矩阵内容:\n");
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%2d ", matrix[i][j]);
        }
        printf("\n");
    }

    // 计算每行的和
    printf("每行的和:\n");
    for (int i = 0; i < 3; i++) {
        int rowSum = 0;
        for (int j = 0; j < 4; j++) {
            rowSum += matrix[i][j];
        }
        printf("第%d行: %d\n", i+1, rowSum);
    }

    // 矩阵转置
    int transpose[4][3];
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
            transpose[j][i] = matrix[i][j];
        }
    }

    printf("转置矩阵:\n");
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 3; j++) {
            printf("%2d ", transpose[i][j]);
        }
        printf("\n");
    }

    return 0;
}

指针

指针基础

#include 

int main() {
    int num = 42;
    int* ptr;  // 声明指针

    ptr = &num;  // 指针指向num的地址

    printf("变量值: %d\n", num);
    printf("变量地址: %p\n", (void*)&num);
    printf("指针值(地址): %p\n", (void*)ptr);
    printf("指针指向的值: %d\n", *ptr);
    printf("指针的地址: %p\n", (void*)&ptr);

    // 通过指针修改值
    *ptr = 100;
    printf("通过指针修改后的值: %d\n", num);

    // 指针运算
    int arr[] = {10, 20, 30, 40, 50};
    int* p = arr;  // 指向数组第一个元素

    printf("数组元素:\n");
    for (int i = 0; i < 5; i++) {
        printf("arr[%d] = %d, *(p+%d) = %d\n", i, arr[i], i, *(p+i));
    }

    // 指针递增
    printf("通过指针遍历数组:\n");
    p = arr;
    for (int i = 0; i < 5; i++) {
        printf("%d ", *p);
        p++;  // 指针递增
    }
    printf("\n");

    return 0;
}

指针与数组

#include 

void printArray(int* arr, int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", *(arr + i));
    }
    printf("\n");
}

int main() {
    int numbers[] = {1, 2, 3, 4, 5};
    int size = sizeof(numbers) / sizeof(numbers[0]);

    // 数组名就是指向第一个元素的指针
    printf("数组名作为指针:\n");
    printf("numbers = %p\n", (void*)numbers);
    printf("&numbers[0] = %p\n", (void*)&numbers[0]);

    // 指针与数组的等价性
    printf("访问数组元素的不同方式:\n");
    for (int i = 0; i < size; i++) {
        printf("numbers[%d] = %d, *(numbers+%d) = %d\n",
               i, numbers[i], i, *(numbers+i));
    }

    // 传递数组给函数
    printf("通过函数打印数组: ");
    printArray(numbers, size);

    return 0;
}

字符串

字符串基础

#include 
#include 

int main() {
    // 字符串声明和初始化
    char str1[] = "Hello";           // 字符数组
    char str2[20] = "World";         // 指定大小
    char* str3 = "C Programming";    // 字符指针
    char str4[50];                   // 未初始化

    printf("str1: %s\n", str1);
    printf("str2: %s\n", str2);
    printf("str3: %s\n", str3);

    // 字符串长度
    printf("str1长度: %zu\n", strlen(str1));
    printf("str2长度: %zu\n", strlen(str2));

    // 字符串复制
    strcpy(str4, "复制的字符串");
    printf("str4: %s\n", str4);

    // 字符串连接
    strcat(str2, " Programming");
    printf("连接后的str2: %s\n", str2);

    // 字符串比较
    int result = strcmp(str1, "Hello");
    printf("strcmp结果: %d\n", result);

    // 逐字符访问
    printf("str1的每个字符: ");
    for (int i = 0; str1[i] != '\0'; i++) {
        printf("%c ", str1[i]);
    }
    printf("\n");

    return 0;
}

字符串函数

#include 
#include 
#include 

// 自定义字符串长度函数
int myStrlen(char* str) {
    int length = 0;
    while (str[length] != '\0') {
        length++;
    }
    return length;
}

// 自定义字符串复制函数
void myStrcpy(char* dest, char* src) {
    int i = 0;
    while (src[i] != '\0') {
        dest[i] = src[i];
        i++;
    }
    dest[i] = '\0';
}

int main() {
    char text[] = "Hello World 123";
    char copy[50];

    // 使用自定义函数
    printf("原字符串: %s\n", text);
    printf("字符串长度: %d\n", myStrlen(text));

    myStrcpy(copy, text);
    printf("复制的字符串: %s\n", copy);

    // 字符分类函数
    printf("字符分析:\n");
    for (int i = 0; text[i] != '\0'; i++) {
        char c = text[i];
        printf("'%c': ", c);
        if (isalpha(c)) printf("字母 ");
        if (isdigit(c)) printf("数字 ");
        if (isspace(c)) printf("空格 ");
        if (isupper(c)) printf("大写 ");
        if (islower(c)) printf("小写 ");
        printf("\n");
    }

    // 字符串转换
    char upper[50], lower[50];
    strcpy(upper, text);
    strcpy(lower, text);

    for (int i = 0; upper[i] != '\0'; i++) {
        upper[i] = toupper(upper[i]);
        lower[i] = tolower(lower[i]);
    }

    printf("转大写: %s\n", upper);
    printf("转小写: %s\n", lower);

    return 0;
}

结构体和联合体

结构体基础

#include 
#include 

// 定义学生结构体
struct Student {
    int id;
    char name[50];
    int age;
    float gpa;
};

// 使用typedef简化
typedef struct {
    int x;
    int y;
} Point;

// 嵌套结构体
typedef struct {
    char street[100];
    char city[50];
    int zipCode;
} Address;

typedef struct {
    int id;
    char name[50];
    Address address;
} Person;

int main() {
    // 结构体变量声明和初始化
    struct Student student1 = {1001, "张三", 20, 3.8};
    struct Student student2;

    // 成员赋值
    student2.id = 1002;
    strcpy(student2.name, "李四");
    student2.age = 21;
    student2.gpa = 3.6;

    // 访问结构体成员
    printf("学生1信息:\n");
    printf("ID: %d, 姓名: %s, 年龄: %d, GPA: %.2f\n",
           student1.id, student1.name, student1.age, student1.gpa);

    printf("学生2信息:\n");
    printf("ID: %d, 姓名: %s, 年龄: %d, GPA: %.2f\n",
           student2.id, student2.name, student2.age, student2.gpa);

    // 使用typedef定义的结构体
    Point p1 = {10, 20};
    Point p2 = {30, 40};

    printf("点1: (%d, %d)\n", p1.x, p1.y);
    printf("点2: (%d, %d)\n", p2.x, p2.y);

    // 嵌套结构体
    Person person = {
        .id = 1,
        .name = "王五",
        .address = {"中山路123号", "北京", 100000}
    };

    printf("人员信息:\n");
    printf("ID: %d, 姓名: %s\n", person.id, person.name);
    printf("地址: %s, %s, %d\n",
           person.address.street, person.address.city, person.address.zipCode);

    return 0;
}

联合体

#include 

// 联合体定义
union Data {
    int i;
    float f;
    char str[20];
};

// 联合体在结构体中的应用
typedef struct {
    int type;  // 0-int, 1-float, 2-string
    union {
        int intValue;
        float floatValue;
        char stringValue[50];
    } value;
} Variant;

int main() {
    union Data data;

    // 联合体成员共享内存
    printf("联合体大小: %zu bytes\n", sizeof(data));

    // 使用不同类型的数据
    data.i = 10;
    printf("整数值: %d\n", data.i);

    data.f = 3.14f;
    printf("浮点值: %.2f\n", data.f);
    printf("此时整数值: %d (已被覆盖)\n", data.i);

    strcpy(data.str, "Hello");
    printf("字符串值: %s\n", data.str);
    printf("此时浮点值: %.2f (已被覆盖)\n", data.f);

    // 变体类型示例
    Variant var1 = {0, .value.intValue = 42};
    Variant var2 = {1, .value.floatValue = 3.14f};
    Variant var3 = {2, .value.stringValue = "Hello World"};

    printf("\n变体类型示例:\n");
    if (var1.type == 0) {
        printf("整数: %d\n", var1.value.intValue);
    }
    if (var2.type == 1) {
        printf("浮点: %.2f\n", var2.value.floatValue);
    }
    if (var3.type == 2) {
        printf("字符串: %s\n", var3.value.stringValue);
    }

    return 0;
}

文件操作

文件读写基础

#include 
#include 

int main() {
    FILE* file;
    char filename[] = "test.txt";
    char buffer[100];

    // 写入文件
    file = fopen(filename, "w");
    if (file == NULL) {
        printf("无法创建文件\n");
        return 1;
    }

    fprintf(file, "Hello, World!\n");
    fprintf(file, "这是第二行\n");
    fprintf(file, "数字: %d\n", 42);

    fclose(file);
    printf("文件写入完成\n");

    // 读取文件
    file = fopen(filename, "r");
    if (file == NULL) {
        printf("无法打开文件\n");
        return 1;
    }

    printf("文件内容:\n");
    while (fgets(buffer, sizeof(buffer), file) != NULL) {
        printf("%s", buffer);
    }

    fclose(file);

    // 追加内容
    file = fopen(filename, "a");
    if (file != NULL) {
        fprintf(file, "追加的内容\n");
        fclose(file);
    }

    return 0;
}

二进制文件操作

#include 
#include 

typedef struct {
    int id;
    char name[50];
    float salary;
} Employee;

int main() {
    Employee employees[] = {
        {1, "张三", 5000.0},
        {2, "李四", 6000.0},
        {3, "王五", 5500.0}
    };

    int count = sizeof(employees) / sizeof(employees[0]);
    FILE* file;

    // 写入二进制文件
    file = fopen("employees.dat", "wb");
    if (file == NULL) {
        printf("无法创建文件\n");
        return 1;
    }

    fwrite(employees, sizeof(Employee), count, file);
    fclose(file);
    printf("员工数据已写入二进制文件\n");

    // 读取二进制文件
    file = fopen("employees.dat", "rb");
    if (file == NULL) {
        printf("无法打开文件\n");
        return 1;
    }

    Employee emp;
    printf("从文件读取的员工信息:\n");
    while (fread(&emp, sizeof(Employee), 1, file) == 1) {
        printf("ID: %d, 姓名: %s, 薪资: %.2f\n",
               emp.id, emp.name, emp.salary);
    }

    fclose(file);

    return 0;
}

内存管理

动态内存分配

#include 
#include 
#include 

int main() {
    int n;
    int* arr;

    printf("请输入数组大小: ");
    scanf("%d", &n);

    // 使用malloc分配内存
    arr = (int*)malloc(n * sizeof(int));
    if (arr == NULL) {
        printf("内存分配失败\n");
        return 1;
    }

    // 初始化数组
    for (int i = 0; i < n; i++) {
        arr[i] = i * i;
    }

    // 打印数组
    printf("数组内容: ");
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    // 使用realloc重新分配内存
    int newSize = n * 2;
    arr = (int*)realloc(arr, newSize * sizeof(int));
    if (arr == NULL) {
        printf("内存重新分配失败\n");
        return 1;
    }

    // 初始化新增的元素
    for (int i = n; i < newSize; i++) {
        arr[i] = i * i;
    }

    printf("扩展后的数组: ");
    for (int i = 0; i < newSize; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    // 释放内存
    free(arr);
    arr = NULL;  // 避免悬空指针

    // 使用calloc分配并初始化为0
    int* zeros = (int*)calloc(5, sizeof(int));
    if (zeros != NULL) {
        printf("calloc分配的数组: ");
        for (int i = 0; i < 5; i++) {
            printf("%d ", zeros[i]);
        }
        printf("\n");
        free(zeros);
    }

    return 0;
}

预处理器

宏定义

#include 

// 简单宏定义
#define PI 3.14159
#define MAX_SIZE 100
#define SQUARE(x) ((x) * (x))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))

// 多行宏定义
#define SWAP(a, b) do { \
    typeof(a) temp = a; \
    a = b; \
    b = temp; \
} while(0)

// 字符串化操作符
#define PRINT_VAR(var) printf(#var " = %d\n", var)

// 连接操作符
#define CONCAT(a, b) a##b

int main() {
    // 使用简单宏
    printf("圆周率: %.5f\n", PI);
    printf("最大尺寸: %d\n", MAX_SIZE);

    // 使用函数式宏
    int num = 5;
    printf("%d的平方: %d\n", num, SQUARE(num));

    int a = 10, b = 20;
    printf("最大值: %d\n", MAX(a, b));
    printf("最小值: %d\n", MIN(a, b));

    // 使用字符串化
    int value = 42;
    PRINT_VAR(value);

    // 使用连接操作符
    int CONCAT(var, 1) = 100;
    int CONCAT(var, 2) = 200;
    printf("var1 = %d, var2 = %d\n", var1, var2);

    return 0;
}

条件编译

#include 

// 定义调试模式
#define DEBUG 1
#define VERSION 2

int main() {
    printf("程序开始运行\n");

    // 条件编译
    #if DEBUG
        printf("调试信息: 程序正在调试模式下运行\n");
    #endif

    #ifdef DEBUG
        printf("DEBUG已定义\n");
    #else
        printf("DEBUG未定义\n");
    #endif

    #ifndef RELEASE
        printf("RELEASE未定义\n");
    #endif

    // 版本控制
    #if VERSION == 1
        printf("版本1功能\n");
    #elif VERSION == 2
        printf("版本2功能\n");
    #else
        printf("未知版本\n");
    #endif

    // 平台相关编译
    #ifdef _WIN32
        printf("Windows平台\n");
    #elif defined(__linux__)
        printf("Linux平台\n");
    #elif defined(__APPLE__)
        printf("macOS平台\n");
    #else
        printf("未知平台\n");
    #endif

    return 0;
}

实战项目

学生管理系统

#include 
#include 
#include 

#define MAX_STUDENTS 100
#define NAME_LENGTH 50

typedef struct {
    int id;
    char name[NAME_LENGTH];
    int age;
    float gpa;
} Student;

Student students[MAX_STUDENTS];
int studentCount = 0;

// 添加学生
void addStudent() {
    if (studentCount >= MAX_STUDENTS) {
        printf("学生数量已达上限\n");
        return;
    }

    Student* s = &students[studentCount];

    printf("请输入学生ID: ");
    scanf("%d", &s->id);

    printf("请输入学生姓名: ");
    scanf("%s", s->name);

    printf("请输入学生年龄: ");
    scanf("%d", &s->age);

    printf("请输入学生GPA: ");
    scanf("%f", &s->gpa);

    studentCount++;
    printf("学生添加成功\n");
}

// 显示所有学生
void displayStudents() {
    if (studentCount == 0) {
        printf("没有学生记录\n");
        return;
    }

    printf("\n学生列表:\n");
    printf("%-5s %-20s %-5s %-5s\n", "ID", "姓名", "年龄", "GPA");
    printf("----------------------------------------\n");

    for (int i = 0; i < studentCount; i++) {
        printf("%-5d %-20s %-5d %.2f\n",
               students[i].id, students[i].name,
               students[i].age, students[i].gpa);
    }
}

// 查找学生
void findStudent() {
    int id;
    printf("请输入要查找的学生ID: ");
    scanf("%d", &id);

    for (int i = 0; i < studentCount; i++) {
        if (students[i].id == id) {
            printf("找到学生:\n");
            printf("ID: %d, 姓名: %s, 年龄: %d, GPA: %.2f\n",
                   students[i].id, students[i].name,
                   students[i].age, students[i].gpa);
            return;
        }
    }

    printf("未找到ID为%d的学生\n", id);
}

// 删除学生
void deleteStudent() {
    int id;
    printf("请输入要删除的学生ID: ");
    scanf("%d", &id);

    for (int i = 0; i < studentCount; i++) {
        if (students[i].id == id) {
            // 移动后面的元素
            for (int j = i; j < studentCount - 1; j++) {
                students[j] = students[j + 1];
            }
            studentCount--;
            printf("学生删除成功\n");
            return;
        }
    }

    printf("未找到ID为%d的学生\n", id);
}

// 保存到文件
void saveToFile() {
    FILE* file = fopen("students.dat", "wb");
    if (file == NULL) {
        printf("无法创建文件\n");
        return;
    }

    fwrite(&studentCount, sizeof(int), 1, file);
    fwrite(students, sizeof(Student), studentCount, file);
    fclose(file);

    printf("数据已保存到文件\n");
}

// 从文件加载
void loadFromFile() {
    FILE* file = fopen("students.dat", "rb");
    if (file == NULL) {
        printf("文件不存在\n");
        return;
    }

    fread(&studentCount, sizeof(int), 1, file);
    fread(students, sizeof(Student), studentCount, file);
    fclose(file);

    printf("数据已从文件加载\n");
}

int main() {
    int choice;

    // 程序启动时加载数据
    loadFromFile();

    while (1) {
        printf("\n=== 学生管理系统 ===\n");
        printf("1. 添加学生\n");
        printf("2. 显示所有学生\n");
        printf("3. 查找学生\n");
        printf("4. 删除学生\n");
        printf("5. 保存到文件\n");
        printf("6. 退出\n");
        printf("请选择操作: ");

        scanf("%d", &choice);

        switch (choice) {
            case 1:
                addStudent();
                break;
            case 2:
                displayStudents();
                break;
            case 3:
                findStudent();
                break;
            case 4:
                deleteStudent();
                break;
            case 5:
                saveToFile();
                break;
            case 6:
                saveToFile();  // 退出前保存
                printf("程序退出\n");
                return 0;
            default:
                printf("无效选择\n");
        }
    }

    return 0;
}

最佳实践

编程规范

// 好的编程习惯示例

#include 
#include 
#include 

// 常量定义
#define MAX_NAME_LENGTH 50
#define MAX_STUDENTS 100

// 结构体定义
typedef struct {
    int id;
    char name[MAX_NAME_LENGTH];
    float grade;
} Student;

// 函数声明
int validateInput(int min, int max);
void printStudent(const Student* student);
Student* createStudent(int id, const char* name, float grade);

int main() {
    // 变量声明和初始化
    Student* students[MAX_STUDENTS] = {NULL};
    int studentCount = 0;

    // 输入验证
    printf("请输入学生数量 (1-%d): ", MAX_STUDENTS);
    studentCount = validateInput(1, MAX_STUDENTS);

    // 动态内存分配
    for (int i = 0; i < studentCount; i++) {
        char name[MAX_NAME_LENGTH];
        float grade;

        printf("请输入第%d个学生的姓名: ", i + 1);
        scanf("%s", name);

        printf("请输入成绩: ");
        scanf("%f", &grade);

        students[i] = createStudent(i + 1, name, grade);
        if (students[i] == NULL) {
            printf("内存分配失败\n");
            // 清理已分配的内存
            for (int j = 0; j < i; j++) {
                free(students[j]);
            }
            return 1;
        }
    }

    // 显示学生信息
    printf("\n学生信息:\n");
    for (int i = 0; i < studentCount; i++) {
        printStudent(students[i]);
    }

    // 清理内存
    for (int i = 0; i < studentCount; i++) {
        free(students[i]);
        students[i] = NULL;
    }

    return 0;
}

// 输入验证函数
int validateInput(int min, int max) {
    int value;
    while (1) {
        if (scanf("%d", &value) == 1 && value >= min && value <= max) {
            return value;
        }
        printf("输入无效,请输入%d到%d之间的数字: ", min, max);
        // 清理输入缓冲区
        while (getchar() != '\n');
    }
}

// 打印学生信息
void printStudent(const Student* student) {
    if (student != NULL) {
        printf("ID: %d, 姓名: %s, 成绩: %.2f\n",
               student->id, student->name, student->grade);
    }
}

// 创建学生对象
Student* createStudent(int id, const char* name, float grade) {
    Student* student = (Student*)malloc(sizeof(Student));
    if (student != NULL) {
        student->id = id;
        strncpy(student->name, name, MAX_NAME_LENGTH - 1);
        student->name[MAX_NAME_LENGTH - 1] = '\0';  // 确保字符串结束
        student->grade = grade;
    }
    return student;
}

常见错误和避免方法

#include 
#include 
#include 

// 错误示例和正确做法

void arrayBoundsExample() {
    printf("=== 数组越界示例 ===\n");

    int arr[5] = {1, 2, 3, 4, 5};

    // 错误:数组越界
    // arr[5] = 6;  // 危险!越界访问

    // 正确:检查边界
    int index = 5;
    if (index < 5) {
        arr[index] = 6;
    } else {
        printf("索引%d超出数组边界\n", index);
    }
}

void memoryLeakExample() {
    printf("=== 内存泄漏示例 ===\n");

    // 错误:忘记释放内存
    /*
    int* ptr = (int*)malloc(sizeof(int) * 10);
    // 使用ptr...
    // 忘记调用free(ptr); 导致内存泄漏
    */

    // 正确:及时释放内存
    int* ptr = (int*)malloc(sizeof(int) * 10);
    if (ptr != NULL) {
        // 使用ptr...
        for (int i = 0; i < 10; i++) {
            ptr[i] = i;
        }

        free(ptr);
        ptr = NULL;  // 避免悬空指针
    }
}

void stringHandlingExample() {
    printf("=== 字符串处理示例 ===\n");

    char dest[10];
    char* src = "This is a very long string";

    // 错误:可能导致缓冲区溢出
    // strcpy(dest, src);

    // 正确:使用安全的字符串函数
    strncpy(dest, src, sizeof(dest) - 1);
    dest[sizeof(dest) - 1] = '\0';

    printf("安全复制的字符串: %s\n", dest);
}

void nullPointerExample() {
    printf("=== 空指针检查示例 ===\n");

    int* ptr = NULL;

    // 错误:不检查空指针
    // *ptr = 10;  // 危险!解引用空指针

    // 正确:检查空指针
    if (ptr != NULL) {
        *ptr = 10;
    } else {
        printf("指针为空,无法解引用\n");
    }
}

int main() {
    arrayBoundsExample();
    memoryLeakExample();
    stringHandlingExample();
    nullPointerExample();

    return 0;
}

学习建议

学习路径

  1. 基础语法阶段(1-2周)

    • 数据类型和变量
    • 运算符和表达式
    • 控制结构(if、for、while)
    • 函数基础
  2. 进阶概念阶段(2-3周)

    • 数组和字符串
    • 指针基础
    • 结构体和联合体
    • 文件操作
  3. 高级特性阶段(2-3周)

    • 动态内存管理
    • 预处理器
    • 多文件编程
    • 调试技巧
  4. 实战项目阶段(2-4周)

    • 完成小型项目
    • 代码优化
    • 错误处理
    • 代码规范

练习建议

  1. 每日编程:每天至少写一个小程序
  2. 代码阅读:阅读优秀的开源C代码
  3. 项目实践:完成实际的项目
  4. 调试练习:学会使用调试器
  5. 代码审查:让他人审查你的代码

推荐资源

  • 书籍

    • 《C程序设计语言》(K&R)
    • 《C和指针》
    • 《C陷阱与缺陷》
  • 在线资源

    • cppreference.com
    • GeeksforGeeks C编程
    • LeetCode算法练习
  • 开发工具

    • GCC编译器
    • GDB调试器
    • Valgrind内存检查
    • Static分析工具

常见面试题目

  1. 指针和数组的区别
  2. 内存分配函数的区别(malloc、calloc、realloc)
  3. 结构体内存对齐
  4. 函数指针的使用
  5. 预处理器的工作原理
  6. 字符串处理函数的实现
  7. 链表、栈、队列的实现
  8. 文件操作和错误处理

总结

C语言作为一门经典的编程语言,具有以下特点:

优势

  • 高效性:接近硬件,执行效率高
  • 可移植性:标准化程度高,跨平台性好
  • 灵活性:提供底层控制能力
  • 基础性:是学习其他语言的良好基础

应用领域

  • 系统编程(操作系统、驱动程序)
  • 嵌入式开发
  • 高性能计算
  • 网络编程
  • 数据库系统

学习要点

  1. 扎实基础:掌握基本语法和概念
  2. 理解内存:深入理解内存管理
  3. 指针精通:熟练掌握指针操作
  4. 实践为主:通过项目巩固知识
  5. 代码规范:养成良好的编程习惯

通过系统学习和大量实践,您将能够熟练掌握C语言,为后续的编程学习和职业发展打下坚实的基础。记住,编程是一门实践性很强的技能,只有通过不断的练习和项目实战,才能真正掌握C语言的精髓。

你可能感兴趣的:(C语言,c语言)