1. C语言实例解析:从基础到进阶的20个经典案例
C语言作为计算机编程的基石语言,其重要性不言而喻。对于初学者而言,通过实际案例来学习是最有效的方式之一。本文将深入剖析20个C语言经典实例,涵盖从基础语法到高级应用的各个层面,帮助读者系统掌握C语言编程的核心技能。
这些实例经过精心挑选,既包含了基础的输入输出、流程控制,也涵盖了指针、文件操作、数据结构等进阶内容。每个实例都配有完整的代码实现和详细解析,确保读者能够理解其背后的编程思想和实现原理。
2. 基础语法实例解析
2.1 变量与基本输入输出
让我们从最基础的变量声明和输入输出开始。这个实例展示了如何声明不同类型的变量,以及使用scanf和printf进行输入输出:
c复制#include <stdio.h>
int main() {
int a;
float b;
char c;
printf("请输入一个整数:");
scanf("%d", &a);
printf("请输入一个浮点数:");
scanf("%f", &b);
printf("请输入一个字符:");
scanf(" %c", &c); // 注意%c前的空格,用于吸收前导空白符
printf("\n您输入的是:\n");
printf("整数:%d\n", a);
printf("浮点数:%.2f\n", b);
printf("字符:%c\n", c);
return 0;
}
注意:在读取字符前使用空格可以避免读取到之前输入留下的换行符,这是初学者常犯的错误。
2.2 条件判断与分支结构
条件判断是编程中的基本结构之一。下面这个实例演示了if-else和switch-case的使用:
c复制#include <stdio.h>
int main() {
int score;
printf("请输入成绩(0-100):");
scanf("%d", &score);
// if-else实现
if(score >= 90) {
printf("优秀\n");
} else if(score >= 80) {
printf("良好\n");
} else if(score >= 60) {
printf("及格\n");
} else {
printf("不及格\n");
}
// switch-case实现
switch(score/10) {
case 10:
case 9: printf("优秀\n"); break;
case 8: printf("良好\n"); break;
case 7:
case 6: printf("及格\n"); break;
default: printf("不及格\n");
}
return 0;
}
这个实例展示了两种不同的条件判断实现方式,帮助理解不同场景下的选择策略。
3. 数组与字符串操作实例
3.1 数组的基本操作
数组是C语言中重要的数据结构,下面实例展示了数组的声明、初始化和基本操作:
c复制#include <stdio.h>
int main() {
int arr[5] = {1, 2, 3, 4, 5};
int sum = 0;
// 计算数组元素和
for(int i = 0; i < 5; i++) {
sum += arr[i];
}
printf("数组元素和:%d\n", sum);
// 查找最大值
int max = arr[0];
for(int i = 1; i < 5; i++) {
if(arr[i] > max) {
max = arr[i];
}
}
printf("数组最大值:%d\n", max);
// 数组反转
for(int i = 0; i < 5/2; i++) {
int temp = arr[i];
arr[i] = arr[4-i];
arr[4-i] = temp;
}
printf("反转后的数组:");
for(int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
3.2 字符串处理
字符串在C语言中以字符数组形式存在,下面实例展示了常见的字符串操作:
c复制#include <stdio.h>
#include <string.h>
int main() {
char str1[100], str2[100];
printf("请输入第一个字符串:");
fgets(str1, sizeof(str1), stdin);
str1[strcspn(str1, "\n")] = '\0'; // 去除换行符
printf("请输入第二个字符串:");
fgets(str2, sizeof(str2), stdin);
str2[strcspn(str2, "\n")] = '\0';
// 字符串连接
strcat(str1, str2);
printf("连接后的字符串:%s\n", str1);
// 字符串比较
int cmp = strcmp(str1, str2);
if(cmp == 0) {
printf("字符串相同\n");
} else if(cmp < 0) {
printf("第一个字符串小于第二个\n");
} else {
printf("第一个字符串大于第二个\n");
}
// 字符串长度
printf("第一个字符串长度:%zu\n", strlen(str1));
return 0;
}
提示:使用fgets读取字符串比scanf更安全,可以避免缓冲区溢出问题。
4. 指针与内存管理实例
4.1 指针基础与应用
指针是C语言的精髓所在,下面实例展示了指针的基本用法:
c复制#include <stdio.h>
int main() {
int a = 10;
int *p = &a;
printf("变量a的值:%d\n", a);
printf("变量a的地址:%p\n", &a);
printf("指针p的值:%p\n", p);
printf("指针p指向的值:%d\n", *p);
// 通过指针修改变量值
*p = 20;
printf("修改后a的值:%d\n", a);
// 指针运算
int arr[5] = {1, 2, 3, 4, 5};
int *arr_p = arr;
printf("\n数组元素通过指针访问:\n");
for(int i = 0; i < 5; i++) {
printf("%d ", *(arr_p + i));
}
printf("\n");
return 0;
}
4.2 动态内存分配
动态内存管理是C语言编程中的重要技能,下面实例展示了malloc和free的使用:
c复制#include <stdio.h>
#include <stdlib.h>
int main() {
int n;
printf("请输入数组大小:");
scanf("%d", &n);
// 动态分配内存
int *arr = (int*)malloc(n * sizeof(int));
if(arr == NULL) {
printf("内存分配失败\n");
return 1;
}
// 初始化数组
for(int i = 0; i < n; i++) {
arr[i] = i * 2;
}
// 打印数组
printf("动态数组内容:\n");
for(int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
// 释放内存
free(arr);
return 0;
}
重要:每次使用malloc分配内存后,都必须检查返回值是否为NULL,并且在使用完毕后调用free释放内存,避免内存泄漏。
5. 文件操作实例
5.1 文件读写基础
文件操作是C语言编程中常见的任务,下面实例展示了基本的文件读写操作:
c复制#include <stdio.h>
int main() {
FILE *file;
char filename[] = "example.txt";
// 写入文件
file = fopen(filename, "w");
if(file == NULL) {
printf("无法打开文件\n");
return 1;
}
fprintf(file, "这是写入文件的第一行\n");
fprintf(file, "这是第二行,数字:%d\n", 42);
fclose(file);
// 读取文件
file = fopen(filename, "r");
if(file == NULL) {
printf("无法打开文件\n");
return 1;
}
printf("\n文件内容:\n");
char line[100];
while(fgets(line, sizeof(line), file) != NULL) {
printf("%s", line);
}
fclose(file);
return 0;
}
5.2 二进制文件操作
二进制文件操作适合处理非文本数据,下面实例展示了二进制文件的读写:
c复制#include <stdio.h>
typedef struct {
int id;
char name[20];
float score;
} Student;
int main() {
Student s1 = {1, "张三", 89.5};
Student s2 = {2, "李四", 92.0};
Student read_s;
FILE *file = fopen("students.dat", "wb");
if(file == NULL) {
printf("无法打开文件\n");
return 1;
}
// 写入二进制数据
fwrite(&s1, sizeof(Student), 1, file);
fwrite(&s2, sizeof(Student), 1, file);
fclose(file);
// 读取二进制数据
file = fopen("students.dat", "rb");
if(file == NULL) {
printf("无法打开文件\n");
return 1;
}
printf("\n学生信息:\n");
while(fread(&read_s, sizeof(Student), 1, file) == 1) {
printf("ID: %d, 姓名: %s, 分数: %.1f\n",
read_s.id, read_s.name, read_s.score);
}
fclose(file);
return 0;
}
6. 数据结构与算法实例
6.1 链表实现
链表是动态数据结构的基础,下面实例展示了单向链表的实现:
c复制#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));
if(newNode == NULL) {
printf("内存分配失败\n");
exit(1);
}
newNode->data = data;
newNode->next = NULL;
return newNode;
}
void insertAtEnd(Node **head, int data) {
Node *newNode = createNode(data);
if(*head == NULL) {
*head = newNode;
return;
}
Node *temp = *head;
while(temp->next != NULL) {
temp = temp->next;
}
temp->next = newNode;
}
void printList(Node *head) {
Node *temp = head;
while(temp != NULL) {
printf("%d -> ", temp->data);
temp = temp->next;
}
printf("NULL\n");
}
int main() {
Node *head = NULL;
insertAtEnd(&head, 10);
insertAtEnd(&head, 20);
insertAtEnd(&head, 30);
printf("链表内容:\n");
printList(head);
// 释放内存
Node *temp;
while(head != NULL) {
temp = head;
head = head->next;
free(temp);
}
return 0;
}
6.2 快速排序实现
快速排序是高效的排序算法,下面实例展示了其C语言实现:
c复制#include <stdio.h>
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int partition(int arr[], int low, int high) {
int pivot = arr[high];
int i = low - 1;
for(int j = low; j < high; j++) {
if(arr[j] < pivot) {
i++;
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i+1], &arr[high]);
return i + 1;
}
void quickSort(int arr[], int low, int high) {
if(low < high) {
int pi = partition(arr, low, high);
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
int main() {
int arr[] = {10, 7, 8, 9, 1, 5};
int n = sizeof(arr)/sizeof(arr[0]);
printf("排序前数组:\n");
for(int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
quickSort(arr, 0, n - 1);
printf("排序后数组:\n");
for(int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
7. 高级应用实例
7.1 递归与汉诺塔问题
汉诺塔是经典的递归问题,下面实例展示了其C语言实现:
c复制#include <stdio.h>
void hanoi(int n, char from, char to, char aux) {
if(n == 1) {
printf("将盘 %d 从 %c 移动到 %c\n", 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() {
int disks;
printf("请输入汉诺塔的盘数:");
scanf("%d", &disks);
hanoi(disks, 'A', 'C', 'B');
return 0;
}
7.2 简单加密解密实现
下面实例展示了简单的加密解密算法实现:
c复制#include <stdio.h>
#include <string.h>
void encrypt(char *str, int key) {
for(int i = 0; str[i] != '\0'; i++) {
str[i] = str[i] + key;
}
}
void decrypt(char *str, int key) {
for(int i = 0; str[i] != '\0'; i++) {
str[i] = str[i] - key;
}
}
int main() {
char message[100];
int key;
printf("请输入要加密的消息:");
fgets(message, sizeof(message), stdin);
message[strcspn(message, "\n")] = '\0';
printf("请输入加密密钥(整数):");
scanf("%d", &key);
encrypt(message, key);
printf("加密后的消息:%s\n", message);
decrypt(message, key);
printf("解密后的消息:%s\n", message);
return 0;
}
8. 综合项目实例
8.1 学生成绩管理系统
下面是一个综合性的学生成绩管理系统实例:
c复制#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STUDENTS 100
typedef struct {
int id;
char name[50];
float score;
} Student;
Student students[MAX_STUDENTS];
int count = 0;
void addStudent() {
if(count >= MAX_STUDENTS) {
printf("学生数量已达上限\n");
return;
}
printf("请输入学生ID:");
scanf("%d", &students[count].id);
printf("请输入学生姓名:");
scanf("%s", students[count].name);
printf("请输入学生成绩:");
scanf("%f", &students[count].score);
count++;
printf("学生信息添加成功\n");
}
void displayStudents() {
if(count == 0) {
printf("没有学生记录\n");
return;
}
printf("\n学生列表:\n");
printf("ID\t姓名\t成绩\n");
for(int i = 0; i < count; i++) {
printf("%d\t%s\t%.1f\n",
students[i].id,
students[i].name,
students[i].score);
}
}
void searchStudent() {
int id;
printf("请输入要查找的学生ID:");
scanf("%d", &id);
for(int i = 0; i < count; i++) {
if(students[i].id == id) {
printf("找到学生:\n");
printf("ID:%d\n", students[i].id);
printf("姓名:%s\n", students[i].name);
printf("成绩:%.1f\n", students[i].score);
return;
}
}
printf("未找到ID为%d的学生\n", id);
}
void saveToFile() {
FILE *file = fopen("students.dat", "wb");
if(file == NULL) {
printf("无法打开文件\n");
return;
}
fwrite(&count, sizeof(int), 1, file);
fwrite(students, sizeof(Student), count, file);
fclose(file);
printf("学生数据已保存到文件\n");
}
void loadFromFile() {
FILE *file = fopen("students.dat", "rb");
if(file == NULL) {
printf("无法打开文件\n");
return;
}
fread(&count, sizeof(int), 1, file);
fread(students, sizeof(Student), count, file);
fclose(file);
printf("从文件加载了%d条学生记录\n", count);
}
int main() {
int choice;
do {
printf("\n学生成绩管理系统\n");
printf("1. 添加学生\n");
printf("2. 显示所有学生\n");
printf("3. 查找学生\n");
printf("4. 保存到文件\n");
printf("5. 从文件加载\n");
printf("0. 退出\n");
printf("请选择操作:");
scanf("%d", &choice);
switch(choice) {
case 1: addStudent(); break;
case 2: displayStudents(); break;
case 3: searchStudent(); break;
case 4: saveToFile(); break;
case 5: loadFromFile(); break;
case 0: printf("退出系统\n"); break;
default: printf("无效选择\n");
}
} while(choice != 0);
return 0;
}
8.2 简易计算器实现
下面是一个支持多种运算的简易计算器实现:
c复制#include <stdio.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("错误:除数不能为零\n");
return 0;
}
return a / b;
}
double power(double a, double b) {
return pow(a, b);
}
int main() {
double num1, num2, result;
char op;
printf("简易计算器\n");
printf("支持操作:+ - * / ^\n");
printf("输入格式:数字 操作符 数字\n");
printf("示例:2 + 3 或 5 ^ 2\n");
printf("输入q退出\n\n");
while(1) {
printf("请输入表达式:");
if(scanf("%lf %c %lf", &num1, &op, &num2) != 3) {
break;
}
switch(op) {
case '+': result = add(num1, num2); break;
case '-': result = subtract(num1, num2); break;
case '*': result = multiply(num1, num2); break;
case '/': result = divide(num1, num2); break;
case '^': result = power(num1, num2); break;
default:
printf("无效操作符\n");
continue;
}
printf("结果:%.2lf\n\n", result);
}
printf("计算器已退出\n");
return 0;
}
9. 常见问题与调试技巧
9.1 段错误(Segmentation Fault)排查
段错误是C语言编程中常见的问题,通常由以下原因引起:
- 访问了未初始化或已释放的指针
- 数组越界访问
- 修改了字符串常量
- 栈溢出
调试技巧:
- 使用gdb调试工具逐步执行程序
- 在可疑代码前后添加printf语句
- 检查所有指针是否有效
- 使用valgrind工具检测内存问题
9.2 内存泄漏检测
内存泄漏是另一个常见问题,可以通过以下方法检测和避免:
- 确保每个malloc都有对应的free
- 使用工具如valgrind检测内存泄漏
- 在复杂程序中,可以使用引用计数或内存池技术
- 养成在free后立即将指针置为NULL的习惯
示例检测代码:
c复制#include <stdlib.h>
#define malloc(size) my_malloc(size, __FILE__, __LINE__)
#define free(ptr) my_free(ptr, __FILE__, __LINE__)
void* my_malloc(size_t size, const char* file, int line) {
void* p = malloc(size);
printf("分配内存:%p 在 %s:%d\n", p, file, line);
return p;
}
void my_free(void* ptr, const char* file, int line) {
printf("释放内存:%p 在 %s:%d\n", ptr, file, line);
free(ptr);
}
10. 性能优化技巧
10.1 循环优化
循环是程序中的性能热点,优化技巧包括:
- 减少循环内部的计算量
- 使用更高效的循环结构
- 展开循环(loop unrolling)
- 避免在循环中调用函数
示例:
c复制// 优化前
for(int i = 0; i < n; i++) {
arr[i] = someComplexFunction(i);
}
// 优化后
int temp;
for(int i = 0; i < n; i++) {
temp = i; // 减少重复计算
arr[i] = someComplexFunction(temp);
}
10.2 缓存友好编程
现代CPU的缓存系统对性能影响巨大,优化技巧:
- 顺序访问内存
- 合理使用数据结构大小
- 避免false sharing
- 预取数据
示例:
c复制// 缓存不友好的访问方式
for(int i = 0; i < 100; i++) {
for(int j = 0; j < 100; j++) {
arr[j][i] = 0; // 列优先访问
}
}
// 缓存友好的访问方式
for(int i = 0; i < 100; i++) {
for(int j = 0; j < 100; j++) {
arr[i][j] = 0; // 行优先访问
}
}
11. 现代C语言特性
11.1 C11标准新特性
C11标准引入了一些有用的新特性:
- 多线程支持(<threads.h>)
- 泛型选择(_Generic)
- 匿名结构体和联合体
- 边界检查函数
示例:
c复制#include <stdio.h>
#define print_type(x) _Generic((x), \
int: "int", \
float: "float", \
double: "double", \
default: "其他类型" \
)
int main() {
int i = 0;
float f = 0.0f;
printf("i的类型是:%s\n", print_type(i));
printf("f的类型是:%s\n", print_type(f));
return 0;
}
11.2 静态代码分析工具
使用静态分析工具可以提高代码质量:
- clang静态分析器
- cppcheck
- Coverity
- PVS-Studio
这些工具可以检测出:
- 潜在的内存泄漏
- 未初始化的变量
- 数组越界访问
- 死代码
- 其他常见错误
12. 跨平台开发注意事项
12.1 数据类型大小差异
不同平台下数据类型大小可能不同,解决方案:
- 使用<stdint.h>中的固定大小类型(int32_t等)
- 使用sizeof检查类型大小
- 避免对数据类型大小做假设
示例:
c复制#include <stdio.h>
#include <stdint.h>
int main() {
printf("int大小:%zu字节\n", sizeof(int));
printf("long大小:%zu字节\n", sizeof(long));
int32_t fixed_size = 0; // 保证是32位
printf("int32_t大小:%zu字节\n", sizeof(fixed_size));
return 0;
}
12.2 字节序问题
不同平台可能有不同的字节序(大端/小端),处理技巧:
- 使用htonl/ntohl等函数转换网络字节序
- 明确文档说明数据格式
- 必要时进行运行时检测
示例:
c复制#include <stdio.h>
int isLittleEndian() {
int num = 1;
return *(char*)&num == 1;
}
int main() {
if(isLittleEndian()) {
printf("小端字节序\n");
} else {
printf("大端字节序\n");
}
return 0;
}
13. 嵌入式C编程特点
13.1 寄存器操作
嵌入式开发中经常需要直接操作硬件寄存器:
c复制#define GPIOA_BASE 0x40020000
#define GPIOA_MODER (*(volatile uint32_t*)(GPIOA_BASE + 0x00))
void configureLED() {
// 设置PA5为输出模式
GPIOA_MODER &= ~(0x3 << 10); // 清除原有设置
GPIOA_MODER |= (0x1 << 10); // 设置为输出模式
}
注意:volatile关键字告诉编译器不要优化对此变量的访问,因为它的值可能被硬件改变。
13.2 中断处理
嵌入式系统中的中断处理示例:
c复制#include <stdint.h>
// 中断处理函数
void __attribute__((interrupt)) TIM2_IRQHandler(void) {
// 处理中断
if(TIM2->SR & TIM_SR_UIF) { // 检查更新中断标志
// 清除中断标志
TIM2->SR &= ~TIM_SR_UIF;
// 中断处理代码
}
}
void configureTimerInterrupt() {
// 配置定时器2
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // 使能定时器2时钟
TIM2->PSC = 8399; // 预分频器
TIM2->ARR = 9999; // 自动重装载值
// 使能更新中断
TIM2->DIER |= TIM_DIER_UIE;
// 配置NVIC
NVIC_EnableIRQ(TIM2_IRQn);
NVIC_SetPriority(TIM2_IRQn, 1);
// 启动定时器
TIM2->CR1 |= TIM_CR1_CEN;
}
14. 代码风格与可维护性
14.1 良好的命名规范
- 变量和函数名使用小写加下划线风格
- 常量使用全大写
- 类型定义使用首字母大写的驼峰命名
- 避免使用缩写,除非是广泛认可的
示例:
c复制// 好的命名
int calculate_average(const int *scores, size_t count);
// 不好的命名
int calc_avg(const int *s, size_t c);
14.2 模块化设计
将功能分解为独立的模块:
- 每个模块有明确的职责
- 最小化模块间的依赖
- 使用头文件声明接口
- 实现细节隐藏在.c文件中
示例模块结构:
code复制math_operations/
├── math_operations.h // 接口声明
└── math_operations.c // 实现细节
15. 测试与调试策略
15.1 单元测试框架
使用Unity等测试框架进行单元测试:
c复制#include "unity.h"
#include "math_operations.h"
void setUp(void) {
// 测试前的初始化
}
void tearDown(void) {
// 测试后的清理
}
void test_addition(void) {
TEST_ASSERT_EQUAL_INT(5, add(2, 3));
TEST_ASSERT_EQUAL_INT(-1, add(2, -3));
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_addition);
return UNITY_END();
}
15.2 断言的使用
合理使用assert进行调试:
c复制#include <assert.h>
double divide(double a, double b) {
assert(b != 0.0); // 调试时检查除数不为零
return a / b;
}
注意:在发布版本中可以通过定义NDEBUG宏来禁用assert。
16. 性能分析工具
16.1 gprof使用
使用gprof进行性能分析:
- 编译时加上-pg选项
- 运行程序生成gmon.out
- 使用gprof分析结果
示例:
bash复制gcc -pg -o program program.c
./program
gprof program gmon.out > analysis.txt
16.2 perf工具
Linux下的perf工具使用:
bash复制perf stat ./program # 基本统计
perf record ./program # 记录性能数据
perf report # 查看报告
17. 安全编程实践
17.1 缓冲区溢出防护
防止缓冲区溢出的技巧:
- 使用安全的字符串函数(strncpy等)
- 检查输入长度
- 使用边界检查函数(C11)
- 启用栈保护(-fstack-protector)
示例:
c复制#include <stdio.h>
#include <string.h>
void safeCopy(char *dest, const char *src, size_t dest_size) {
if(dest_size == 0) return;
strncpy(dest, src, dest_size - 1);
dest[dest_size - 1] = '\0';
}
int main() {
char buffer[10];
safeCopy(buffer, "这是一个很长的字符串", sizeof(buffer));
printf("%s\n", buffer);
return 0;
}
17.2 整数溢出防护
防止整数溢出的方法:
- 检查运算结果是否超出范围
- 使用安全的数学库
- 使用更大的数据类型进行中间计算
示例:
c复制#include <stdio.h>
#include <limits.h>
int safeAdd(int a, int b) {
if((b > 0 && a > INT_MAX - b) ||
(b < 0 && a < INT_MIN - b)) {
printf("整数溢出风险\n");
return 0;
}
return a + b;
}
int main() {
printf("%d\n", safeAdd(INT_MAX, 1));
return 0;
}
18. 多线程编程
18.1 pthread基础
使用pthread进行多线程编程:
c复制#include <stdio.h>
#include <pthread.h>
void* threadFunc(void* arg) {
int thread_num = *(int*)arg;
printf("线程%d运行中\n", thread_num);
return NULL;
}
int main() {
pthread_t thread1, thread2;
int num1 = 1, num2 = 2;
pthread_create(&thread1, NULL, threadFunc, &num1);
pthread_create(&thread2, NULL, threadFunc, &num2);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
printf("所有线程已完成\n");
return 0;
}
18.2 线程同步
使用互斥锁进行线程同步:
c复制#include <stdio.h>
#include <pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int shared_data = 0;
void* threadFunc(void* arg) {
for(int i = 0; i < 100000; i++) {
pthread_mutex_lock(&mutex);
shared_data++;
pthread_mutex_unlock(&mutex);
}
return NULL;
}
int main() {
pthread_t thread1, thread2;
pthread_create(&thread1, NULL, threadFunc, NULL);
pthread_create(&thread2, NULL, threadFunc, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
printf("共享数据最终值:%d\n", shared_data);
return 0;
}
19. 网络编程基础
19.1 TCP客户端/服务器
简单的TCP服务器实现:
c复制#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};
// 创建socket文件描述符
if((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 设置socket选项
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);
// 绑定socket到端口
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("服务器监听端口 %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("收到消息:%s\n", buffer);
// 发送响应
char* response = "Hello from server";
send(new_socket, response, strlen(response), 0);
printf("响应已发送\n");
close(new_socket);
close(server_fd);
return 0;
}
19.2 UDP通信示例
UDP客户端/服务器实现:
c复制// UDP服务器
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys
