C语言完整教学文档(适用小白,项目实战有学生管理系统等三个基础项目)

C语言完整教学文档

目录


一、C语言简介

1.1 什么是C语言

C语言是一种通用的、过程式的计算机编程语言,由Dennis Ritchie于1972年在贝尔实验室开发,最初用于编写UNIX操作系统。

1.2 C语言特点

特点说明
高效性接近硬件,执行速度快
可移植性可在不同平台上运行
灵活性既能进行底层操作,又能实现复杂算法
基础性很多现代语言(C++、Java、Python)都受C影响
广泛应用操作系统、嵌入式、游戏引擎等

1.3 C语言应用领域

C语言应用
操作系统
嵌入式系统
编译器开发
数据库系统
网络编程
游戏引擎
驱动程序
Linux/Unix
单片机/物联网
GCC/LLVM
MySQL/Redis

1.4 C语言发展历程

年份版本重要特性
1972诞生Dennis Ritchie开发
1978K&R C《The C Programming Language》出版
1989ANSI C (C89)第一个标准化版本
1999C99添加新数据类型、变长数组等
2011C11多线程支持、改进Unicode
2018C18Bug修复和澄清

二、开发环境搭建

2.1 Windows环境

方法1:安装MinGW
1. 下载MinGW安装器
   访问:https://sourceforge.net/projects/mingw/

2. 安装GCC编译器
   - 选择 mingw32-gcc-g++
   - 选择 mingw32-base

3. 配置环境变量
   将 C:\MinGW\bin 添加到系统PATH

4. 验证安装
   打开命令提示符,输入:
   gcc --version
方法2:安装Visual Studio
1. 下载Visual Studio Community(免费)
   https://visualstudio.microsoft.com/

2. 安装时选择"使用C++的桌面开发"

3. 创建C项目
   文件 -> 新建 -> 项目 -> C++空项目
   添加.c文件即可
方法3:使用Dev-C++(推荐初学者)
1. 下载Dev-C++
   https://sourceforge.net/projects/orwelldevcpp/

2. 安装并启动

3. 创建新项目
   文件 -> 新建 -> 项目 -> Console Application

2.2 macOS环境

# 安装Xcode Command Line Tools
xcode-select --install

# 验证安装
gcc --version
clang --version

# 创建第一个程序
echo '#include <stdio.h>
int main() {
    printf("Hello, World!\\n");
    return 0;
}' > hello.c

# 编译
gcc hello.c -o hello

# 运行
./hello

2.3 Linux环境

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

# CentOS/RHEL
sudo yum groupinstall "Development Tools"

# 验证安装
gcc --version

# 编译运行
gcc hello.c -o hello
./hello

2.4 在线编译器(无需安装)

网站特点
OnlineGDB支持调试
Repl.it在线IDE
Ideone多语言支持
Compiler Explorer查看汇编代码

三、基础语法

3.1 第一个C程序

#include <stdio.h>  // 包含标准输入输出库

// 主函数,程序入口
int main() {
    printf("Hello, World!\n");  // 输出文本
    return 0;  // 返回0表示程序正常结束
}

### 3.2 编译与运行

```bash
# 编译(生成可执行文件)
gcc hello.c -o hello

# 运行
./hello    # Linux/macOS
hello.exe  # Windows

# 一步编译运行(仅生成临时文件)
gcc hello.c && ./a.out

3.3 注释

// 这是单行注释

/*
   这是多行注释
   可以写很多行
   常用于函数说明
*/

/**
 * 文档注释(Doxygen风格)
 * @brief 计算两数之和
 * @param a 第一个数
 * @param b 第二个数
 * @return 两数之和
 */
int add(int a, int b) {
    return a + b;
}

3.4 标识符命名规则

// 合法的标识符
int age;
int _count;
int studentAge;
int student_age;
int value123;

// 非法的标识符
// int 123value;  // 不能以数字开头
// int student-age;  // 不能包含连字符
// int int;  // 不能使用关键字

命名规范

类型命名风格示例
变量小写+下划线student_count
常量全大写+下划线MAX_SIZE
函数小写+下划线calculate_sum
全大写+下划线PI_VALUE

3.5 关键字

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

四、数据类型与运算符

4.1 基本数据类型

#include <stdio.h>

int main() {
    // 整型
    int age = 25;                    // 整数(通常4字节)
    short height = 170;              // 短整型(2字节)
    long population = 1400000000L;   // 长整型(4或8字节)
    long long bigNumber = 9223372036854775807LL;  // 超长整型(8字节)
    
    // 字符型
    char grade = 'A';                // 字符(1字节)
    
    // 浮点型
    float pi = 3.14159f;             // 单精度浮点(4字节)
    double e = 2.718281828;          // 双精度浮点(8字节)
    
    // 无符号类型
    unsigned int count = 100;        // 无符号整数(只能为正)
    
    // 打印各类型大小
    printf("int: %zu bytes\n", sizeof(int));
    printf("char: %zu bytes\n", sizeof(char));
    printf("float: %zu bytes\n", sizeof(float));
    printf("double: %zu bytes\n", sizeof(double));
    
    return 0;
}

数据类型范围表

类型大小范围
char1字节-128 到 127
unsigned char1字节0 到 255
short2字节-32,768 到 32,767
int4字节-2,147,483,648 到 2,147,483,647
long4/8字节取决于系统
float4字节3.4E-38 到 3.4E+38
double8字节1.7E-308 到 1.7E+308

4.2 格式化输出

#include <stdio.h>

int main() {
    int num = 42;
    float pi = 3.14159;
    char ch = 'A';
    char str[] = "Hello";
    
    // 基本格式
    printf("整数: %d\n", num);           // 十进制整数
    printf("浮点数: %f\n", pi);          // 浮点数
    printf("字符: %c\n", ch);            // 字符
    printf("字符串: %s\n", str);         // 字符串
    
    // 进制转换
    printf("八进制: %o\n", num);         // 52
    printf("十六进制: %x\n", num);       // 2a
    printf("十六进制(大写): %X\n", num); // 2A
    
    // 宽度和精度
    printf("右对齐: %5d\n", num);        // "   42"
    printf("左对齐: %-5d\n", num);       // "42   "
    printf("补零: %05d\n", num);         // "00042"
    printf("保留2位小数: %.2f\n", pi);   // "3.14"
    printf("宽度10,2位小数: %10.2f\n", pi);  // "      3.14"
    
    return 0;
}

4.3 算术运算符

#include <stdio.h>

int main() {
    int a = 10, b = 3;
    
    printf("加法: %d + %d = %d\n", a, b, a + b);      // 13
    printf("减法: %d - %d = %d\n", a, b, a - b);      // 7
    printf("乘法: %d * %d = %d\n", a, b, a * b);      // 30
    printf("除法: %d / %d = %d\n", a, b, a / b);      // 3(整数除法)
    printf("取余: %d %% %d = %d\n", a, b, a % b);     // 1
    
    // 浮点除法
    float result = (float)a / b;
    printf("浮点除法: %.2f\n", result);                // 3.33
    
    // 自增自减
    int x = 5;
    printf("x++: %d\n", x++);  // 先使用再加1,输出5
    printf("++x: %d\n", ++x);  // 先加1再使用,输出7
    
    return 0;
}

4.4 关系运算符

#include <stdio.h>

int main() {
    int a = 5, b = 10;
    
    printf("%d == %d: %d\n", a, b, a == b);  // 0(假)
    printf("%d != %d: %d\n", a, b, a != b);  // 1(真)
    printf("%d > %d: %d\n", a, b, a > b);    // 0
    printf("%d < %d: %d\n", a, b, a < b);    // 1
    printf("%d >= %d: %d\n", a, b, a >= b);  // 0
    printf("%d <= %d: %d\n", a, b, a <= b);  // 1
    
    return 0;
}

4.5 逻辑运算符

#include <stdio.h>

int main() {
    int x = 5, y = 10, z = 15;
    
    // 逻辑与 &&(短路求值)
    if (x < y && y < z) {
        printf("x < y < z\n");
    }
    
    // 逻辑或 ||
    if (x > 10 || y > 5) {
        printf("至少一个条件为真\n");
    }
    
    // 逻辑非 !
    if (!(x > y)) {
        printf("x 不大于 y\n");
    }
    
    return 0;
}

4.6 位运算符

#include <stdio.h>

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

int main() {
    int a = 12;  // 1100
    int b = 10;  // 1010
    
    printf("a = 12: ");
    printBinary(a);
    printf("b = 10: ");
    printBinary(b);
    
    printf("\na & b (按位与): %d\n", a & b);      // 8 (1000)
    printf("a | b (按位或): %d\n", a | b);        // 14 (1110)
    printf("a ^ b (按位异或): %d\n", a ^ b);      // 6 (0110)
    printf("~a (按位取反): %d\n", ~a);            // -13
    printf("a << 1 (左移): %d\n", a << 1);        // 24 (11000)
    printf("a >> 1 (右移): %d\n", a >> 1);        // 6 (110)
    
    return 0;
}

4.7 运算符优先级

优先级运算符说明
1() [] -> .括号、数组、成员访问
2! ~ ++ -- + - * &一元运算符
3* / %乘除模
4+ -加减
5<< >>位移
6< <= > >=关系
7== !=相等
8&按位与
9^按位异或
10|按位或
11&&逻辑与
12||逻辑或
13?:三元条件
14= += -=赋值

五、控制流程

5.1 if语句

#include <stdio.h>

int main() {
    int score = 85;
    
    // 简单if
    if (score >= 60) {
        printf("及格\n");
    }
    
    // if-else
    if (score >= 60) {
        printf("及格\n");
    } else {
        printf("不及格\n");
    }
    
    // if-else if-else
    if (score >= 90) {
        printf("优秀\n");
    } else if (score >= 80) {
        printf("良好\n");
    } else if (score >= 70) {
        printf("中等\n");
    } else if (score >= 60) {
        printf("及格\n");
    } else {
        printf("不及格\n");
    }
    
    // 嵌套if
    if (score >= 60) {
        if (score >= 90) {
            printf("优秀及格\n");
        } else {
            printf("普通及格\n");
        }
    }
    
    // 三元运算符
    char* result = (score >= 60) ? "及格" : "不及格";
    printf("%s\n", result);
    
    return 0;
}

5.2 switch语句

#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;
        case 4:
            printf("星期四\n");
            break;
        case 5:
            printf("星期五\n");
            break;
        case 6:
        case 7:
            printf("周末\n");
            break;
        default:
            printf("无效的日期\n");
    }
    
    // 字符判断
    char grade = 'B';
    switch (grade) {
        case 'A':
            printf("优秀\n");
            break;
        case 'B':
            printf("良好\n");
            break;
        case 'C':
            printf("中等\n");
            break;
        default:
            printf("需要努力\n");
    }
    
    return 0;
}

5.3 while循环

#include <stdio.h>

int main() {
    // 基本while循环
    int i = 1;
    while (i <= 5) {
        printf("%d ", i);
        i++;
    }
    printf("\n");  // 输出: 1 2 3 4 5
    
    // 计算1到100的和
    int sum = 0, n = 1;
    while (n <= 100) {
        sum += n;
        n++;
    }
    printf("1到100的和: %d\n", sum);  // 5050
    
    // do-while循环(至少执行一次)
    int num;
    do {
        printf("请输入正数(输入0结束): ");
        scanf("%d", &num);
        printf("你输入了: %d\n", num);
    } while (num != 0);
    
    return 0;
}

5.4 for循环

#include <stdio.h>

int main() {
    // 基本for循环
    for (int i = 1; i <= 5; i++) {
        printf("%d ", i);
    }
    printf("\n");
    
    // 倒序循环
    for (int i = 5; i >= 1; i--) {
        printf("%d ", i);
    }
    printf("\n");
    
    // 步长为2
    for (int i = 0; i <= 10; i += 2) {
        printf("%d ", i);  // 0 2 4 6 8 10
    }
    printf("\n");
    
    // 嵌套循环(打印乘法表)
    for (int i = 1; i <= 9; i++) {
        for (int j = 1; j <= i; j++) {
            printf("%d*%d=%d\t", j, i, i*j);
        }
        printf("\n");
    }
    
    return 0;
}

5.5 循环控制

#include <stdio.h>

int main() {
    // break:跳出循环
    for (int i = 1; i <= 10; i++) {
        if (i == 5) {
            break;  // 遇到5就停止
        }
        printf("%d ", i);  // 输出: 1 2 3 4
    }
    printf("\n");
    
    // continue:跳过本次循环
    for (int i = 1; i <= 10; i++) {
        if (i % 2 == 0) {
            continue;  // 跳过偶数
        }
        printf("%d ", i);  // 输出: 1 3 5 7 9
    }
    printf("\n");
    
    // goto语句(不推荐使用)
    int count = 0;
    start:
        printf("%d ", count);
        count++;
        if (count < 5) {
            goto start;
        }
    printf("\n");
    
    return 0;
}

5.6 控制流程图

开始
条件判断
执行语句块
跳过
遇到break?
退出循环
遇到continue?
继续执行
结束

六、函数

6.1 函数定义

#include <stdio.h>

// 函数声明(原型)
int add(int a, int b);
void greet(void);
int max(int a, int b);

// 主函数
int main() {
    int sum = add(5, 3);
    printf("5 + 3 = %d\n", sum);
    
    greet();
    
    int maximum = max(10, 20);
    printf("最大值: %d\n", maximum);
    
    return 0;
}

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

void greet(void) {
    printf("Hello, World!\n");
}

int max(int a, int b) {
    return (a > b) ? a : b;
}

6.2 函数参数传递

#include <stdio.h>

// 值传递(不会改变原变量)
void swapByValue(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
    printf("函数内: a=%d, b=%d\n", a, b);
}

// 地址传递(会改变原变量)
void swapByPointer(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main() {
    int x = 5, y = 10;
    
    printf("交换前: x=%d, y=%d\n", x, y);
    
    swapByValue(x, y);
    printf("值传递后: x=%d, y=%d\n", x, y);  // 不变
    
    swapByPointer(&x, &y);
    printf("地址传递后: x=%d, y=%d\n", x, y);  // 已交换
    
    return 0;
}

6.3 递归函数

#include <stdio.h>

// 阶乘
int factorial(int n) {
    if (n == 0 || n == 1) {
        return 1;  // 基准情况
    }
    return n * factorial(n - 1);  // 递归调用
}

// 斐波那契数列
int fibonacci(int n) {
    if (n == 0) return 0;
    if (n == 1) return 1;
    return fibonacci(n - 1) + fibonacci(n - 2);
}

// 汉诺塔
void hanoi(int n, char from, char to, char aux) {
    if (n == 1) {
        printf("移动盘子1从 %c 到 %c\n", from, to);
        return;
    }
    hanoi(n - 1, from, aux, to);
    printf("移动盘子%d从 %c 到 %c\n", n, from, to);
    hanoi(n - 1, aux, to, from);
}

int main() {
    // 阶乘
    printf("5! = %d\n", factorial(5));  // 120
    
    // 斐波那契
    printf("斐波那契数列前10项: ");
    for (int i = 0; i < 10; i++) {
        printf("%d ", fibonacci(i));
    }
    printf("\n");
    
    // 汉诺塔
    printf("\n汉诺塔(3个盘子):\n");
    hanoi(3, 'A', 'C', 'B');
    
    return 0;
}

6.4 可变参数函数

#include <stdio.h>
#include <stdarg.h>

// 计算多个整数的和
int sum(int count, ...) {
    va_list args;
    va_start(args, count);
    
    int total = 0;
    for (int i = 0; i < count; i++) {
        total += va_arg(args, int);
    }
    
    va_end(args);
    return total;
}

// 查找最大值
int max(int count, ...) {
    va_list args;
    va_start(args, count);
    
    int maximum = va_arg(args, int);
    for (int i = 1; i < count; i++) {
        int value = va_arg(args, int);
        if (value > maximum) {
            maximum = value;
        }
    }
    
    va_end(args);
    return maximum;
}

int main() {
    printf("2个数的和: %d\n", sum(2, 10, 20));
    printf("5个数的和: %d\n", sum(5, 1, 2, 3, 4, 5));
    
    printf("最大值: %d\n", max(4, 10, 50, 30, 20));
    
    return 0;
}

七、数组与字符串

7.1 一维数组

#include <stdio.h>

int main() {
    // 数组声明和初始化
    int arr1[5];  // 声明
    int arr2[5] = {1, 2, 3, 4, 5};  // 完全初始化
    int arr3[] = {1, 2, 3};  // 自动推断大小
    int arr4[5] = {1, 2};  // 部分初始化,其余为0
    
    // 访问数组元素
    printf("arr2[0] = %d\n", arr2[0]);
    arr2[0] = 10;
    printf("修改后 arr2[0] = %d\n", arr2[0]);
    
    // 遍历数组
    printf("数组元素: ");
    for (int i = 0; i < 5; i++) {
        printf("%d ", arr2[i]);
    }
    printf("\n");
    
    // 计算数组长度
    int len = sizeof(arr2) / sizeof(arr2[0]);
    printf("数组长度: %d\n", len);
    
    // 数组求和
    int sum = 0;
    for (int i = 0; i < 5; i++) {
        sum += arr2[i];
    }
    printf("数组和: %d\n", sum);
    
    // 查找最大值
    int max = arr2[0];
    for (int i = 1; i < 5; i++) {
        if (arr2[i] > max) {
            max = arr2[i];
        }
    }
    printf("最大值: %d\n", max);
    
    return 0;
}

7.2 二维数组

#include <stdio.h>

int main() {
    // 二维数组声明和初始化
    int matrix[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    };
    
    // 访问元素
    printf("matrix[1][2] = %d\n", matrix[1][2]);  // 7
    
    // 遍历二维数组
    printf("矩阵:\n");
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%3d ", matrix[i][j]);
        }
        printf("\n");
    }
    
    // 矩阵转置
    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转置矩阵:\n");
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 3; j++) {
            printf("%3d ", transpose[i][j]);
        }
        printf("\n");
    }
    
    return 0;
}

7.3 字符串基础

#include <stdio.h>
#include <string.h>

int main() {
    // 字符串声明
    char str1[] = "Hello";  // 自动添加\0
    char str2[10] = "World";
    char str3[] = {'H', 'i', '\0'};  // 必须手动添加\0
    
    // 输出字符串
    printf("%s\n", str1);
    printf("%s\n", str2);
    
    // 字符串长度
    printf("str1长度: %zu\n", strlen(str1));
    
    // 字符串复制
    char dest[20];
    strcpy(dest, str1);
    printf("复制后: %s\n", dest);
    
    // 字符串拼接
    strcat(dest, " ");
    strcat(dest, str2);
    printf("拼接后: %s\n", dest);
    
    // 字符串比较
    if (strcmp(str1, str2) == 0) {
        printf("字符串相同\n");
    } else {
        printf("字符串不同\n");
    }
    
    // 字符串查找
    char *pos = strstr(dest, "World");
    if (pos != NULL) {
        printf("找到World,位置: %ld\n", pos - dest);
    }
    
    return 0;
}

7.4 字符串常用函数

#include <stdio.h>
#include <string.h>
#include <ctype.h>

int main() {
    char str[] = "Hello, World!";
    
    // strlen - 字符串长度
    printf("长度: %zu\n", strlen(str));
    
    // strcpy - 复制
    char copy[50];
    strcpy(copy, str);
    
    // strncpy - 复制n个字符
    char partial[10];
    strncpy(partial, str, 5);
    partial[5] = '\0';
    printf("前5个字符: %s\n", partial);
    
    // strcat - 拼接
    strcat(copy, " Welcome!");
    printf("拼接后: %s\n", copy);
    
    // strcmp - 比较
    printf("strcmp结果: %d\n", strcmp("abc", "abc"));  // 0
    
    // strchr - 查找字符
    char *ch = strchr(str, 'W');
    if (ch) printf("找到W: %s\n", ch);
    
    // strstr - 查找子串
    char *sub = strstr(str, "World");
    if (sub) printf("找到World: %s\n", sub);
    
    // 转大写
    char upper[50];
    strcpy(upper, str);
    for (int i = 0; upper[i]; i++) {
        upper[i] = toupper(upper[i]);
    }
    printf("大写: %s\n", upper);
    
    // 转小写
    for (int i = 0; upper[i]; i++) {
        upper[i] = tolower(upper[i]);
    }
    printf("小写: %s\n", upper);
    
    return 0;
}

7.5 字符串数组

#include <stdio.h>
#include <string.h>

int main() {
    // 字符串数组
    char *fruits[] = {
        "Apple",
        "Banana",
        "Cherry",
        "Date"
    };
    
    int count = sizeof(fruits) / sizeof(fruits[0]);
    
    printf("水果列表:\n");
    for (int i = 0; i < count; i++) {
        printf("%d. %s\n", i+1, fruits[i]);
    }
    
    // 二维字符数组
    char names[3][20] = {
        "Alice",
        "Bob",
        "Charlie"
    };
    
    printf("\n名字列表:\n");
    for (int i = 0; i < 3; i++) {
        printf("%s\n", names[i]);
    }
    
    // 字符串排序(冒泡排序)
    char *items[] = {"Zebra", "Apple", "Mango", "Banana"};
    int n = 4;
    
    for (int i = 0; i < n-1; i++) {
        for (int j = 0; j < n-i-1; j++) {
            if (strcmp(items[j], items[j+1]) > 0) {
                char *temp = items[j];
                items[j] = items[j+1];
                items[j+1] = temp;
            }
        }
    }
    
    printf("\n排序后:\n");
    for (int i = 0; i < n; i++) {
        printf("%s\n", items[i]);
    }
    
    return 0;
}

八、指针

8.1 指针基础

#include <stdio.h>

int main() {
    int num = 42;
    int *ptr;  // 声明指针
    
    ptr = &num;  // 获取num的地址
    
    printf("num的值: %d\n", num);
    printf("num的地址: %p\n", (void*)&num);
    printf("ptr存储的地址: %p\n", (void*)ptr);
    printf("ptr指向的值: %d\n", *ptr);
    
    // 通过指针修改值
    *ptr = 100;
    printf("修改后num的值: %d\n", num);
    
    // 指针的大小(通常8字节在64位系统)
    printf("指针大小: %zu bytes\n", sizeof(ptr));
    
    return 0;
}

8.2 指针与数组

#include <stdio.h>

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int *ptr = arr;  // 数组名就是指向首元素的指针
    
    // 通过指针访问数组
    printf("第一个元素: %d\n", *ptr);
    printf("第二个元素: %d\n", *(ptr + 1));
    
    // 指针遍历数组
    printf("数组元素: ");
    for (int i = 0; i < 5; i++) {
        printf("%d ", *(ptr + i));
        // 等价于 ptr[i] 或 arr[i]
    }
    printf("\n");
    
    // 指针算术
    printf("\n指针移动:\n");
    ptr = arr;
    printf("*ptr = %d\n", *ptr);  // 10
    ptr++;
    printf("*ptr = %d\n", *ptr);  // 20
    ptr += 2;
    printf("*ptr = %d\n", *ptr);  // 40
    
    return 0;
}

8.3 指针与字符串

#include <stdio.h>
#include <string.h>

int main() {
    // 字符串指针
    char *str1 = "Hello";  // 字符串常量
    char str2[] = "World";  // 字符数组
    
    printf("str1: %s\n", str1);
    printf("str2: %s\n", str2);
    
    // str1[0] = 'h';  // 错误!不能修改字符串常量
    str2[0] = 'w';     // 正确,可以修改数组
    
    // 遍历字符串
    char *p = str2;
    while (*p != '\0') {
        printf("%c ", *p);
        p++;
    }
    printf("\n");
    
    // 字符串数组
    char *fruits[] = {"Apple", "Banana", "Cherry"};
    for (int i = 0; i < 3; i++) {
        printf("%s\n", fruits[i]);
    }
    
    return 0;
}

8.4 指针与函数

#include <stdio.h>

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

// 通过指针返回多个值
void getMinMax(int arr[], int size, int *min, int *max) {
    *min = *max = arr[0];
    for (int i = 1; i < size; i++) {
        if (arr[i] < *min) *min = arr[i];
        if (arr[i] > *max) *max = arr[i];
    }
}

// 返回指针的函数
int* getMiddle(int arr[], int size) {
    return &arr[size/2];
}

int main() {
    // 交换函数
    int x = 5, y = 10;
    printf("交换前: x=%d, y=%d\n", x, y);
    swap(&x, &y);
    printf("交换后: x=%d, y=%d\n", x, y);
    
    // 获取最值
    int numbers[] = {45, 23, 78, 12, 90, 34};
    int min, max;
    getMinMax(numbers, 6, &min, &max);
    printf("最小值: %d, 最大值: %d\n", min, max);
    
    // 返回指针
    int *middle = getMiddle(numbers, 6);
    printf("中间元素: %d\n", *middle);
    
    return 0;
}

8.5 多级指针

#include <stdio.h>

int main() {
    int num = 42;
    int *ptr1 = &num;     // 一级指针
    int **ptr2 = &ptr1;   // 二级指针
    int ***ptr3 = &ptr2;  // 三级指针
    
    printf("num = %d\n", num);
    printf("*ptr1 = %d\n", *ptr1);
    printf("**ptr2 = %d\n", **ptr2);
    printf("***ptr3 = %d\n", ***ptr3);
    
    // 通过多级指针修改值
    ***ptr3 = 100;
    printf("修改后 num = %d\n", num);
    
    // 指针数组(字符串数组)
    char *names[] = {"Alice", "Bob", "Charlie"};
    char **p = names;
    
    printf("\n名字列表:\n");
    for (int i = 0; i < 3; i++) {
        printf("%s\n", *(p + i));
    }
    
    return 0;
}

8.6 函数指针

#include <stdio.h>

// 普通函数
int add(int a, int b) {
    return a + b;
}

int subtract(int a, int b) {
    return a - b;
}

int multiply(int a, int b) {
    return a * b;
}

// 接受函数指针的函数
int calculate(int a, int b, int (*operation)(int, int)) {
    return operation(a, b);
}

int main() {
    // 声明函数指针
    int (*func_ptr)(int, int);
    
    // 使用函数指针
    func_ptr = add;
    printf("10 + 5 = %d\n", func_ptr(10, 5));
    
    func_ptr = subtract;
    printf("10 - 5 = %d\n", func_ptr(10, 5));
    
    // 函数指针数组
    int (*operations[])(int, int) = {add, subtract, multiply};
    char *symbols[] = {"+", "-", "*"};
    
    for (int i = 0; i < 3; i++) {
        printf("10 %s 5 = %d\n", symbols[i], operations[i](10, 5));
    }
    
    // 作为参数传递
    printf("\n使用calculate函数:\n");
    printf("10 + 5 = %d\n", calculate(10, 5, add));
    printf("10 * 5 = %d\n", calculate(10, 5, multiply));
    
    return 0;
}

九、结构体与联合体

9.1 结构体基础

#include <stdio.h>
#include <string.h>

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

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

int main() {
    // 声明和初始化
    struct Student s1 = {1, "Alice", 20, 95.5};
    struct Student s2;
    
    // 赋值
    s2.id = 2;
    strcpy(s2.name, "Bob");
    s2.age = 21;
    s2.score = 88.0;
    
    // 访问成员
    printf("学生1: ID=%d, 姓名=%s, 年龄=%d, 成绩=%.1f\n",
           s1.id, s1.name, s1.age, s1.score);
    
    // 使用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);
    
    // 结构体数组
    struct Student students[3] = {
        {1, "Alice", 20, 95.5},
        {2, "Bob", 21, 88.0},
        {3, "Charlie", 19, 92.3}
    };
    
    printf("\n学生列表:\n");
    for (int i = 0; i < 3; i++) {
        printf("%d. %s - %.1f分\n",
               students[i].id, students[i].name, students[i].score);
    }
    
    return 0;
}

9.2 结构体指针

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

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

// 打印员工信息
void printEmployee(Employee *emp) {
    printf("ID: %d, 姓名: %s, 工资: %.2f\n",
           emp->id, emp->name, emp->salary);
}

// 动态创建员工
Employee* createEmployee(int id, const char *name, float salary) {
    Employee *emp = (Employee*)malloc(sizeof(Employee));
    if (emp == NULL) {
        return NULL;
    }
    
    emp->id = id;
    strcpy(emp->name, name);
    emp->salary = salary;
    
    return emp;
}

int main() {
    // 栈上分配
    Employee e1 = {1, "Alice", 50000.0};
    Employee *ptr = &e1;
    
    // 通过指针访问
    printf("方式1: %s\n", (*ptr).name);
    printf("方式2: %s\n", ptr->name);
    
    // 动态分配
    Employee *e2 = createEmployee(2, "Bob", 60000.0);
    if (e2 != NULL) {
        printEmployee(e2);
        free(e2);  // 释放内存
    }
    
    return 0;
}

9.3 嵌套结构体

#include <stdio.h>
#include <string.h>

// 日期结构体
typedef struct {
    int year;
    int month;
    int day;
} Date;

// 地址结构体
typedef struct {
    char street[100];
    char city[50];
    char country[50];
} Address;

// 人员结构体(嵌套)
typedef struct {
    char name[50];
    Date birthday;
    Address address;
} Person;

int main() {
    Person p = {
        "Alice",
        {1995, 5, 15},
        {"123 Main St", "New York", "USA"}
    };
    
    printf("姓名: %s\n", p.name);
    printf("生日: %d-%02d-%02d\n",
           p.birthday.year, p.birthday.month, p.birthday.day);
    printf("地址: %s, %s, %s\n",
           p.address.street, p.address.city, p.address.country);
    
    return 0;
}

9.4 联合体

#include <stdio.h>

// 联合体:所有成员共享同一块内存
union Data {
    int i;
    float f;
    char str[20];
};

int main() {
    union Data data;
    
    printf("联合体大小: %zu bytes\n", sizeof(data));
    
    // 赋值给int成员
    data.i = 10;
    printf("data.i = %d\n", data.i);
    
    // 赋值给float成员(会覆盖int)
    data.f = 3.14;
    printf("data.f = %.2f\n", data.f);
    printf("data.i = %d(已被覆盖)\n", data.i);
    
    // 赋值给字符串
    snprintf(data.str, sizeof(data.str), "Hello");
    printf("data.str = %s\n", data.str);
    
    return 0;
}

9.5 枚举类型

#include <stdio.h>

// 定义枚举
enum Weekday {
    MONDAY,     // 0
    TUESDAY,    // 1
    WEDNESDAY,  // 2
    THURSDAY,   // 3
    FRIDAY,     // 4
    SATURDAY,   // 5
    SUNDAY      // 6
};

// 指定值的枚举
enum Color {
    RED = 1,
    GREEN = 2,
    BLUE = 4,
    YELLOW = 8
};

int main() {
    enum Weekday today = WEDNESDAY;
    
    switch(today) {
        case MONDAY:
            printf("星期一\n");
            break;
        case WEDNESDAY:
            printf("星期三\n");
            break;
        default:
            printf("其他日期\n");
    }
    
    // 枚举作为标志位
    enum Color myColor = RED | BLUE;  // 位或操作
    
    if (myColor & RED) {
        printf("包含红色\n");
    }
    
    if (myColor & BLUE) {
        printf("包含蓝色\n");
    }
    
    return 0;
}

十、文件操作

10.1 文件基础

#include <stdio.h>

int main() {
    FILE *fp;
    
    // 写入文件
    fp = fopen("test.txt", "w");
    if (fp == NULL) {
        printf("无法打开文件\n");
        return 1;
    }
    
    fprintf(fp, "Hello, World!\n");
    fprintf(fp, "这是第二行\n");
    fprintf(fp, "数字: %d\n", 42);
    
    fclose(fp);
    printf("文件写入成功\n");
    
    // 读取文件
    fp = fopen("test.txt", "r");
    if (fp == NULL) {
        printf("无法打开文件\n");
        return 1;
    }
    
    char buffer[100];
    printf("\n文件内容:\n");
    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
        printf("%s", buffer);
    }
    
    fclose(fp);
    
    return 0;
}

10.2 文件模式

模式说明
"r"只读,文件必须存在
"w"只写,文件不存在则创建,存在则清空
"a"追加,文件不存在则创建
"r+"读写,文件必须存在
"w+"读写,文件不存在则创建,存在则清空
"a+"读写,追加模式
"rb" "wb"二进制模式

10.3 字符和字符串IO

#include <stdio.h>

int main() {
    FILE *fp;
    
    // 写入字符
    fp = fopen("chars.txt", "w");
    fputc('A', fp);
    fputc('B', fp);
    fputc('C', fp);
    fclose(fp);
    
    // 读取字符
    fp = fopen("chars.txt", "r");
    int ch;
    while ((ch = fgetc(fp)) != EOF) {
        printf("%c ", ch);
    }
    printf("\n");
    fclose(fp);
    
    // 写入字符串
    fp = fopen("strings.txt", "w");
    fputs("第一行\n", fp);
    fputs("第二行\n", fp);
    fclose(fp);
    
    // 读取字符串
    fp = fopen("strings.txt", "r");
    char buffer[100];
    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
        printf("%s", buffer);
    }
    fclose(fp);
    
    return 0;
}

10.4 格式化IO

#include <stdio.h>

typedef struct {
    int id;
    char name[50];
    float score;
} Student;

int main() {
    FILE *fp;
    Student students[] = {
        {1, "Alice", 95.5},
        {2, "Bob", 88.0},
        {3, "Charlie", 92.3}
    };
    
    // 写入格式化数据
    fp = fopen("students.txt", "w");
    for (int i = 0; i < 3; i++) {
        fprintf(fp, "%d %s %.1f\n",
                students[i].id, students[i].name, students[i].score);
    }
    fclose(fp);
    
    // 读取格式化数据
    fp = fopen("students.txt", "r");
    Student s;
    
    printf("学生列表:\n");
    while (fscanf(fp, "%d %s %f", &s.id, s.name, &s.score) == 3) {
        printf("ID: %d, 姓名: %s, 成绩: %.1f\n",
               s.id, s.name, s.score);
    }
    fclose(fp);
    
    return 0;
}

10.5 二进制文件

#include <stdio.h>
#include <string.h>

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

int main() {
    FILE *fp;
    Employee employees[] = {
        {1, "Alice", 50000.0},
        {2, "Bob", 60000.0},
        {3, "Charlie", 55000.0}
    };
    
    // 写入二进制
    fp = fopen("employees.dat", "wb");
    fwrite(employees, sizeof(Employee), 3, fp);
    fclose(fp);
    printf("二进制文件写入成功\n");
    
    // 读取二进制
    fp = fopen("employees.dat", "rb");
    Employee emp;
    
    printf("\n员工列表:\n");
    while (fread(&emp, sizeof(Employee), 1, fp) == 1) {
        printf("ID: %d, 姓名: %s, 工资: %.2f\n",
               emp.id, emp.name, emp.salary);
    }
    fclose(fp);
    
    return 0;
}

10.6 文件定位

#include <stdio.h>

int main() {
    FILE *fp = fopen("test.txt", "w+");
    
    // 写入数据
    fprintf(fp, "0123456789");
    
    // 移动到开头
    rewind(fp);
    printf("当前位置: %ld\n", ftell(fp));
    
    // 移动文件指针
    fseek(fp, 5, SEEK_SET);  // 从开头移动5个字节
    printf("当前位置: %ld\n", ftell(fp));
    
    // 读取字符
    int ch = fgetc(fp);
    printf("读取字符: %c\n", ch);
    
    // 移动到末尾
    fseek(fp, 0, SEEK_END);
    printf("文件大小: %ld bytes\n", ftell(fp));
    
    fclose(fp);
    return 0;
}

十一、动态内存管理

11.1 malloc和free

#include <stdio.h>
#include <stdlib.h>

int main() {
    // 分配单个整数
    int *ptr = (int*)malloc(sizeof(int));
    if (ptr == NULL) {
        printf("内存分配失败\n");
        return 1;
    }
    
    *ptr = 42;
    printf("值: %d\n", *ptr);
    free(ptr);  // 释放内存
    
    // 分配数组
    int n = 5;
    int *arr = (int*)malloc(n * sizeof(int));
    if (arr == NULL) {
        printf("内存分配失败\n");
        return 1;
    }
    
    // 初始化数组
    for (int i = 0; i < n; i++) {
        arr[i] = i * 10;
    }
    
    // 打印数组
    printf("数组: ");
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
    
    free(arr);  // 释放数组
    
    return 0;
}

11.2 calloc和realloc

#include <stdio.h>
#include <stdlib.h>

int main() {
    // calloc - 分配并初始化为0
    int *arr1 = (int*)calloc(5, sizeof(int));
    printf("calloc分配的数组: ");
    for (int i = 0; i < 5; i++) {
        printf("%d ", arr1[i]);  // 都是0
    }
    printf("\n");
    
    // realloc - 重新分配大小
    arr1 = (int*)realloc(arr1, 10 * sizeof(int));
    if (arr1 == NULL) {
        printf("重新分配失败\n");
        return 1;
    }
    
    // 初始化新元素
    for (int i = 5; i < 10; i++) {
        arr1[i] = i;
    }
    
    printf("扩展后的数组: ");
    for (int i = 0; i < 10; i++) {
        printf("%d ", arr1[i]);
    }
    printf("\n");
    
    free(arr1);
    
    return 0;
}

11.3 动态二维数组

#include <stdio.h>
#include <stdlib.h>

int main() {
    int rows = 3, cols = 4;
    
    // 方法1: 指针数组
    int **matrix = (int**)malloc(rows * sizeof(int*));
    for (int i = 0; i < rows; i++) {
        matrix[i] = (int*)malloc(cols * sizeof(int));
    }
    
    // 初始化
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            matrix[i][j] = i * cols + j;
        }
    }
    
    // 打印
    printf("矩阵:\n");
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%3d ", matrix[i][j]);
        }
        printf("\n");
    }
    
    // 释放内存
    for (int i = 0; i < rows; i++) {
        free(matrix[i]);
    }
    free(matrix);
    
    return 0;
}

11.4 内存泄漏检测

#include <stdio.h>
#include <stdlib.h>

// 内存泄漏示例(错误)
void memory_leak() {
    int *ptr = (int*)malloc(sizeof(int));
    *ptr = 42;
    // 忘记free(ptr) - 内存泄漏!
}

// 正确的内存管理
void proper_management() {
    int *ptr = (int*)malloc(sizeof(int));
    if (ptr == NULL) {
        return;
    }
    
    *ptr = 42;
    printf("值: %d\n", *ptr);
    
    free(ptr);  // 正确释放
    ptr = NULL;  // 防止野指针
}

int main() {
    proper_management();
    
    // 使用Valgrind检测内存泄漏:
    // gcc program.c -o program
    // valgrind --leak-check=full ./program
    
    return 0;
}

十二、预处理器

12.1 宏定义

#include <stdio.h>

// 简单宏
#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 PRINT_ARRAY(arr, size) \
    do { \
        for (int i = 0; i < (size); i++) { \
            printf("%d ", (arr)[i]); \
        } \
        printf("\n"); \
    } while(0)

int main() {
    // 使用简单宏
    printf("圆周率: %f\n", PI);
    printf("最大容量: %d\n", MAX_SIZE);
    
    // 使用宏函数
    printf("5的平方: %d\n", SQUARE(5));
    printf("最大值: %d\n", MAX(10, 20));
    
    // 使用多行宏
    int arr[] = {1, 2, 3, 4, 5};
    printf("数组: ");
    PRINT_ARRAY(arr, 5);
    
    return 0;
}

12.2 条件编译

#include <stdio.h>

#define DEBUG 1
#define VERSION 2

int main() {
    // #ifdef - 如果定义了
    #ifdef DEBUG
        printf("调试模式开启\n");
    #endif
    
    // #ifndef - 如果没定义
    #ifndef RELEASE
        printf("非发布版本\n");
    #endif
    
    // #if - 条件判断
    #if VERSION == 1
        printf("版本 1\n");
    #elif VERSION == 2
        printf("版本 2\n");
    #else
        printf("未知版本\n");
    #endif
    
    // 预定义宏
    printf("文件: %s\n", __FILE__);
    printf("行号: %d\n", __LINE__);
    printf("日期: %s\n", __DATE__);
    printf("时间: %s\n", __TIME__);
    
    return 0;
}

12.3 文件包含

// math_utils.h
#ifndef MATH_UTILS_H
#define MATH_UTILS_H

int add(int a, int b);
int multiply(int a, int b);

#endif

// math_utils.c
#include "math_utils.h"

int add(int a, int b) {
    return a + b;
}

int multiply(int a, int b) {
    return a * b;
}

// main.c
#include <stdio.h>
#include "math_utils.h"

int main() {
    printf("10 + 5 = %d\n", add(10, 5));
    printf("10 * 5 = %d\n", multiply(10, 5));
    return 0;
}

十三、实战项目

13.1 项目1: 学生管理系统

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_STUDENTS 100
#define NAME_LENGTH 50

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

Student students[MAX_STUDENTS];
int student_count = 0;

// 添加学生
void addStudent() {
    if (student_count >= MAX_STUDENTS) {
        printf("学生数量已达上限\n");
        return;
    }
    
    Student *s = &students[student_count];
    
    printf("输入学号: ");
    scanf("%d", &s->id);
    printf("输入姓名: ");
    scanf("%s", s->name);
    printf("输入年龄: ");
    scanf("%d", &s->age);
    printf("输入成绩: ");
    scanf("%f", &s->score);
    
    student_count++;
    printf("添加成功!\n");
}

// 显示所有学生
void displayStudents() {
    if (student_count == 0) {
        printf("暂无学生记录\n");
        return;
    }
    
    printf("\n%-10s %-20s %-10s %-10s\n", "学号", "姓名", "年龄", "成绩");
    printf("----------------------------------------------------------\n");
    
    for (int i = 0; i < student_count; i++) {
        printf("%-10d %-20s %-10d %-10.1f\n",
               students[i].id,
               students[i].name,
               students[i].age,
               students[i].score);
    }
}

// 查找学生
void searchStudent() {
    int id;
    printf("输入要查找的学号: ");
    scanf("%d", &id);
    
    for (int i = 0; i < student_count; i++) {
        if (students[i].id == id) {
            printf("\n找到学生:\n");
            printf("学号: %d\n", students[i].id);
            printf("姓名: %s\n", students[i].name);
            printf("年龄: %d\n", students[i].age);
            printf("成绩: %.1f\n", students[i].score);
            return;
        }
    }
    
    printf("未找到该学生\n");
}

// 删除学生
void deleteStudent() {
    int id;
    printf("输入要删除的学号: ");
    scanf("%d", &id);
    
    for (int i = 0; i < student_count; i++) {
        if (students[i].id == id) {
            // 后面的学生前移
            for (int j = i; j < student_count - 1; j++) {
                students[j] = students[j + 1];
            }
            student_count--;
            printf("删除成功!\n");
            return;
        }
    }
    
    printf("未找到该学生\n");
}

// 保存到文件
void saveToFile() {
    FILE *fp = fopen("students.dat", "wb");
    if (fp == NULL) {
        printf("无法打开文件\n");
        return;
    }
    
    fwrite(&student_count, sizeof(int), 1, fp);
    fwrite(students, sizeof(Student), student_count, fp);
    fclose(fp);
    
    printf("保存成功!\n");
}

// 从文件加载
void loadFromFile() {
    FILE *fp = fopen("students.dat", "rb");
    if (fp == NULL) {
        printf("文件不存在\n");
        return;
    }
    
    fread(&student_count, sizeof(int), 1, fp);
    fread(students, sizeof(Student), student_count, fp);
    fclose(fp);
    
    printf("加载成功! 共%d条记录\n", student_count);
}

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("==================================\n");
        printf("请选择: ");
        scanf("%d", &choice);
        
        switch (choice) {
            case 1:
                addStudent();
                break;
            case 2:
                displayStudents();
                break;
            case 3:
                searchStudent();
                break;
            case 4:
                deleteStudent();
                break;
            case 5:
                saveToFile();
                break;
            case 6:
                saveToFile();
                printf("再见!\n");
                return 0;
            default:
                printf("无效选择!\n");
        }
    }
    
    return 0;
}

13.2 项目2: 简易计算器

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

// 基础运算
double add(double a, double b) { return a + b; }
double subtract(double a, double b) { return a - b; }
double multiply(double a, double b) { return a * b; }
double divide(double a, double b) {
    if (b == 0) {
        printf("错误: 除数不能为0\n");
        return 0;
    }
    return a / b;
}

// 科学计算
double power(double base, double exp) { return pow(base, exp); }
double squareRoot(double num) {
    if (num < 0) {
        printf("错误: 不能对负数开方\n");
        return 0;
    }
    return sqrt(num);
}

// 显示菜单
void showMenu() {
    printf("\n========== 简易计算器 ==========\n");
    printf("1. 加法 (+)\n");
    printf("2. 减法 (-)\n");
    printf("3. 乘法 (*)\n");
    printf("4. 除法 (/)\n");
    printf("5. 幂运算 (^)\n");
    printf("6. 平方根 (√)\n");
    printf("7. 退出\n");
    printf("==================================\n");
}

int main() {
    int choice;
    double num1, num2, result;
    
    while (1) {
        showMenu();
        printf("请选择操作: ");
        scanf("%d", &choice);
        
        if (choice == 7) {
            printf("感谢使用!\n");
            break;
        }
        
        if (choice == 6) {
            printf("输入数字: ");
            scanf("%lf", &num1);
            result = squareRoot(num1);
            printf("√%.2f = %.2f\n", num1, result);
            continue;
        }
        
        if (choice >= 1 && choice <= 5) {
            printf("输入第一个数: ");
            scanf("%lf", &num1);
            printf("输入第二个数: ");
            scanf("%lf", &num2);
            
            switch (choice) {
                case 1:
                    result = add(num1, num2);
                    printf("%.2f + %.2f = %.2f\n", num1, num2, result);
                    break;
                case 2:
                    result = subtract(num1, num2);
                    printf("%.2f - %.2f = %.2f\n", num1, num2, result);
                    break;
                case 3:
                    result = multiply(num1, num2);
                    printf("%.2f * %.2f = %.2f\n", num1, num2, result);
                    break;
                case 4:
                    result = divide(num1, num2);
                    printf("%.2f / %.2f = %.2f\n", num1, num2, result);
                    break;
                case 5:
                    result = power(num1, num2);
                    printf("%.2f ^ %.2f = %.2f\n", num1, num2, result);
                    break;
            }
        } else {
            printf("无效选择!\n");
        }
    }
    
    return 0;
}

13.3 项目3: 链表实现

#include <stdio.h>
#include <stdlib.h>

// 节点结构
typedef struct Node {
    int data;
    struct Node *next;
} Node;

// 创建新节点
Node* createNode(int data) {
    Node *newNode = (Node*)malloc(sizeof(Node));
    newNode->data = data;
    newNode->next = NULL;
    return newNode;
}

// 在头部插入
void insertAtHead(Node **head, int data) {
    Node *newNode = createNode(data);
    newNode->next = *head;
    *head = newNode;
}

// 在尾部插入
void insertAtTail(Node **head, int data) {
    Node *newNode = createNode(data);
    
    if (*head == NULL) {
        *head = newNode;
        return;
    }
    
    Node *current = *head;
    while (current->next != NULL) {
        current = current->next;
    }
    current->next = newNode;
}

// 删除节点
void deleteNode(Node **head, int data) {
    if (*head == NULL) return;
    
    // 删除头节点
    if ((*head)->data == data) {
        Node *temp = *head;
        *head = (*head)->next;
        free(temp);
        return;
    }
    
    // 删除其他节点
    Node *current = *head;
    while (current->next != NULL) {
        if (current->next->data == data) {
            Node *temp = current->next;
            current->next = current->next->next;
            free(temp);
            return;
        }
        current = current->next;
    }
}

// 查找节点
Node* search(Node *head, int data) {
    Node *current = head;
    while (current != NULL) {
        if (current->data == data) {
            return current;
        }
        current = current->next;
    }
    return NULL;
}

// 打印链表
void printList(Node *head) {
    if (head == NULL) {
        printf("链表为空\n");
        return;
    }
    
    Node *current = head;
    while (current != NULL) {
        printf("%d -> ", current->data);
        current = current->next;
    }
    printf("NULL\n");
}

// 获取链表长度
int getLength(Node *head) {
    int length = 0;
    Node *current = head;
    while (current != NULL) {
        length++;
        current = current->next;
    }
    return length;
}

// 释放链表
void freeList(Node **head) {
    Node *current = *head;
    while (current != NULL) {
        Node *temp = current;
        current = current->next;
        free(temp);
    }
    *head = NULL;
}

int main() {
    Node *head = NULL;
    
    // 插入元素
    insertAtHead(&head, 10);
    insertAtHead(&head, 20);
    insertAtTail(&head, 30);
    insertAtTail(&head, 40);
    
    printf("链表: ");
    printList(head);
    printf("长度: %d\n", getLength(head));
    
    // 查找
    int searchData = 30;
    Node *found = search(head, searchData);
    if (found) {
        printf("找到元素: %d\n", searchData);
    } else {
        printf("未找到元素: %d\n", searchData);
    }
    
    // 删除
    deleteNode(&head, 20);
    printf("删除20后: ");
    printList(head);
    
    // 释放内存
    freeList(&head);
    
    return 0;
}

附录

A. C语言学习路径

系统编程
数据结构
嵌入式
开始学习C语言
环境搭建
基础语法
数据类型与运算符
控制流程
函数
数组与字符串
指针
选择方向
文件操作
链表/树/图
单片机编程
项目实战

B. 常见错误与调试

错误类型原因解决方法
段错误访问非法内存检查指针、数组越界
内存泄漏忘记free配对malloc/free
野指针使用未初始化指针初始化为NULL
缓冲区溢出字符串操作越界使用strncpy等安全函数

C. 编译选项

# 基础编译
gcc program.c -o program

# 显示警告
gcc -Wall -Wextra program.c -o program

# 调试信息
gcc -g program.c -o program

# 优化
gcc -O2 program.c -o program

# 链接数学库
gcc program.c -o program -lm

# 多文件编译
gcc main.c utils.c -o program

文档版本: v1.0
编制日期: 2025年10月
适用人群: C语言初学者到中级开发者
预计学习时间: 8-12周

祝学习愉快!💻✨

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值