前言
2026年4月的TIOBE编程语言排行榜,有个数据挺让人意外的:C语言从第三名蹿到了第二名,市场份额还涨了2.39%,是Top 10里涨幅最大的语言。
这挺有意思的。近几年各种”高级语言”、”脚本语言”层出不穷,很多人觉得C语言这种”老古董”该退出历史舞台了。结果呢?AI时代的到来,反而让C语言焕发了新生——大模型的底层框架、推理引擎、编译器优化,哪个离得开C/C++?
我自己也是从”觉得C语言过时”到重新认识它的。写惯了Python、JavaScript这些高层语言,一开始觉得C语言满屏的指针和malloc太麻烦。但当你需要榨干每一滴性能、需要直接操作硬件资源时,就会发现C语言那种”你控制一切”的感觉,是其他语言给不了的。
这篇文章,就是想帮有编程基础但还没系统学过C语言的人,找到一条清晰的学习路径。不求把C语言讲透,但求让你知道学什么、怎么用、能做什么。

一、C语言为什么在2026年依然重要
1.1 榜单数据的启示
先看数据。2026年4月的TIOBE榜单:
| 排名 | 语言 | 市场份额 | 变化 |
|---|---|---|---|
| 1 | Python | 20.97% | -2.11% |
| 2 | C | 12.34% | +2.39% |
| 3 | C++ | 8.03% | -2.30% |
C语言不仅排名上升,还是Top 10里涨幅最大的。TIOBE官方甚至把4月的标题定为:”C Gains Again While Rust Loses Some Steam”——C语言再度回升,Rust失去动力。
1.2 AI时代为什么需要C语言
大模型的火热,带来了一个意想不到的连锁反应:底层性能需求爆发。
你想啊,AI大模型跑起来,推理速度、内存占用、算力调度……这些都需要精确控制。Python跑得快是因为有C在底层撑着——NumPy、TensorFlow、PyTorch,核心计算全是C/C++实现的。
具体来说,这些领域现在C/C++人才缺口很大:
- AI推理引擎开发:TensorRT、ONNX Runtime、MLC-LLM
- 高性能计算:科学计算、信号处理、图像处理
- 嵌入式开发:IoT设备、微控制器、实时系统
- 操作系统内核:Linux内核部分模块、驱动开发
- 游戏引擎:Unreal Engine、Unity核心模块
1.3 C语言的核心优势
性能控制:没有垃圾回收、没有虚拟机,直接编译成机器码。每一行代码怎么执行、内存怎么分配,完全由你决定。
资源控制:指针可以直接操作内存地址,这在硬件交互、性能优化场景下是刚需。
可移植性:C语言几乎是跨平台开发的标准——从嵌入式设备到超级计算机,从Windows到Linux到macOS,主流操作系统底层都是C写的。
生态系统:Linux内核、Glibc、Redis、Nginx……大量核心基础设施都是C语言开发的。
二、C语言基础:快速上手
2.1 开发环境
Linux/macOS
大多数Unix-like系统自带GCC编译器,直接打开终端:
bash
# 检查GCC版本
gcc --version
# 如果没有,用包管理器安装
# Ubuntu/Debian:
sudo apt install build-essential
# macOS:
xcode-select --install
Windows
推荐使用MinGW-w64或WSL(Windows Subsystem for Linux):
bash
# WSL安装后直接用gcc
wsl --install
wsl
gcc --version
IDE选择
- VS Code + C/C++插件:轻量级,适合学习和小型项目
- CLion:JetBrains出品,功能强大,学生可免费申请教育版
- Qt Creator:适合Qt开发,也有纯C/C++模式
- Vim/Emacs:纯命令行开发,适合追求极致效率的人
2.2 第一个C程序
c
// hello.c
#include <stdio.h>
int main() {
printf("Hello, World!\n");
return 0;
}
编译运行:
bash
gcc hello.c -o hello
./hello
2.3 基础语法速览
变量和数据类型
c
#include <stdio.h>
int main() {
// 基本数据类型
int age = 25;
float height = 1.75f;
double salary = 8500.50;
char grade = 'A';
_Bool is_student = 1; // C99布尔类型
// 格式化输出
printf("年龄: %d\n", age);
printf("身高: %.2f米\n", height);
printf("月薪: %.2f元\n", salary);
printf("等级: %c\n", grade);
// 数组
int scores[] = {85, 92, 78, 96};
printf("第一门成绩: %d\n", scores[0]);
// 字符串(字符数组)
char name[] = "ZhangSan";
printf("姓名: %s\n", name);
return 0;
}
控制流
c
// 条件判断
if (age >= 18) {
printf("成年人\n");
} else if (age >= 6) {
printf("未成年人\n");
} else {
printf("儿童\n");
}
// switch语句
switch (grade) {
case 'A':
printf("优秀\n");
break;
case 'B':
printf("良好\n");
break;
default:
printf("其他\n");
}
// 循环
for (int i = 0; i < 5; i++) {
printf("第%d次循环\n", i);
}
int j = 0;
while (j < 3) {
printf("while循环第%d次\n", j);
j++;
}
// do-while(至少执行一次)
int k = 0;
do {
printf("do-while第%d次\n", k);
k++;
} while (k < 3);
函数定义
c
#include <stdio.h>
// 函数声明
int add(int a, int b);
void greet(const char* name);
// 主函数
int main() {
int result = add(10, 20);
printf("10 + 20 = %d\n", result);
greet("World");
return 0;
}
// 函数定义
int add(int a, int b) {
return a + b;
}
void greet(const char* name) {
printf("Hello, %s!\n", name);
}
三、C语言核心:指针与内存
3.1 指针基础
指针是C语言的精髓,也是让很多人望而却步的概念。我当年学的时候也是云里雾里,后来发现关键是要理解:指针就是地址。
c
#include <stdio.h>
int main() {
int number = 42;
int *ptr = &number; // ptr存储number的地址
printf("number的值: %d\n", number);
printf("number的地址: %p\n", &number);
printf("ptr的值(也是地址): %p\n", ptr);
printf("通过ptr访问number: %d\n", *ptr); // 解引用
// 修改ptr指向的值
*ptr = 100;
printf("修改后number的值: %d\n", number);
return 0;
}
3.2 指针与数组
数组名本身就是指针,指向数组第一个元素:
c
#include <stdio.h>
int main() {
int arr[] = {10, 20, 30, 40, 50};
int *ptr = arr; // 等价于 int *ptr = &arr[0];
// 两种访问方式等价
printf("arr[0] = %d, *(ptr+0) = %d\n", arr[0], *(ptr+0));
printf("arr[2] = %d, *(ptr+2) = %d\n", arr[2], *(ptr+2));
// 遍历数组
for (int i = 0; i < 5; i++) {
printf("arr[%d] = %d\n", i, *(ptr + i));
}
// 指针算术
ptr++; // 指向下一个元素
printf("ptr++后: *ptr = %d\n", *ptr); // 输出30
return 0;
}
3.3 动态内存分配
堆内存手动管理是C语言的核心技能,也是容易出bug的地方:
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 + 1) * 10;
}
// 打印
for (int i = 0; i < 5; i++) {
printf("arr[%d] = %d\n", i, arr[i]);
}
// 重新分配(扩大)
int *new_arr = (int *)realloc(arr, 10 * sizeof(int));
if (new_arr == NULL) {
printf("重新分配失败\n");
free(arr); // 记得释放原内存
return 1;
}
arr = new_arr;
// 填充新增的内存
for (int i = 5; i < 10; i++) {
arr[i] = (i + 1) * 10;
}
// 释放内存
free(arr);
arr = NULL; // 避免野指针
return 0;
}
内存分配函数总结:
| 函数 | 说明 |
|---|---|
malloc(size) | 分配指定字节的内存 |
calloc(n, size) | 分配并清零内存 |
realloc(ptr, size) | 重新分配内存 |
free(ptr) | 释放内存 |
3.4 常见内存错误及避免
c
// 错误1:野指针(指针未初始化或已释放)
int *ptr; // 未初始化
// printf("%d", *ptr); // 危险!
// 正确做法
int *ptr = NULL;
if (ptr != NULL) {
printf("%d", *ptr);
}
// 错误2:内存泄漏(malloc后忘记free)
void leaky_function() {
int *arr = (int *)malloc(100 * sizeof(int));
// ... 使用arr ...
// 忘记free(arr)!
}
// 正确做法:配对使用
void correct_function() {
int *arr = (int *)malloc(100 * sizeof(int));
// ... 使用arr ...
free(arr);
arr = NULL;
}
// 错误3:缓冲区溢出
char buffer[10];
strcpy(buffer, "This is too long!"); // 危险!
// 正确做法:检查长度或使用安全函数
strncpy(buffer, "This is long", sizeof(buffer) - 1);
buffer[sizeof(buffer) - 1] = '\0';
四、文件操作
4.1 文件读写基础
c
#include <stdio.h>
int main() {
// 写入文件
FILE *fp = fopen("test.txt", "w");
if (fp == NULL) {
printf("打开文件失败\n");
return 1;
}
fprintf(fp, "姓名: 张三\n");
fprintf(fp, "年龄: %d\n", 25);
fprintf(fp, "月薪: %.2f\n", 8500.50);
fclose(fp); // 关闭文件
// 读取文件
fp = fopen("test.txt", "r");
if (fp == NULL) {
printf("打开文件失败\n");
return 1;
}
char line[256];
while (fgets(line, sizeof(line), fp) != NULL) {
printf("%s", line);
}
fclose(fp);
return 0;
}
4.2 二进制文件操作
c
#include <stdio.h>
typedef struct {
char name[50];
int age;
float score;
} Student;
// 写入二进制文件
void write_students() {
Student students[] = {
{"张三", 20, 85.5},
{"李四", 22, 92.0},
{"王五", 21, 88.5}
};
FILE *fp = fopen("students.dat", "wb");
if (fp == NULL) {
printf("打开文件失败\n");
return;
}
int count = sizeof(students) / sizeof(Student);
fwrite(&count, sizeof(int), 1, fp); // 先写入数量
fwrite(students, sizeof(Student), count, fp);
fclose(fp);
}
// 读取二进制文件
void read_students() {
FILE *fp = fopen("students.dat", "rb");
if (fp == NULL) {
printf("打开文件失败\n");
return;
}
int count;
fread(&count, sizeof(int), 1, fp);
Student *students = (Student *)malloc(count * sizeof(Student));
fread(students, sizeof(Student), count, fp);
for (int i = 0; i < count; i++) {
printf("%s, %d岁, %.1f分\n",
students[i].name,
students[i].age,
students[i].score);
}
free(students);
fclose(fp);
}
五、结构体与自定义类型
5.1 结构体定义和使用
c
#include <stdio.h>
#include <string.h>
// 定义结构体
struct Person {
char name[50];
int age;
float height;
};
// typedef简化类型名
typedef struct {
char name[50];
int age;
float height;
} Person;
// 嵌套结构体
struct Address {
char city[50];
char street[100];
};
struct Employee {
char name[50];
int id;
struct Address addr; // 嵌套
};
int main() {
// 初始化结构体
Person p1 = {"张三", 25, 1.75f};
// 单独赋值
Person p2;
strcpy(p2.name, "李四");
p2.age = 28;
p2.height = 1.68f;
// 访问成员
printf("%s今年%d岁,身高%.2f米\n", p1.name, p1.age, p1.height);
// 结构体数组
Person people[] = {
{"张三", 25, 1.75f},
{"李四", 28, 1.68f},
{"王五", 22, 1.80f}
};
int count = sizeof(people) / sizeof(Person);
for (int i = 0; i < count; i++) {
printf("%s\n", people[i].name);
}
return 0;
}
5.2 链表实现
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Node {
int data;
struct Node *next;
} Node;
// 创建新节点
Node* create_node(int data) {
Node *new_node = (Node *)malloc(sizeof(Node));
if (new_node == NULL) {
printf("内存分配失败\n");
return NULL;
}
new_node->data = data;
new_node->next = NULL;
return new_node;
}
// 头部插入
Node* insert_at_head(Node *head, int data) {
Node *new_node = create_node(data);
new_node->next = head;
return new_node; // 返回新的头节点
}
// 尾部插入
void insert_at_tail(Node **head_ref, int data) {
Node *new_node = create_node(data);
if (*head_ref == NULL) {
*head_ref = new_node;
return;
}
Node *temp = *head_ref;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = new_node;
}
// 打印链表
void print_list(Node *head) {
Node *temp = head;
while (temp != NULL) {
printf("%d -> ", temp->data);
temp = temp->next;
}
printf("NULL\n");
}
// 释放链表内存
void free_list(Node *head) {
Node *temp;
while (head != NULL) {
temp = head;
head = head->next;
free(temp);
}
}
int main() {
Node *head = NULL;
insert_at_tail(&head, 10);
insert_at_tail(&head, 20);
insert_at_tail(&head, 30);
head = insert_at_head(head, 5); // 头部插入
print_list(head); // 输出: 5 -> 10 -> 20 -> 30 -> NULL
free_list(head);
return 0;
}
六、Makefile:项目管理
6.1 为什么需要Makefile
一个C项目通常有多个源文件,手动编译太麻烦:
bash
# 不用Makefile的编译
gcc -o main main.c utils.c config.c -I./include
# 改了一个文件,所有文件都得重新编译
6.2 简单Makefile
makefile
# Makefile
CC = gcc
CFLAGS = -Wall -g -I./include
TARGET = myprogram
# 源文件
SRCS = main.c utils.c config.c
OBJS = $(SRCS:.c=.o)
# 头文件目录
HEADERS = include/utils.h include/config.h
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(OBJS) -o $(TARGET)
main.o: main.c $(HEADERS)
$(CC) $(CFLAGS) -c main.c
utils.o: utils.c $(HEADERS)
$(CC) $(CFLAGS) -c utils.c
config.o: config.c $(HEADERS)
$(CC) $(CFLAGS) -c config.c
clean:
rm -f $(OBJS) $(TARGET)
.PHONY: all clean
6.3 使用技巧
bash
make # 编译
make clean # 清理
make -j4 # 并行编译,加速
make verbose # 显示详细命令
七、C语言学习资源
7.1 经典书籍
入门推荐:
- 《C Primer Plus》- Stephen Prata,详尽但不啰嗦
- 《C程序设计语言》- K&R,C语言作者写的,经典中的经典
进阶推荐:
- 《C和指针》- 深入理解指针和内存
- 《C陷阱与缺陷》- 常见错误及避免方法
- 《C专家编程》- 资深C程序员的经验分享
7.2 在线资源
- Learn-C.org:免费在线教程,交互式练习
- HackerRank C Challenges:编程挑战
- LeetCode Hot 100:算法题,C语言实现
7.3 开源项目推荐
学C语言最好的方式就是读优秀的开源代码:
| 项目 | 说明 | 学习重点 |
|---|---|---|
| Redis | 高性能KV数据库 | 数据结构、网络编程 |
| SQLite | 嵌入式数据库 | SQL解析、存储引擎 |
| Linux内核 | 操作系统内核 | 系统编程、性能优化 |
| Git | 版本控制系统 | 数据结构、命令行工具 |
八、实战项目:命令行学生管理系统
8.1 项目结构
plaintext
student_mgr/
├── include/
│ ├── student.h
│ └── db.h
├── src/
│ ├── main.c
│ ├── student.c
│ └── db.c
├── data/
│ └── students.dat
├── Makefile
└── README.md
8.2 核心代码
c
// include/student.h
#ifndef STUDENT_H
#define STUDENT_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int id;
char name[50];
int age;
float score;
} Student;
typedef struct {
Student *students;
int count;
int capacity;
} StudentList;
// 函数声明
StudentList* create_list(int capacity);
void add_student(StudentList *list, Student s);
void list_students(StudentList *list);
void save_to_file(StudentList *list, const char *filename);
StudentList* load_from_file(const char *filename);
void free_list(StudentList *list);
#endif
总结
C语言学了二十多年,到现在依然是系统编程的核心语言,这不是没有道理的。它的”简单”——没有花哨的语法、没有复杂的运行时——反而是最大的优势。
在2026年这个AI爆发的时代,底层性能需求比以往任何时候都要高。大模型的推理加速、边缘计算的实时响应、物联网设备的高效运行……这些场景都在呼唤懂C语言的开发者。
学C语言,核心是理解它的思维:手动管理内存、直接操作硬件、精确控制每一行代码的执行。这种感觉一开始会觉得麻烦,但当你真正掌握之后,会有一种”终于控制了一切”的自由。
当然,C语言不是银弹。它不适合快速开发Web应用、不适合写脚本、不适合AI上层应用。但在你需要它的地方,它无可替代。
2026年了,如果你想在技术深度上更进一步,C语言值得你认真投入。
相关资源推荐:
延伸阅读:

发表回复