1. 内存管理
示例:动态分配和释放二维数组
#include <stdio.h>
#include <stdlib.h>
int main() {
int rows = 3, cols = 4;
// 动态分配二维数组
int **array = (int **)malloc(rows * sizeof(int *));
if (array == NULL) {
perror("Failed to allocate memory");
return 1;
}
for (int i = 0; i < rows; i++) {
array[i] = (int *)malloc(cols * sizeof(int));
if (array[i] == NULL) {
perror("Failed to allocate memory");
// 释放已分配的内存
for (int j = 0; j < i; j++) {
free(array[j]);
}
free(array);
return 1;
}
}
// 初始化并打印数组
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
array[i][j] = i * cols + j;
printf("%d ", array[i][j]);
}
printf("\n");
}
// 释放内存
for (int i = 0; i < rows; i++) {
free(array[i]);
}
free(array);
return 0;
}
解释:
- 使用
malloc
动态分配内存来创建一个二维数组。 - 检查每次分配是否成功,避免内存泄漏。
- 使用完毕后,使用
free
释放所有分配的内存。
2. 指针和多级指针
示例:使用多级指针修改变量的值
#include <stdio.h>
int main() {
int value = 10;
int *ptr = &value;
int **ptr2 = &ptr;
printf("Original value: %d\n", value); // 输出 10
**ptr2 = 20;
printf("Modified value: %d\n", value); // 输出 20
return 0;
}
解释:
ptr
是指向value
的指针。ptr2
是指向ptr
的指针(多级指针)。- 通过
**ptr2
修改value
的值。
3. 指针运算
示例:指针与数组的关系
#include <stdio.h>
int main() {
int arr[] = {10, 20, 30, 40, 50};
int *ptr = arr; // 数组名作为指针
for (int i = 0; i < 5; i++) {
printf("Element %d: %d\n", i, *(ptr + i));
}
return 0;
}
解释:
- 数组名
arr
可以作为指针使用。 - 通过指针运算
*(ptr + i)
访问数组元素。
4. 位操作
示例:设置、清除和切换位
#include <stdio.h>
int main() {
unsigned int num = 0b0000; // 初始为 0
// 设置第2位(从0开始计数)
num |= (1 << 2);
printf("After setting bit 2: %04b\n", num); // 输出 0100
// 清除第2位
num &= ~(1 << 2);
printf("After clearing bit 2: %04b\n", num); // 输出 0000
// 切换第1位
num ^= (1 << 1);
printf("After toggling bit 1: %04b\n", num); // 输出 0010
return 0;
}
解释:
- 使用位运算符
|
,&
,^
来设置、清除和切换特定位。 1 << n
用于创建一个掩码,将第n
位设为1。
5. 宏和预处理器
示例:使用宏定义和条件编译
#include <stdio.h>
#define PI 3.14159
#define SQUARE(x) ((x) * (x))
// 条件编译
#define DEBUG
int main() {
double radius = 5.0;
double area = PI * SQUARE(radius);
printf("Area: %.2f\n", area);
#ifdef DEBUG
printf("Debug Mode: radius=%.2f, area=%.2f\n", radius, area);
#endif
return 0;
}
解释:
#define
用于定义常量和宏函数。- 宏
SQUARE(x)
计算x
的平方。 - 使用
#ifdef
进行条件编译,根据是否定义DEBUG
来决定是否输出调试信息。
6. 函数指针
示例:使用函数指针实现回调
#include <stdio.h>
// 定义函数指针类型
typedef void (*Callback)(int);
// 一个接受回调函数的函数
void process(int data, Callback cb) {
// 处理数据
data += 10;
// 调用回调函数
cb(data);
}
// 回调函数
void myCallback(int result) {
printf("Callback called with result: %d\n", result);
}
int main() {
int value = 5;
process(value, myCallback); // 传递回调函数
return 0;
}
解释:
- 定义一个函数指针类型
Callback
,指向接受int
参数且返回void
的函数。 process
函数接受一个整数和一个回调函数指针,处理数据后调用回调。- 在
main
中,将myCallback
作为回调函数传递给process
。
7. 复杂的结构体和联合体
示例:使用嵌套结构体和联合体
#include <stdio.h>
#include <string.h>
// 定义日期结构体
typedef struct {
int year;
int month;
int day;
} Date;
// 定义人员结构体,包含联合体
typedef struct {
char name[50];
int age;
Date birthdate;
union {
char studentID[20];
char employeeID[20];
} id;
int isStudent; // 1 表示学生,0 表示员工
} Person;
int main() {
Person p1;
strcpy(p1.name, "Alice");
p1.age = 25;
p1.birthdate.year = 1998;
p1.birthdate.month = 5;
p1.birthdate.day = 15;
p1.isStudent = 1;
strcpy(p1.id.studentID, "S12345678");
Person p2;
strcpy(p2.name, "Bob");
p2.age = 30;
p2.birthdate.year = 1993;
p2.birthdate.month = 8;
p2.birthdate.day = 22;
p2.isStudent = 0;
strcpy(p2.id.employeeID, "E87654321");
// 打印信息
printf("Person 1: %s, Age: %d, Birthdate: %04d-%02d-%02d, Student ID: %s\n",
p1.name, p1.age, p1.birthdate.year, p1.birthdate.month, p1.birthdate.day, p1.id.studentID);
printf("Person 2: %s, Age: %d, Birthdate: %04d-%02d-%02d, Employee ID: %s\n",
p2.name, p2.age, p2.birthdate.year, p2.birthdate.month, p2.birthdate.day, p2.id.employeeID);
return 0;
}
解释:
Person
结构体包含一个嵌套的Date
结构体和一个联合体id
,根据isStudent
标志使用不同的 ID。- 联合体
id
可以存储studentID
或employeeID
,但同一时间只能使用一个。
8. 异常处理和错误处理
示例:使用返回值和错误代码进行错误处理
#include <stdio.h>
#include <stdlib.h>
// 定义错误代码
#define SUCCESS 0
#define ERROR_INVALID_INPUT 1
#define ERROR_ALLOCATION_FAILED 2
// 函数:计算数组的平均值
int calculate_average(int *arr, int size, double *average) {
if (arr == NULL || average == NULL) {
return ERROR_INVALID_INPUT;
}
if (size <= 0) {
return ERROR_INVALID_INPUT;
}
long sum = 0;
for (int i = 0; i < size; i++) {
sum += arr[i];
}
*average = (double)sum / size;
return SUCCESS;
}
int main() {
int data[] = {10, 20, 30, 40, 50};
double avg;
int status = calculate_average(data, 5, &avg);
if (status == SUCCESS) {
printf("Average: %.2f\n", avg);
} else if (status == ERROR_INVALID_INPUT) {
fprintf(stderr, "Error: Invalid input provided.\n");
} else if (status == ERROR_ALLOCATION_FAILED) {
fprintf(stderr, "Error: Memory allocation failed.\n");
} else {
fprintf(stderr, "Error: Unknown error occurred.\n");
}
return status;
}
解释:
calculate_average
函数通过返回值指示操作是否成功,并通过指针参数返回结果。- 在
main
函数中,根据返回的状态码进行相应的错误处理和信息输出。
这些示例涵盖了 C 语言中一些较为复杂的概念和技术。通过理解和练习这些示例,你可以更深入地掌握 C 语言的高级特性和底层操作。如果你有任何具体问题或需要进一步的解释,请随时告诉我!