1. 引言
在掌握了 C 语言的基础语法之后,我们进入语法进阶阶段。这一阶段将帮助你深入理解 C 语言的核心机制,包括指针、内存管理、结构体、文件操作等高级主题。这些知识是编写高效、健壮、可维护 C 程序的关键。
2. 指针深入
2.1 指针与数组
指针和数组在 C 语言中关系密切。数组名在大多数表达式中会退化为指向首元素的指针。
c
int arr[5] = {1, 2, 3, 4, 5};
int *p = arr; // p 指向 arr[0]
// 以下两种写法等价
printf("%d\n", arr[2]);
printf("%d\n", *(p + 2));
2.2 指针算术
指针支持加减运算,移动的单位是所指向类型的大小。
c
int arr[5] = {10, 20, 30, 40, 50};
int *p = arr;
p++; // 指向 arr[1]
p += 2; // 指向 arr[3]
printf("%d\n", *p); // 输出 40
2.3 多级指针
指向指针的指针,常用于二维数组、字符串数组或需要在函数中修改指针本身。
c
int value = 42;
int *p = &value;
int **pp = &p;
printf("%d\n", **pp); // 输出 42
2.4 指针与函数
指针作为函数参数
通过指针传递,可以在函数内部修改调用者的变量。
c
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 3, y = 5;
swap(&x, &y);
printf("x=%d, y=%d\n", x, y); // x=5, y=3
return 0;
}
函数指针
函数指针可以指向函数,用于回调、策略模式等场景。
c
#include <stdio.h>
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int main() {
int (*op)(int, int) = add;
printf("%d\n", op(5, 3)); // 8
op = sub;
printf("%d\n", op(5, 3)); // 2
return 0;
}
3. 动态内存管理
3.1 malloc 与 free
动态分配堆内存,使用完毕后必须释放,否则造成内存泄漏。
c
#include <stdio.h>
#include <stdlib.h>
int main() {
int *arr = (int *)malloc(5 * sizeof(int));
if (arr == NULL) {
printf("内存分配失败\n");
return 1;
}
for (int i = 0; i < 5; i++) {
arr[i] = i * i;
}
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
printf("\n");
free(arr);
return 0;
}
3.2 calloc 与 realloc
calloc:分配并初始化为 0。realloc:调整已分配内存的大小。
c
int *arr = (int *)calloc(5, sizeof(int)); // 全部初始化为 0
arr = (int *)realloc(arr, 10 * sizeof(int)); // 扩容到 10 个
3.3 常见内存错误
- 忘记释放内存 → 内存泄漏。
- 释放后继续使用 → 悬空指针。
- 越界访问 → 未定义行为。
- 重复释放 → 崩溃。
4. 结构体与联合体
4.1 结构体定义与使用
c
#include <stdio.h>
#include <string.h>
struct Student {
char name[50];
int age;
float score;
};
int main() {
struct Student s1;
strcpy(s1.name, "张三");
s1.age = 20;
s1.score = 88.5;
printf("姓名: %s, 年龄: %d, 成绩: %.1f\n", s1.name, s1.age, s1.score);
return 0;
}
4.2 typedef 简化类型名
c
typedef struct {
char name[50];
int age;
} Person;
Person p = {"李四", 25};
4.3 结构体指针
c
Person p = {"王五", 30};
Person *pp = &p;
printf("%s\n", pp->name); // 使用 -> 访问成员
4.4 联合体
联合体所有成员共享同一块内存,大小取最大成员。
c
union Data {
int i;
float f;
char str[20];
};
union Data data;
data.i = 10;
printf("%d\n", data.i);
data.f = 3.14;
printf("%f\n", data.f); // 此时 i 的值已被覆盖
5. 文件操作
5.1 打开与关闭文件
c
#include <stdio.h>
int main() {
FILE *fp = fopen("test.txt", "w");
if (fp == NULL) {
printf("文件打开失败\n");
return 1;
}
fprintf(fp, "Hello, C Language!\n");
fclose(fp);
return 0;
}
5.2 读写文件
c
// 写入
FILE *fp = fopen("data.txt", "w");
fprintf(fp, "姓名: %s, 年龄: %d\n", "赵六", 28);
fclose(fp);
// 读取
fp = fopen("data.txt", "r");
char buffer[100];
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
printf("%s", buffer);
}
fclose(fp);
5.3 二进制文件
c
typedef struct {
int id;
char name[50];
} Record;
// 写入二进制
Record r = {1, "Alice"};
FILE *fp = fopen("record.dat", "wb");
fwrite(&r, sizeof(Record), 1, fp);
fclose(fp);
// 读取二进制
Record r2;
fp = fopen("record.dat", "rb");
fread(&r2, sizeof(Record), 1, fp);
fclose(fp);
printf("ID: %d, Name: %s\n", r2.id, r2.name);
6. 预处理指令
6.1 宏定义
c
#define PI 3.14159
#define SQUARE(x) ((x) * (x))
printf("%.2f\n", PI); // 3.14
printf("%d\n", SQUARE(5)); // 25
6.2 条件编译
c
#define DEBUG
#ifdef DEBUG
printf("调试模式\n");
#else
printf("发布模式\n");
#endif
6.3 头文件保护
c
#ifndef MY_HEADER_H
#define MY_HEADER_H
// 头文件内容
#endif
7. 总结
语法进阶是 C 语言学习的分水岭。掌握指针、动态内存、结构体和文件操作后,你就具备了编写真实项目的能力。建议通过大量编码练习巩固这些概念,并注意内存安全与代码规范。