前置知识: C

C 语言高级特性与系统编程

00:00
4 min Advanced 2026/5/3

高级数据结构、内存管理、文件系统、网络编程与并发模型。

1. 高级数据结构

1.1 链表

 #include <stdio.h>
 #include <stdlib.h>
 // 链表节点结构
 typedef struct Node {
  int data;
  struct Node *next;
 }
 // 创建新节点
 Node* createNode(int data) {
  Node* newNode = (Node*)malloc(sizeof(Node));
  if (newNode == NULL) {
  printf("Memory allocation failed\n");
  exit(1);
  }
  newNode->data = data;
  newNode->next = NULL;
  return newNode;
 }
 // 插入节点到链表头部
 Node* insertAtHead(Node* head, int data) {
  Node* newNode = createNode(data);
  newNode->next = head;
  return newNode;
 }
 // 插入节点到链表尾部
 Node* insertAtTail(Node* head, int data) {
  Node* newNode = createNode(data);
  if (head == NULL) {
  return newNode;
  }
  Node* temp = head;
  while (temp->next != NULL) {
  temp = temp->next;
  }
  temp->next = newNode;
  return head;
 }
 // 打印链表
 void printList(Node* head) {
  Node* temp = head;
  while (temp != NULL) {
  printf("%d -> ", temp->data);
  temp = temp->next;
  }
  printf("NULL\n");
 }
 // 释放链表内存
 void freeList(Node* head) {
  Node* temp;
  while (head != NULL) {
  temp = head;
  head = head->next;
  free(temp);
  }
 }
 int main() {
  Node* head = NULL;
  head = insertAtHead(head, 3);
  head = insertAtHead(head, 2);
  head = insertAtHead(head, 1);
  head = insertAtTail(head, 4);
  head = insertAtTail(head, 5);
  printList(head);
  freeList(head);
  return 0;
 }

1.2 二叉树

 #include <stdio.h>
 #include <stdlib.h>
 // 二叉树节点结构
 typedef struct TreeNode {
  int data;
  struct TreeNode *left;
  struct TreeNode *right;
 }
 // 创建新节点
 TreeNode* createTreeNode(int data) {
  TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
  if (newNode == NULL) {
  printf("Memory allocation failed\n");
  exit(1);
  }
  newNode->data = data;
  newNode->left = NULL;
  newNode->right = NULL;
  return newNode;
 }
 // 插入节点到二叉搜索树
 TreeNode* insertBST(TreeNode* root, int data) {
  if (root == NULL) {
  return createTreeNode(data);
  }
  if (data < root->data) {
  root->left = insertBST(root->left, data);
  } else if (data > root->data) {
  root->right = insertBST(root->right, data);
  }
  return root;
 }
 // 中序遍历
 void inorderTraversal(TreeNode* root) {
  if (root != NULL) {
  inorderTraversal(root->left);
  printf("%d ", root->data);
  inorderTraversal(root->right);
  }
 }
 // 前序遍历
 void preorderTraversal(TreeNode* root) {
  if (root != NULL) {
  printf("%d ", root->data);
  preorderTraversal(root->left);
  preorderTraversal(root->right);
  }
 }
 // 后序遍历
 void postorderTraversal(TreeNode* root) {
  if (root != NULL) {
  postorderTraversal(root->left);
  postorderTraversal(root->right);
  printf("%d ", root->data);
  }
 }
 // 释放二叉树内存
 void freeTree(TreeNode* root) {
  if (root != NULL) {
  freeTree(root->left);
  freeTree(root->right);
  free(root);
  }
 }
 int main() {
  TreeNode* root = NULL;
  root = insertBST(root, 50);
  root = insertBST(root, 30);
  root = insertBST(root, 70);
  root = insertBST(root, 20);
  root = insertBST(root, 40);
  root = insertBST(root, 60);
  root = insertBST(root, 80);
  printf("Inorder traversal: ");
  inorderTraversal(root);
  printf("\n");
  printf("Preorder traversal: ");
  preorderTraversal(root);
  printf("\n");
  printf("Postorder traversal: ");
  postorderTraversal(root);
  printf("\n");
  freeTree(root);
  return 0;
 }

2. 内存管理

2.1 动态内存分配

 #include <stdio.h>
 #include <stdlib.h>
 int main() {
  // 分配单个整数的内存
  int* ptr = (int*)malloc(sizeof(int));
  if (ptr == NULL) {
  printf("Memory allocation failed\n");
  return 1;
  }
  *ptr = 10;
  printf("Value: %d\n", *ptr);
  free(ptr);
  // 分配数组的内存
  int n = 5;
  int* arr = (int*)malloc(n * sizeof(int));
  if (arr == NULL) {
  printf("Memory allocation failed\n");
  return 1;
  }
  // 初始化数组
  for (int i = 0; i < n; i++) {
  arr[i] = i + 1;
  }
  // 打印数组
  for (int i = 0; i < n; i++) {
  printf("arr[%d] = %d\n", i, arr[i]);
  }
  // 重新分配内存
  n = 10;
  arr = (int*)realloc(arr, n * sizeof(int));
  if (arr == NULL) {
  printf("Memory reallocation failed\n");
  return 1;
  }
  // 填充新元素
  for (int i = 5; i < n; i++) {
  arr[i] = i + 1;
  }
  // 打印数组
  printf("After reallocation:\n");
  for (int i = 0; i < n; i++) {
  printf("arr[%d] = %d\n", i, arr[i]);
  }
  free(arr);
  return 0;
 }

2.2 内存泄漏检测

 #include <stdio.h>
 #include <stdlib.h>
 // 模拟内存泄漏
 void memoryLeak() {
  int* ptr = (int*)malloc(sizeof(int));
  *ptr = 42;
  // 没有释放内存,导致内存泄漏
  printf("Value: %d\n", *ptr);
  // free(ptr); // 注释掉这行,造成内存泄漏
 }
 int main() {
  // 多次调用,造成多次内存泄漏
  for (int i = 0; i < 1000; i++) {
  memoryLeak();
  }
  printf("Memory leak demonstration complete\n");
  return 0;
 }

3. 系统编程

3.1 文件操作

 #include <stdio.h>
 int main() {
  FILE* fp;
  char buffer[100];
  // 打开文件进行写入
  fp = fopen("example.txt", "w");
  if (fp == NULL) {
  printf("Error opening file\n");
  return 1;
  }
  // 写入内容
  fprintf(fp, "Hello, World!\n");
  fprintf(fp, "This is a test file.\n");
  // 关闭文件
  fclose(fp);
  // 打开文件进行读取
  fp = fopen("example.txt", "r");
  if (fp == NULL) {
  printf("Error opening file\n");
  return 1;
  }
  // 读取并打印内容
  printf("File content:\n");
  while (fgets(buffer, sizeof(buffer), fp) != NULL) {
  printf("%s", buffer);
  }
  // 关闭文件
  fclose(fp);
  return 0;
 }

3.2 进程管理

 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/wait.h>
 int main() {
  pid_t pid;
  // 创建子进程
  pid = fork();
  if (pid < 0) {
  // fork 失败
  fprintf(stderr, "Fork failed\n");
  return 1;
  } else if (pid == 0) {
  // 子进程
  printf("Child process, PID: %d\n", getpid());
  printf("Child's parent PID: %d\n", getppid());
  // 执行另一个程序
  execl("/bin/ls", "ls", "-l", NULL);
  // 如果 execl 失败,会执行到这里
  fprintf(stderr, "execl failed\n");
  return 1;
  } else {
  // 父进程
  printf("Parent process, PID: %d\n", getpid());
  printf("Created child process with PID: %d\n", pid);
  // 等待子进程结束
  wait(NULL);
  printf("Child process completed\n");
  }
  return 0;
 }

3.3 线程管理

 #include <stdio.h>
 #include <stdlib.h>
 #include <pthread.h>
 // 共享变量
 int counter = 0;
 // 互斥锁
 pthread_mutex_t mutex;
 // 线程函数
 void* increment(void* arg) {
  for (int i = 0; i < 100000; i++) {
  // 加锁
  pthread_mutex_lock(&mutex);
  counter++;
  // 解锁
  pthread_mutex_unlock(&mutex);
  }
  return NULL;
 }
 int main() {
  pthread_t thread1, thread2;
  // 初始化互斥锁
  pthread_mutex_init(&mutex, NULL);
  // 创建线程
  pthread_create(&thread1, NULL, increment, NULL);
  pthread_create(&thread2, NULL, increment, NULL);
  // 等待线程结束
  pthread_join(thread1, NULL);
  pthread_join(thread2, NULL);
  // 销毁互斥锁
  pthread_mutex_destroy(&mutex);
  printf("Final counter value: %d\n", counter);
  return 0;
 }

4. 网络编程

4.1 TCP 服务器

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #define PORT 8080
 #define BUFFER_SIZE 1024
 int main() {
  int server_fd, new_socket;
  struct sockaddr_in address;
  int opt = 1;
  int addrlen = sizeof(address);
  char buffer[BUFFER_SIZE] = {0};
  char *hello = "Hello from server";
  // 创建套接字文件描述符
  if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
  perror("socket failed");
  exit(EXIT_FAILURE);
  }
  // 设置套接字选项
  if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
  perror("setsockopt");
  exit(EXIT_FAILURE);
  }
  address.sin_family = AF_INET;
  address.sin_addr.s_addr = INADDR_ANY;
  address.sin_port = htons(PORT);
  // 绑定套接字到端口
  if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
  perror("bind failed");
  exit(EXIT_FAILURE);
  }
  // 开始监听
  if (listen(server_fd, 3) < 0) {
  perror("listen");
  exit(EXIT_FAILURE);
  }
  printf("Server listening on port %d\n", PORT);
  // 接受连接
  if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
  perror("accept");
  exit(EXIT_FAILURE);
  }
  // 读取客户端消息
  read(new_socket, buffer, BUFFER_SIZE);
  printf("Client: %s\n", buffer);
  // 发送响应
  send(new_socket, hello, strlen(hello), 0);
  printf("Hello message sent\n");
  // 关闭连接
  close(new_socket);
  close(server_fd);
  return 0;
 }

4.2 TCP 客户端

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #define PORT 8080
 #define BUFFER_SIZE 1024
 int main() {
  int sock = 0;
  struct sockaddr_in serv_addr;
  char *hello = "Hello from client";
  char buffer[BUFFER_SIZE] = {0};
  // 创建套接字文件描述符
  if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  printf("\n Socket creation error \n");
  return -1;
  }
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_port = htons(PORT);
  // 转换 IPv4 地址
  if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0) {
  printf("\nInvalid address/ Address not supported \n");
  return -1;
  }
  // 连接到服务器
  if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
  printf("\nConnection Failed \n");
  return -1;
  }
  // 发送消息
  send(sock, hello, strlen(hello), 0);
  printf("Hello message sent\n");
  // 读取响应
  read(sock, buffer, BUFFER_SIZE);
  printf("Server: %s\n", buffer);
  // 关闭连接
  close(sock);
  return 0;
 }

5. 高级特性

5.1 宏和预处理

 #include <stdio.h>
 // 简单宏
 #define PI 3.14159
 #define MAX(a, b) ((a) > (b) ? (a) : (b))
 // 带参数的宏
 #define SQUARE(x) ((x) * (x))
 // 多行宏
 #define PRINT_ARRAY(arr, n) \
  do { \
  for (int i = 0; i < n; i++) { \
  printf("%d ", arr[i]); \
  } \
  printf("\n"); \
  } while(0)
 // 条件编译
 #define DEBUG 1
 int main() {
  // 使用简单宏
  printf("PI = %f\n", PI);
  printf("MAX(5, 10) = %d\n", MAX(5, 10));
  // 使用带参数的宏
  int x = 5;
  printf("SQUARE(%d) = %d\n", x, SQUARE(x));
  // 使用多行宏
  int arr[] = {1, 2, 3, 4, 5};
  int n = sizeof(arr) / sizeof(arr[0]);
  PRINT_ARRAY(arr, n);
  // 使用条件编译
 #ifdef DEBUG
  printf("Debug mode is enabled\n");
 #else
  printf("Debug mode is disabled\n");
 #endif
  return 0;
 }

5.2 函数指针

 #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 divide(int a, int b) {
  if (b != 0) {
  return a / b;
  }
  return 0;
 }
 int main() {
  // 函数指针声明
  int (*operation)(int, int);
  int a = 10, b = 5;
  // 使用函数指针调用 add 函数
  operation = add;
  printf("%d + %d = %d\n", a, b, operation(a, b));
  // 使用函数指针调用 subtract 函数
  operation = subtract;
  printf("%d - %d = %d\n", a, b, operation(a, b));
  // 使用函数指针调用 multiply 函数
  operation = multiply;
  printf("%d * %d = %d\n", a, b, operation(a, b));
  // 使用函数指针调用 divide 函数
  operation = divide;
  printf("%d / %d = %d\n", a, b, operation(a, b));
  return 0;
 }

5.3 位操作

 #include <stdio.h>
 // 打印二进制表示
 void printBinary(unsigned int n) {
  for (int i = 31; i >= 0; i--) {
  printf("%d", (n >> i) & 1);
  if (i % 4 == 0) printf(" ");
  }
  printf("\n");
 }
 int main() {
  unsigned int a = 0b10101010;
  unsigned int b = 0b11001100;
  printf("a: ");
  printBinary(a);
  printf("b: ");
  printBinary(b);
  // 按位与
  printf("a & b: ");
  printBinary(a & b);
  // 按位或
  printf("a | b: ");
  printBinary(a | b);
  // 按位异或
  printf("a ^ b: ");
  printBinary(a ^ b);
  // 按位取反
  printf("~a: ");
  printBinary(~a);
  // 左移
  printf("a << 2: ");
  printBinary(a << 2);
  // 右移
  printf("a >> 2: ");
  printBinary(a >> 2);
  return 0;
 }

6. 最佳实践

6.1 代码风格

  1. 命名规范
  • 函数和变量使用小写字母,单词之间用下划线分隔
  • 常量使用大写字母,单词之间用下划线分隔
  • 结构体和类型定义使用大写字母开头,单词之间用下划线分隔
  1. 缩进
  • 使用 4 个空格进行缩进
  • 保持代码块的缩进一致
  1. 注释
  • 为函数和复杂代码块添加注释
  • 注释应该清晰明了,解释代码的功能和实现思路
  1. 错误处理
  • 检查所有函数调用的返回值
  • 对错误情况进行适当的处理
  • 使用 errnoperror 来处理系统调用错误

6.2 性能优化

  1. 内存管理
  • 避免频繁的内存分配和释放
  • 使用合适的内存分配函数(malloccallocrealloc
  • 及时释放不再使用的内存
  1. 算法选择
  • 选择时间复杂度合适的算法
  • 对于大数据集,考虑使用更高效的数据结构
  1. 编译器优化
  • 使用 -O2-O3 编译选项启用编译器优化
  • 避免使用会阻止编译器优化的代码模式
  1. 系统调用
  • 减少系统调用的次数
  • 使用缓冲 I/O 来减少文件操作的系统调用

7. 项目实战

7.1 简单的命令行计算器

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 // 函数声明
 int add(int a, int b);
 int subtract(int a, int b);
 int multiply(int a, int b);
 int divide(int a, int b);
 int main(int argc, char *argv[]) {
  if (argc != 4) {
  printf("Usage: %s <operation> <num1> <num2>\n", argv[0]);
  printf("Operations: add, subtract, multiply, divide\n");
  return 1;
  }
  char *operation = argv[1];
  int num1 = atoi(argv[2]);
  int num2 = atoi(argv[3]);
  int result;
  if (strcmp(operation, "add") == 0) {
  result = add(num1, num2);
  } else if (strcmp(operation, "subtract") == 0) {
  result = subtract(num1, num2);
  } else if (strcmp(operation, "multiply") == 0) {
  result = multiply(num1, num2);
  } else if (strcmp(operation, "divide") == 0) {
  if (num2 == 0) {
  printf("Error: Division by zero\n");
  return 1;
  }
  result = divide(num1, num2);
  } else {
  printf("Error: Invalid operation\n");
  return 1;
  }
  printf("Result: %d\n", result);
  return 0;
 }
 // 函数定义
 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 divide(int a, int b) {
  return a / b;
 }

7.2 简单的文件复制程序

 #include <stdio.h>
 int main(int argc, char *argv[]) {
  FILE *source, *destination;
  char buffer[1024];
  size_t bytesRead;
  if (argc != 3) {
  printf("Usage: %s <source file> <destination file>\n", argv[0]);
  return 1;
  }
  // 打开源文件
  source = fopen(argv[1], "rb");
  if (source == NULL) {
  printf("Error opening source file\n");
  return 1;
  }
  // 打开目标文件
  destination = fopen(argv[2], "wb");
  if (destination == NULL) {
  printf("Error opening destination file\n");
  fclose(source);
  return 1;
  }
  // 复制文件内容
  while ((bytesRead = fread(buffer, 1, sizeof(buffer), source)) > 0) {
  fwrite(buffer, 1, bytesRead, destination);
  }
  // 关闭文件
  fclose(source);
  fclose(destination);
  printf("File copied successfully\n");
  return 0;
 }

8. 常见问题与解决方案

8.1 内存泄漏

问题:程序运行时内存使用持续增长 解决方案

  • 确保所有 malloccallocrealloc 分配的内存都有对应free 调用
  • 使用工具如 Valgrind 来检测内存泄漏

8.2 段错误

问题程序崩溃,出现 “Segmentation fault” 解决方案

  • 检查是否访问了空指针
  • 检查是否数组越界
  • 检查是否溢出
  • 使用 GDB 调试器来定问题

8.3 文件操作失败

问题文件打开、读取写入失败 解决方案

  • 检查文件路径是否正确
  • 检查文件权限
  • 检查磁盘空间是否充足
  • 使用 perror 来查看具体的错误信息

8.4 网络连接问题

问题网络连接失败超时 解决方案

  • 检查网络连接是否正常
  • 检查防火墙设置
  • 检查服务器是否正在运
  • 检查端口是否正确

9. 延伸阅读

知识检测

学习进度

-- 已学文档
--% 知识覆盖率

学习推荐

专注模式