C语言经典100例程序教程
说明
本教程按照题目类型划分为 10 个部分,每部分包含 10 个例题,既适合初学者入门,也能帮助进阶者巩固基本算法和数据结构的实现。
编译示例程序时,请使用支持 C99 或更高标准的编译器,例如:gcc example.c -std=c99 -o example
📑 目录
- 基础语法(例 01 ~ 10)
- 字符串与数组(例 11 ~ 20)
- 排序与搜索算法(例 21 ~ 30)
- 数据结构(例 31 ~ 40)
- 递归与经典问题(例 41 ~ 50)
- 指针与内存管理(例 51 ~ 60)
- 文件 I/O 与错误处理(例 61 ~ 70)
- 位操作与数值运算(例 71 ~ 80)
- 实用算法与综合实例(例 81 ~ 90)
- 杂项与拓展练习(例 91 ~ 100)
基础语法(例 01 ~ 10)
例 01 — Hello World
#include <stdio.h>
int main(void) {
printf("Hello, World!\n");
return 0;
}
说明:最简单的 C 程序,输出 “Hello, World!”。
例 02 — 交换两个整数(不借助第三变量,利用异或)
#include <stdio.h>
int main(void) {
int a, b;
printf("请输入两个整数:");
scanf("%d %d", &a, &b);
// 利用异或进行交换
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("交换后:a = %d, b = %d\n", a, b);
return 0;
}
说明:利用异或运算符实现不借助临时变量的交换。
例 03 — 阶乘(递归实现)
#include <stdio.h>
long long factorial(int n) {
return n <= 1 ? 1 : n * factorial(n - 1);
}
int main(void) {
int n;
printf("请输入一个整数:");
scanf("%d", &n);
printf("%d 的阶乘是 %lld\n", n, factorial(n));
return 0;
}
说明:使用递归方式计算阶乘。
例 04 — 斐波那契数列(迭代实现)
#include <stdio.h>
int main(void) {
int n;
printf("请输入斐波那契数列项数:");
scanf("%d", &n);
long long a = 0, b = 1, temp;
printf("斐波那契数列:\n");
for (int i = 0; i < n; i++) {
printf("%lld ", a);
temp = a + b;
a = b;
b = temp;
}
printf("\n");
return 0;
}
说明:利用迭代求斐波那契序列。
例 05 — 判断质数
#include <stdio.h>
#include <math.h>
#include <stdbool.h>
bool isPrime(int n) {
if(n < 2) return false;
for (int i = 2; i <= (int)sqrt(n); i++) {
if (n % i == 0)
return false;
}
return true;
}
int main(void) {
int n;
printf("请输入一个整数:");
scanf("%d", &n);
printf("%d %s质数。\n", n, isPrime(n) ? "是" : "不是");
return 0;
}
说明:判断输入的整数是否为质数。
例 06 — 输出指定范围内的所有质数
#include <stdio.h>
#include <math.h>
#include <stdbool.h>
bool isPrime(int n) {
if(n < 2) return false;
for (int i = 2; i <= (int)sqrt(n); i++) {
if (n % i == 0)
return false;
}
return true;
}
int main(void) {
int lower, upper;
printf("请输入下界和上界:");
scanf("%d %d", &lower, &upper);
printf("区间内的质数有:\n");
for (int i = lower; i <= upper; i++) {
if (isPrime(i))
printf("%d ", i);
}
printf("\n");
return 0;
}
说明:遍历区间,依次判断打印质数。
例 07 — 最大公约数与最小公倍数
#include <stdio.h>
int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
int main(void) {
int a, b;
printf("请输入两个正整数:");
scanf("%d %d", &a, &b);
int g = gcd(a, b);
printf("最大公约数:%d\n", g);
printf("最小公倍数:%d\n", a / g * b);
return 0;
}
说明:利用欧几里得算法求 GCD,并计算 LCM。
例 08 — 反转整数
#include <stdio.h>
int main(void) {
int n, rev = 0;
printf("请输入一个整数:");
scanf("%d", &n);
while(n != 0) {
rev = rev * 10 + n % 10;
n /= 10;
}
printf("反转后的整数为:%d\n", rev);
return 0;
}
说明:利用循环求整数反转。
例 09 — 判断回文数
#include <stdio.h>
int main(void) {
int n, original, rev = 0;
printf("请输入一个整数:");
scanf("%d", &n);
original = n;
while(n != 0) {
rev = rev * 10 + n % 10;
n /= 10;
}
if(original == rev)
printf("是回文数。\n");
else
printf("不是回文数。\n");
return 0;
}
说明:检查输入整数正读和反读是否相同。
例 10 — 判断阿姆斯壮数(三位数)
#include <stdio.h>
#include <math.h>
int main(void) {
printf("三位阿姆斯壮数有:\n");
for (int n = 100; n <= 999; n++) {
int a = n / 100;
int b = (n / 10) % 10;
int c = n % 10;
if (a * a * a + b * b * b + c * c * c == n)
printf("%d ", n);
}
printf("\n");
return 0;
}
说明:输出所有三位阿姆斯壮数(立方和等于原数)。
字符串与数组(例 11 ~ 20)
例 11 — 求整数各位数字之和
#include <stdio.h>
int main(void) {
int n, sum = 0;
printf("请输入一个整数:");
scanf("%d", &n);
while(n != 0) {
sum += n % 10;
n /= 10;
}
printf("各位之和 = %d\n", sum);
return 0;
}
说明:利用循环将各位数字求和。
例 12 — 十进制转二进制(打印二进制表示)
#include <stdio.h>
void printBinary(unsigned int n) {
if(n > 1)
printBinary(n / 2);
printf("%d", n % 2);
}
int main(void) {
unsigned int n;
printf("请输入一个非负整数:");
scanf("%u", &n);
printf("二进制:");
printBinary(n);
printf("\n");
return 0;
}
说明:使用递归打印一个整数的二进制表示。
例 13 — 二进制字符串转十进制
#include <stdio.h>
#include <string.h>
int binaryToDecimal(const char *bin) {
int result = 0;
for (int i = 0; i < (int)strlen(bin); i++) {
result = result * 2 + (bin[i] - '0');
}
return result;
}
int main(void) {
char bin[65];
printf("请输入二进制字符串:");
scanf("%s", bin);
printf("十进制为:%d\n", binaryToDecimal(bin));
return 0;
}
说明:将一个二进制数字符串转换为十进制整数。
例 14 — 统计字符串中元音字母的个数
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(void) {
char str[256];
printf("请输入一行字符串:");
fgets(str, sizeof(str), stdin);
int count = 0;
for (int i = 0; i < (int)strlen(str); i++) {
char c = tolower(str[i]);
if (c == 'a' || c == 'e' || c == 'i' ||
c == 'o' || c == 'u') {
count++;
}
}
printf("元音字母个数:%d\n", count);
return 0;
}
说明:遍历字符串,并统计所有元音字符。
例 15 — 反转字符串
#include <stdio.h>
#include <string.h>
int main(void) {
char str[256];
printf("请输入一个字符串:");
fgets(str, sizeof(str), stdin);
int len = strlen(str);
if (str[len-1] == '\n') {
str[len-1] = '\0';
len--;
}
for (int i = 0; i < len / 2; i++) {
char temp = str[i];
str[i] = str[len - i - 1];
str[len - i - 1] = temp;
}
printf("反转后的字符串:%s\n", str);
return 0;
}
说明:利用双指针交换实现字符串反转。
例 16 — 判断回文字符串
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
bool isPalindrome(const char *str) {
int i = 0, j = strlen(str) - 1;
while(i < j) {
if(str[i] != str[j])
return false;
i++; j--;
}
return true;
}
int main(void) {
char str[256];
printf("请输入一个字符串:");
fgets(str, sizeof(str), stdin);
// 去除换行符
int len = strlen(str);
if(str[len-1]=='\n') str[len-1] = '\0';
printf("%s\n", isPalindrome(str) ? "是回文字符串" : "不是回文字符串");
return 0;
}
说明:判断输入的字符串是否正读与反读相同。
例 17 — 删除字符串中的元音字母
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(void) {
char str[256], result[256];
printf("请输入一个字符串:");
fgets(str, sizeof(str), stdin);
int idx = 0;
for (int i = 0; i < (int)strlen(str); i++) {
char c = tolower(str[i]);
if (c != 'a' && c != 'e' && c != 'i' && c != 'o' && c != 'u') {
result[idx++] = str[i];
}
}
result[idx] = '\0';
printf("删除元音后的字符串:%s\n", result);
return 0;
}
说明:遍历字符串,将非元音字符复制至新字符串。
例 18 — 冒泡排序(整型数组)
#include <stdio.h>
int main(void) {
int n;
printf("请输入数组元素个数:");
scanf("%d", &n);
int arr[n];
printf("请输入 %d 个整数:", n);
for(int i = 0; i < n; i++)
scanf("%d", &arr[i]);
// 冒泡排序
for(int i = 0; i < n - 1; i++)
for(int j = 0; j < n - i - 1; j++)
if(arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
printf("排序结果:");
for(int i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
return 0;
}
说明:利用冒泡排序对输入数组进行升序排序。
例 19 — 线性查找
#include <stdio.h>
int main(void) {
int n, key;
printf("请输入数组元素个数:");
scanf("%d", &n);
int arr[n];
printf("请输入 %d 个整数:", n);
for(int i = 0; i < n; i++)
scanf("%d", &arr[i]);
printf("请输入要查找的值:");
scanf("%d", &key);
for(int i = 0; i < n; i++) {
if(arr[i] == key) {
printf("找到 %d 在下标 %d 处。\n", key, i);
return 0;
}
}
printf("未找到 %d。\n", key);
return 0;
}
说明:遍历数组查找给定目标值。
例 20 — 递归实现二分查找(要求数组已排序)
#include <stdio.h>
int binarySearch(int arr[], int left, int right, int key) {
if (left > right)
return -1;
int mid = left + (right - left) / 2;
if (arr[mid] == key)
return mid;
else if(arr[mid] > key)
return binarySearch(arr, left, mid - 1, key);
else
return binarySearch(arr, mid + 1, right, key);
}
int main(void) {
int n, key;
printf("请输入数组元素个数:");
scanf("%d", &n);
int arr[n];
printf("请输入 %d 个排序后的整数:", n);
for(int i = 0; i < n; i++)
scanf("%d", &arr[i]);
printf("请输入要查找的值:");
scanf("%d", &key);
int index = binarySearch(arr, 0, n - 1, key);
if(index != -1)
printf("找到 %d 下标为 %d。\n", key, index);
else
printf("未找到 %d。\n", key);
return 0;
}
说明:利用递归实现二分查找。
排序与搜索算法(例 21 ~ 30)
例 21 — 选择排序
#include <stdio.h>
int main(void) {
int n;
printf("请输入数组元素个数:");
scanf("%d", &n);
int arr[n];
printf("请输入 %d 个整数:", n);
for(int i = 0; i < n; i++)
scanf("%d", &arr[i]);
// 选择排序
for(int i = 0; i < n - 1; i++) {
int minIndex = i;
for(int j = i + 1; j < n; j++) {
if(arr[j] < arr[minIndex])
minIndex = j;
}
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
printf("排序结果:");
for(int i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
return 0;
}
说明:依次选择最小值进行交换实现排序。
例 22 — 插入排序
#include <stdio.h>
int main(void) {
int n;
printf("请输入数组元素个数:");
scanf("%d", &n);
int arr[n];
printf("请输入 %d 个整数:", n);
for(int i = 0; i < n; i++)
scanf("%d", &arr[i]);
// 插入排序
for(int i = 1; i < n; i++) {
int key = arr[i];
int j = i - 1;
while(j >= 0 && arr[j] > key) {
arr[j+1] = arr[j];
j--;
}
arr[j+1] = key;
}
printf("排序结果:");
for(int i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
return 0;
}
说明:通过不断比较和插入将数组排序。
例 23 — 快速排序(递归实现)
#include <stdio.h>
void quickSort(int arr[], int left, int right) {
if (left >= right)
return;
int pivot = arr[(left + right) / 2];
int i = left, j = right;
while(i <= j) {
while(arr[i] < pivot) i++;
while(arr[j] > pivot) j--;
if(i <= j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
i++; j--;
}
}
quickSort(arr, left, j);
quickSort(arr, i, right);
}
int main(void) {
int n;
printf("请输入数组元素个数:");
scanf("%d", &n);
int arr[n];
printf("请输入 %d 个整数:", n);
for(int i = 0; i < n; i++)
scanf("%d", &arr[i]);
quickSort(arr, 0, n - 1);
printf("排序结果:");
for(int i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
return 0;
}
说明:利用递归和分治策略实现快速排序。
例 24 — 归并排序
#include <stdio.h>
#include <stdlib.h>
void merge(int arr[], int left, int mid, int right) {
int i, j, k;
int n1 = mid - left + 1, n2 = right - mid;
int *L = malloc(n1 * sizeof(int));
int *R = malloc(n2 * sizeof(int));
for (i = 0; i < n1; i++)
L[i] = arr[left + i];
for (j = 0; j < n2; j++)
R[j] = arr[mid + 1 + j];
i = j = 0, k = left;
while(i < n1 && j < n2) {
if(L[i] <= R[j])
arr[k++] = L[i++];
else
arr[k++] = R[j++];
}
while(i < n1)
arr[k++] = L[i++];
while(j < n2)
arr[k++] = R[j++];
free(L);
free(R);
}
void mergeSort(int arr[], int left, int right) {
if(left < right) {
int mid = left + (right - left) / 2;
mergeSort(arr, left, mid);
mergeSort(arr, mid+1, right);
merge(arr, left, mid, right);
}
}
int main(void) {
int n;
printf("请输入数组元素个数:");
scanf("%d", &n);
int arr[n];
printf("请输入 %d 个整数:", n);
for(int i = 0; i < n; i++)
scanf("%d", &arr[i]);
mergeSort(arr, 0, n - 1);
printf("排序结果:");
for(int i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
return 0;
}
说明:使用分治法实现归并排序,对数组进行排序。
例 25 — 计数排序(仅适用于非负整数)
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n;
printf("请输入数组元素个数:");
scanf("%d", &n);
int arr[n];
printf("请输入 %d 个非负整数:", n);
int max = 0;
for(int i = 0; i < n; i++){
scanf("%d", &arr[i]);
if(arr[i] > max)
max = arr[i];
}
int *count = calloc(max + 1, sizeof(int));
for(int i = 0; i < n; i++)
count[arr[i]]++;
printf("排序结果:");
for(int i = 0; i <= max; i++)
while(count[i]--)
printf("%d ", i);
printf("\n");
free(count);
return 0;
}
说明:利用计数数组统计各数字频率,实现排序(适用于非负整数)。
例 26 — 希尔排序
#include <stdio.h>
int main(void) {
int n;
printf("请输入数组元素个数:");
scanf("%d", &n);
int arr[n];
printf("请输入 %d 个整数:", n);
for (int i = 0; i < n; i++)
scanf("%d", &arr[i]);
// 希尔排序
for (int gap = n/2; gap > 0; gap /= 2) {
for (int i = gap; i < n; i++) {
int temp = arr[i];
int j = i;
while (j >= gap && arr[j - gap] > temp) {
arr[j] = arr[j - gap];
j -= gap;
}
arr[j] = temp;
}
}
printf("排序结果:");
for (int i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
return 0;
}
说明:通过缩小增量进行插入排序,完成希尔排序。
例 27 — 桶排序(对 0~1 之间的浮点数排序)
#include <stdio.h>
#include <stdlib.h>
#define BUCKETS 10
int cmp(const void *a, const void *b) {
float fa = *(const float*)a;
float fb = *(const float*)b;
return (fa > fb) - (fa < fb);
}
int main(void) {
int n;
printf("请输入数组元素个数:");
scanf("%d", &n);
float arr[n];
printf("请输入 %d 个浮点数(0 ~ 1之间):", n);
for (int i = 0; i < n; i++)
scanf("%f", &arr[i]);
// 创建桶
float **buckets = malloc(BUCKETS * sizeof(float*));
int *bucketCounts = calloc(BUCKETS, sizeof(int));
int *bucketSizes = calloc(BUCKETS, sizeof(int));
for (int i = 0; i < BUCKETS; i++) {
bucketSizes[i] = n / BUCKETS + 1;
buckets[i] = malloc(bucketSizes[i] * sizeof(float));
}
// 分配数据到桶中
for (int i = 0; i < n; i++) {
int idx = (int)(arr[i] * BUCKETS);
if(idx >= BUCKETS) idx = BUCKETS - 1;
buckets[idx][bucketCounts[idx]++] = arr[i];
}
// 桶内排序并合并
int index = 0;
for (int i = 0; i < BUCKETS; i++) {
qsort(buckets[i], bucketCounts[i], sizeof(float), cmp);
for (int j = 0; j < bucketCounts[i]; j++) {
arr[index++] = buckets[i][j];
}
free(buckets[i]);
}
free(buckets);
free(bucketCounts);
free(bucketSizes);
printf("排序结果:");
for (int i = 0; i < n; i++)
printf("%f ", arr[i]);
printf("\n");
return 0;
}
说明:采用桶排序对 0~1 之间的浮点数排序。
例 28 — 基数排序(适用于非负整数)
#include <stdio.h>
#include <stdlib.h>
int getMax(int arr[], int n) {
int max = arr[0];
for (int i = 1; i < n; i++)
if (arr[i] > max)
max = arr[i];
return max;
}
void countSort(int arr[], int n, int exp) {
int *output = malloc(n * sizeof(int));
int count[10] = {0};
for (int i = 0; i < n; i++)
count[(arr[i] / exp) % 10]++;
for (int i = 1; i < 10; i++)
count[i] += count[i - 1];
for (int i = n - 1; i >= 0; i--) {
output[count[(arr[i] / exp) % 10] - 1] = arr[i];
count[(arr[i] / exp) % 10]--;
}
for (int i = 0; i < n; i++)
arr[i] = output[i];
free(output);
}
void radixSort(int arr[], int n) {
int max = getMax(arr, n);
for (int exp = 1; max/exp > 0; exp *= 10)
countSort(arr, n, exp);
}
int main(void) {
int n;
printf("请输入数组元素个数:");
scanf("%d", &n);
int *arr = malloc(n * sizeof(int));
printf("请输入 %d 个非负整数:", n);
for (int i = 0; i < n; i++)
scanf("%d", &arr[i]);
radixSort(arr, n);
printf("排序结果:");
for (int i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
free(arr);
return 0;
}
说明:使用基数排序对非负整数数组进行排序。
例 29 — 洗牌算法(Fisher–Yates 算法)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void) {
int n;
printf("请输入数组元素个数:");
scanf("%d", &n);
int arr[n];
for (int i = 0; i < n; i++)
arr[i] = i + 1;
srand((unsigned)time(NULL));
for (int i = n - 1; i > 0; i--) {
int j = rand() % (i + 1);
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
printf("洗牌结果:");
for (int i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
return 0;
}
说明:随机打乱数组元素顺序。
例 30 — 使用随机排序实现简单乱序(与例29类似)
// 本例与例29实现相同,故略(读者可参照例29)。
说明:此处已给出洗牌算法示例。
数据结构(例 31 ~ 40)
例 31 — 数组实现栈
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 100
typedef struct {
int data[MAX_SIZE];
int top;
} Stack;
void initStack(Stack *s) {
s->top = -1;
}
int push(Stack *s, int value) {
if (s->top >= MAX_SIZE - 1)
return 0; // 栈满
s->data[++(s->top)] = value;
return 1;
}
int pop(Stack *s, int *value) {
if (s->top < 0)
return 0; // 栈空
*value = s->data[(s->top)--];
return 1;
}
int main(void) {
Stack s;
initStack(&s);
push(&s, 10);
push(&s, 20);
int value;
pop(&s, &value);
printf("出栈元素:%d\n", value);
return 0;
}
说明:利用数组实现简单的栈操作。
例 32 — 数组实现循环队列
#include <stdio.h>
#define MAX_SIZE 100
typedef struct {
int data[MAX_SIZE];
int front;
int rear;
int size;
} CircularQueue;
void initQueue(CircularQueue *q) {
q->front = 0;
q->rear = 0;
q->size = 0;
}
int enqueue(CircularQueue *q, int value) {
if (q->size == MAX_SIZE)
return 0; // 队列满
q->data[q->rear] = value;
q->rear = (q->rear + 1) % MAX_SIZE;
q->size++;
return 1;
}
int dequeue(CircularQueue *q, int *value) {
if (q->size == 0)
return 0; // 队列空
*value = q->data[q->front];
q->front = (q->front + 1) % MAX_SIZE;
q->size--;
return 1;
}
int main(void) {
CircularQueue q;
initQueue(&q);
enqueue(&q, 100);
enqueue(&q, 200);
int value;
dequeue(&q, &value);
printf("出队元素:%d\n", value);
return 0;
}
说明:使用数组和环形指针实现循环队列。
例 33 — 单链表的插入与遍历
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node *next;
} Node;
Node* createNode(int value) {
Node* node = malloc(sizeof(Node));
node->data = value;
node->next = NULL;
return node;
}
void insertAtHead(Node **head, int value) {
Node *node = createNode(value);
node->next = *head;
*head = node;
}
void traverseList(Node *head) {
while(head) {
printf("%d ", head->data);
head = head->next;
}
printf("\n");
}
int main(void) {
Node *head = NULL;
insertAtHead(&head, 3);
insertAtHead(&head, 2);
insertAtHead(&head, 1);
printf("链表内容:");
traverseList(head);
return 0;
}
说明:利用动态内存分配构建单链表,并遍历打印每个结点数据。
例 34 — 二叉树中序遍历(递归)
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node *left, *right;
} Node;
Node* createNode(int value) {
Node *node = malloc(sizeof(Node));
node->data = value;
node->left = node->right = NULL;
return node;
}
void inorder(Node *root) {
if(root == NULL)
return;
inorder(root->left);
printf("%d ", root->data);
inorder(root->right);
}
int main(void) {
// 构造简单二叉树
Node *root = createNode(2);
root->left = createNode(1);
root->right = createNode(3);
printf("中序遍历:");
inorder(root);
printf("\n");
return 0;
}
说明:递归实现二叉树的中序遍历。
例 35 — 二叉搜索树的插入与查找
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node *left, *right;
} Node;
Node* insert(Node *root, int value) {
if(root == NULL)
return createNode(value);
if(value < root->data)
root->left = insert(root->left, value);
else if(value > root->data)
root->right = insert(root->right, value);
return root;
}
Node* createNode(int value) {
Node *node = malloc(sizeof(Node));
node->data = value;
node->left = node->right = NULL;
return node;
}
int search(Node *root, int key) {
if(root == NULL)
return 0;
if(root->data == key)
return 1;
return key < root->data ? search(root->left, key) : search(root->right, key);
}
int main(void) {
Node *root = NULL;
int arr[] = {5, 3, 7, 2, 4, 6, 8};
for (int i = 0; i < 7; i++)
root = insert(root, arr[i]);
int key;
printf("请输入要查找的值:");
scanf("%d", &key);
printf("%s\n", search(root, key) ? "找到" : "未找到");
return 0;
}
说明:构造二叉搜索树,并实现查找功能。
例 36 — 图的深度优先搜索(邻接表存储)
#include <stdio.h>
#include <stdlib.h>
#define MAX_VERTICES 100
typedef struct Node {
int vertex;
struct Node *next;
} Node;
typedef struct {
Node *head;
} List;
void addEdge(List graph[], int src, int dest) {
Node *newNode = malloc(sizeof(Node));
newNode->vertex = dest;
newNode->next = graph[src].head;
graph[src].head = newNode;
}
void dfs(List graph[], int vertex, int visited[]) {
visited[vertex] = 1;
printf("%d ", vertex);
Node *temp = graph[vertex].head;
while(temp) {
if(!visited[temp->vertex])
dfs(graph, temp->vertex, visited);
temp = temp->next;
}
}
int main(void) {
int V = 5;
List graph[V];
for(int i = 0; i < V; i++)
graph[i].head = NULL;
addEdge(graph, 0, 1); addEdge(graph, 0, 4);
addEdge(graph, 1, 2); addEdge(graph, 1, 3);
addEdge(graph, 1, 4);
addEdge(graph, 2, 3);
addEdge(graph, 3, 4);
int visited[V];
for(int i = 0; i < V; i++) visited[i] = 0;
printf("深度优先遍历:");
dfs(graph, 0, visited);
printf("\n");
return 0;
}
说明:利用邻接表存储图,并用递归实现 DFS 遍历。
例 37 — 图的广度优先搜索(邻接表存储)
#include <stdio.h>
#include <stdlib.h>
#define MAX_VERTICES 100
typedef struct Node {
int vertex;
struct Node *next;
} Node;
typedef struct {
Node *head;
} List;
typedef struct {
int items[MAX_VERTICES];
int front, rear;
} Queue;
void initQueue(Queue *q) {
q->front = 0;
q->rear = -1;
}
int isEmpty(Queue *q) {
return q->rear < q->front;
}
void enqueue(Queue *q, int value) {
q->items[++(q->rear)] = value;
}
int dequeue(Queue *q) {
return q->items[(q->front)++];
}
void addEdge(List graph[], int src, int dest) {
Node *newNode = malloc(sizeof(Node));
newNode->vertex = dest;
newNode->next = graph[src].head;
graph[src].head = newNode;
}
void bfs(List graph[], int start, int V) {
int visited[MAX_VERTICES] = {0};
Queue q;
initQueue(&q);
visited[start] = 1;
enqueue(&q, start);
while(!isEmpty(&q)) {
int current = dequeue(&q);
printf("%d ", current);
Node *temp = graph[current].head;
while(temp) {
if(!visited[temp->vertex]) {
visited[temp->vertex] = 1;
enqueue(&q, temp->vertex);
}
temp = temp->next;
}
}
}
int main(void) {
int V = 5;
List graph[V];
for (int i = 0; i < V; i++)
graph[i].head = NULL;
addEdge(graph, 0, 1); addEdge(graph, 0, 4);
addEdge(graph, 1, 2); addEdge(graph, 1, 3);
addEdge(graph, 1, 4);
addEdge(graph, 2, 3);
addEdge(graph, 3, 4);
printf("广度优先遍历:");
bfs(graph, 0, V);
printf("\n");
return 0;
}
说明:利用队列实现图的广度优先搜索。
例 38 — 并查集(Union-Find)
#include <stdio.h>
#include <stdlib.h>
int find(int parent[], int i) {
if (parent[i] == i)
return i;
return parent[i] = find(parent, parent[i]);
}
void unionSet(int parent[], int rank[], int x, int y) {
int xroot = find(parent, x);
int yroot = find(parent, y);
if (xroot == yroot)
return;
if (rank[xroot] < rank[yroot])
parent[xroot] = yroot;
else if (rank[xroot] > rank[yroot])
parent[yroot] = xroot;
else {
parent[yroot] = xroot;
rank[xroot]++;
}
}
int main(void) {
int n = 5;
int parent[n], rank[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
rank[i] = 0;
}
// 合并几个集合:例如合并 (0,1), (1,2)
unionSet(parent, rank, 0, 1);
unionSet(parent, rank, 1, 2);
printf("0 和 2 %s同一个集合。\n", find(parent, 0) == find(parent, 2) ? "属于" : "不属于");
return 0;
}
说明:利用并查集判断集合合并及查找操作。
例 39 — 简单动态数组实现
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n;
printf("请输入元素个数:");
scanf("%d", &n);
int *arr = malloc(n * sizeof(int));
if(arr == NULL) {
printf("内存分配失败。\n");
return 1;
}
printf("请输入 %d 个整数:", n);
for(int i = 0; i < n; i++)
scanf("%d", &arr[i]);
printf("动态数组内容:");
for(int i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
free(arr);
return 0;
}
说明:利用 malloc 动态分配数组内存,实现基本动态数组操作。
例 40 — 简单哈希表(开放寻址法,散列函数取模)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TABLE_SIZE 10
typedef struct {
int key;
int value;
int occupied;
} HashEntry;
void initTable(HashEntry table[]) {
for (int i = 0; i < TABLE_SIZE; i++) {
table[i].occupied = 0;
}
}
int hashFunction(int key) {
return key % TABLE_SIZE;
}
void insert(HashEntry table[], int key, int value) {
int index = hashFunction(key);
while(table[index].occupied) {
index = (index + 1) % TABLE_SIZE;
}
table[index].key = key;
table[index].value = value;
table[index].occupied = 1;
}
int search(HashEntry table[], int key) {
int index = hashFunction(key);
int start = index;
while(table[index].occupied) {
if(table[index].key == key)
return table[index].value;
index = (index + 1) % TABLE_SIZE;
if(index == start)
break;
}
return -1; // 未找到
}
int main(void) {
HashEntry table[TABLE_SIZE];
initTable(table);
insert(table, 15, 100);
insert(table, 25, 200);
printf("键 15 对应的值:%d\n", search(table, 15));
printf("键 25 对应的值:%d\n", search(table, 25));
return 0;
}
说明:用简单的开放寻址法实现哈希表的插入和查找。
递归与经典问题(例 41 ~ 50)
例 41 — 汉诺塔问题
#include <stdio.h>
void hanoi(int n, char from, char aux, char to) {
if(n == 1) {
printf("%c -> %c\n", from, to);
return;
}
hanoi(n-1, from, to, aux);
printf("%c -> %c\n", from, to);
hanoi(n-1, aux, from, to);
}
int main(void) {
int n;
printf("请输入盘子的数量:");
scanf("%d", &n);
hanoi(n, 'A', 'B', 'C');
return 0;
}
说明:递归解决汉诺塔问题。
例 42 — N 皇后问题(求解方案数)
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
int N, solutions = 0;
int *col, *diag1, *diag2;
void solve(int row) {
if(row == N) {
solutions++;
return;
}
for (int c = 0; c < N; c++) {
if (!col[c] && !diag1[row+c] && !diag2[row-c+N-1]) {
col[c] = diag1[row+c] = diag2[row-c+N-1] = 1;
solve(row + 1);
col[c] = diag1[row+c] = diag2[row-c+N-1] = 0;
}
}
}
int main(void) {
printf("请输入皇后个数:");
scanf("%d", &N);
col = calloc(N, sizeof(int));
diag1 = calloc(2*N-1, sizeof(int));
diag2 = calloc(2*N-1, sizeof(int));
solve(0);
printf("共有 %d 种解法。\n", solutions);
free(col); free(diag1); free(diag2);
return 0;
}
说明:采用回溯法求解 N 皇后问题。
例 43 — 全排列(递归生成数组排列)
#include <stdio.h>
#include <stdlib.h>
void swap(int *a, int *b) {
int temp = *a; *a = *b; *b = temp;
}
void permute(int arr[], int l, int r) {
if (l == r) {
for (int i = 0; i <= r; i++)
printf("%d ", arr[i]);
printf("\n");
} else {
for (int i = l; i <= r; i++) {
swap(&arr[l], &arr[i]);
permute(arr, l+1, r);
swap(&arr[l], &arr[i]); // 回溯
}
}
}
int main(void) {
int n;
printf("请输入数组元素个数:");
scanf("%d", &n);
int *arr = malloc(n * sizeof(int));
printf("请输入 %d 个整数:", n);
for (int i = 0; i < n; i++)
scanf("%d", &arr[i]);
printf("全排列结果:\n");
permute(arr, 0, n-1);
free(arr);
return 0;
}
说明:利用递归生成数组的所有排列组合。
例 44 — 帕斯卡三角形
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n;
printf("请输入行数:");
scanf("%d", &n);
int **triangle = malloc(n * sizeof(int *));
for (int i = 0; i < n; i++) {
triangle[i] = malloc((i+1) * sizeof(int));
for (int j = 0; j <= i; j++) {
if(j == 0 || j == i)
triangle[i][j] = 1;
else
triangle[i][j] = triangle[i-1][j-1] + triangle[i-1][j];
printf("%d ", triangle[i][j]);
}
printf("\n");
}
for (int i = 0; i < n; i++)
free(triangle[i]);
free(triangle);
return 0;
}
说明:利用二维数组构造并打印帕斯卡三角形。
例 45 — 泰勒级数展开计算 sin(x)(近似)
#include <stdio.h>
double mysin(double x, int terms) {
double sum = 0;
double term = x;
int sign = 1;
for (int i = 1, j = 1; i <= terms; i++, j += 2) {
sum += sign * term;
term = term * x * x / ((j + 1) * (j + 2));
sign = -sign;
}
return sum;
}
int main(void) {
double x;
printf("请输入角度(弧度):");
scanf("%lf", &x);
printf("sin(%.2lf) ≈ %lf\n", x, mysin(x, 10));
return 0;
}
说明:利用泰勒展开近似计算 sin(x) 值。
例 46 — 简易命令行计算器
#include <stdio.h>
int main(void) {
double a, b;
char op;
printf("输入计算表达式(例如 3.5 + 2.1):");
scanf("%lf %c %lf", &a, &op, &b);
switch(op) {
case '+': printf("结果:%lf\n", a + b); break;
case '-': printf("结果:%lf\n", a - b); break;
case '*': printf("结果:%lf\n", a * b); break;
case '/':
if(b != 0)
printf("结果:%lf\n", a / b);
else
printf("错误:除数为 0\n");
break;
default: printf("不支持的运算符\n");
}
return 0;
}
说明:利用 switch-case 实现简单的四则运算计算器。
例 47 — 贪心算法解决找零问题
#include <stdio.h>
int main(void) {
int amount;
int coins[] = {50, 20, 10, 5, 1};
int n = sizeof(coins) / sizeof(coins[0]);
printf("请输入找零金额:");
scanf("%d", &amount);
printf("找零方案:\n");
for(int i = 0; i < n; i++) {
int num = amount / coins[i];
amount %= coins[i];
printf("面额 %d: %d 个\n", coins[i], num);
}
return 0;
}
说明:采用贪心策略,计算不同面额的硬币数量。
例 48 — 0/1 背包问题(动态规划实现)
#include <stdio.h>
#include <stdlib.h>
int max(int a, int b) {
return a > b ? a : b;
}
int main(void) {
int n, W;
printf("请输入物品数和背包容量:");
scanf("%d %d", &n, &W);
int *weights = malloc(n * sizeof(int));
int *values = malloc(n * sizeof(int));
printf("请输入每个物品的重量和价值:\n");
for (int i = 0; i < n; i++)
scanf("%d %d", &weights[i], &values[i]);
int **dp = malloc((n+1) * sizeof(int *));
for (int i = 0; i <= n; i++) {
dp[i] = calloc(W+1, sizeof(int));
}
for (int i = 1; i <= n; i++) {
for (int w = 1; w <= W; w++) {
if (weights[i-1] <= w)
dp[i][w] = max(dp[i-1][w], dp[i-1][w-weights[i-1]] + values[i-1]);
else
dp[i][w] = dp[i-1][w];
}
}
printf("最大价值:%d\n", dp[n][W]);
for (int i = 0; i <= n; i++)
free(dp[i]);
free(dp); free(weights); free(values);
return 0;
}
说明:利用二维动态规划数组实现 0/1 背包问题求最大价值。
例 49 — 大数阶乘(利用数组存储每位数字)
#include <stdio.h>
#include <string.h>
#define MAX_DIGITS 1000
int main(void) {
int n;
printf("请输入整数 n:");
scanf("%d", &n);
int result[MAX_DIGITS] = {0};
result[0] = 1;
int len = 1;
for (int x = 2; x <= n; x++) {
int carry = 0;
for (int i = 0; i < len; i++) {
int prod = result[i] * x + carry;
result[i] = prod % 10;
carry = prod / 10;
}
while(carry) {
result[len++] = carry % 10;
carry /= 10;
}
}
printf("%d! = ", n);
for (int i = len - 1; i >= 0; i--)
printf("%d", result[i]);
printf("\n");
return 0;
}
说明:利用数组模拟大整数乘法,计算 n 的阶乘。
例 50 — KMP 算法实现字符串匹配
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void computeLPS(const char *pat, int M, int *lps) {
int length = 0;
lps[0] = 0;
int i = 1;
while(i < M) {
if(pat[i] == pat[length]) {
length++;
lps[i] = length;
i++;
} else {
if(length != 0)
length = lps[length - 1];
else {
lps[i] = 0;
i++;
}
}
}
}
void KMPSearch(const char *txt, const char *pat) {
int N = strlen(txt);
int M = strlen(pat);
int *lps = malloc(M * sizeof(int));
computeLPS(pat, M, lps);
int i = 0, j = 0;
while(i < N) {
if(pat[j] == txt[i]) {
i++; j++;
}
if(j == M) {
printf("找到匹配,位置:%d\n", i - j);
j = lps[j - 1];
} else if(i < N && pat[j] != txt[i]) {
if(j != 0)
j = lps[j - 1];
else
i++;
}
}
free(lps);
}
int main(void) {
char txt[256], pat[256];
printf("请输入文本:");
scanf("%s", txt);
printf("请输入模式串:");
scanf("%s", pat);
KMPSearch(txt, pat);
return 0;
}
说明:利用 KMP 算法进行字符串匹配,并输出匹配位置。
指针与内存管理(例 51 ~ 60)
例 51 — 指针基本使用及地址输出
#include <stdio.h>
int main(void) {
int a = 10;
int *p = &a;
printf("a = %d, 地址 = %p\n", a, (void*)&a);
printf("指针 p 的值 = %p, *p = %d\n", (void*)p, *p);
return 0;
}
说明:演示变量与指针的基本用法及输出地址。
例 52 — 指针算术运算示例
#include <stdio.h>
int main(void) {
int arr[] = {10, 20, 30, 40, 50};
int *p = arr;
printf("数组地址:%p\n", (void*)arr);
printf("指针 p 初始指向:%d\n", *p);
p++;
printf("p++ 后指向:%d\n", *p);
return 0;
}
说明:展示指针自增及数组元素访问。
例 53 — 动态内存分配(malloc 和 free 示例)
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n;
printf("请输入动态数组大小:");
scanf("%d", &n);
int *arr = malloc(n * sizeof(int));
if(arr == NULL) {
printf("内存分配失败!\n");
return 1;
}
for (int i = 0; i < n; i++)
arr[i] = i + 1;
printf("动态数组内容:");
for (int i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
free(arr);
return 0;
}
说明:使用 malloc 分配内存,并在使用后调用 free 释放。
例 54 — 利用指针交换两个数(传地址方式)
#include <stdio.h>
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main(void) {
int x = 5, y = 10;
printf("交换前:x = %d, y = %d\n", x, y);
swap(&x, &y);
printf("交换后:x = %d, y = %d\n", x, y);
return 0;
}
说明:演示通过函数和指针交换两个变量的值。
例 55 — 利用指针反转数组
#include <stdio.h>
void reverseArray(int *arr, int n) {
int *start = arr, *end = arr + n - 1;
while(start < end) {
int temp = *start;
*start = *end;
*end = temp;
start++; end--;
}
}
int main(void) {
int n;
printf("请输入数组大小:");
scanf("%d", &n);
int arr[n];
printf("请输入 %d 个整数:", n);
for (int i = 0; i < n; i++)
scanf("%d", &arr[i]);
reverseArray(arr, n);
printf("反转后的数组:");
for (int i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
return 0;
}
说明:通过指针操作交换数组元素,实现数组反转。
例 56 — 演示内存泄漏与修复
#include <stdio.h>
#include <stdlib.h>
int main(void) {
// 内存泄漏示例
int *ptr = malloc(10 * sizeof(int));
if(ptr == NULL) {
printf("内存分配失败\n");
return 1;
}
// 进行一些操作……
// 忘记调用 free(ptr);
// 修复方法:调用 free(ptr) 释放内存
free(ptr);
printf("内存已释放,避免内存泄漏。\n");
return 0;
}
说明:示范内存分配后及时释放,避免内存泄漏。
例 57 — 双重指针使用(指针数组示例)
#include <stdio.h>
int main(void) {
int a = 100;
int *p = &a;
int **pp = &p;
printf("a = %d\n", a);
printf("*p = %d\n", *p);
printf("**pp = %d\n", **pp);
return 0;
}
说明:演示二级指针的基本用法。
例 58 — 利用动态内存构造链表(malloc实现)
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node *next;
} Node;
Node* createNode(int value) {
Node *node = malloc(sizeof(Node));
node->data = value;
node->next = NULL;
return node;
}
void insertAtHead(Node **head, int value) {
Node *node = createNode(value);
node->next = *head;
*head = node;
}
void traverseList(Node *head) {
while(head) {
printf("%d ", head->data);
head = head->next;
}
printf("\n");
}
int main(void) {
Node *head = NULL;
insertAtHead(&head, 10);
insertAtHead(&head, 20);
insertAtHead(&head, 30);
printf("链表内容:");
traverseList(head);
return 0;
}
说明:动态分配内存构造链表,实现基本插入和遍历。
例 59 — 结构体指针的基本使用
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int id;
char name[50];
} Person;
int main(void) {
Person *p = malloc(sizeof(Person));
p->id = 1;
snprintf(p->name, sizeof(p->name), "Alice");
printf("ID: %d, Name: %s\n", p->id, p->name);
free(p);
return 0;
}
说明:演示如何使用结构体指针存取数据。
例 60 — 函数指针示例(简单回调)
#include <stdio.h>
int add(int a, int b) {
return a + b;
}
int operate(int a, int b, int (*op)(int, int)) {
return op(a, b);
}
int main(void) {
int result = operate(5, 3, add);
printf("结果:%d\n", result);
return 0;
}
说明:通过函数指针实现回调机制。
文件 I/O 与错误处理(例 61 ~ 70)
例 61 — 写入文本到文件
#include <stdio.h>
int main(void) {
FILE *fp = fopen("output.txt", "w");
if(fp == NULL) {
perror("打开文件失败");
return 1;
}
fprintf(fp, "Hello, File!\n");
fclose(fp);
printf("写入文件成功。\n");
return 0;
}
说明:将文本写入文件,并检查打开文件是否成功。
例 62 — 读取文件逐行输出
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE *fp = fopen("output.txt", "r");
if(fp == NULL) {
perror("打开文件失败");
return 1;
}
char line[256];
while(fgets(line, sizeof(line), fp)) {
printf("%s", line);
}
fclose(fp);
return 0;
}
说明:逐行读取文件内容并输出到屏幕。
例 63 — 文件复制
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE *src = fopen("output.txt", "r");
if(src == NULL) {
perror("打开源文件失败");
return 1;
}
FILE *dest = fopen("copy.txt", "w");
if(dest == NULL) {
perror("打开目标文件失败");
fclose(src);
return 1;
}
char buffer[1024];
size_t bytes;
while((bytes = fread(buffer, 1, sizeof(buffer), src)) > 0)
fwrite(buffer, 1, bytes, dest);
fclose(src);
fclose(dest);
printf("文件复制成功。\n");
return 0;
}
说明:利用 fread 和 fwrite 实现二进制文件复制。
例 64 — 统计文件中单词数
#include <stdio.h>
#include <ctype.h>
int main(void) {
FILE *fp = fopen("output.txt", "r");
if(fp == NULL) {
perror("打开文件失败");
return 1;
}
int c, prev = ' ';
int words = 0;
while ((c = fgetc(fp)) != EOF) {
if(isspace(prev) && !isspace(c))
words++;
prev = c;
}
fclose(fp);
printf("单词总数:%d\n", words);
return 0;
}
说明:遍历文件字符,统计单词的数量。
例 65 — 向文件追加文本
#include <stdio.h>
int main(void) {
FILE *fp = fopen("output.txt", "a");
if(fp == NULL) {
perror("打开文件失败");
return 1;
}
fprintf(fp, "追加一行文本。\n");
fclose(fp);
printf("文件追加成功。\n");
return 0;
}
说明:以追加模式打开文件,并写入新内容。
例 66 — CSV 文件读取简单示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
FILE *fp = fopen("data.csv", "r");
if(fp == NULL) {
perror("打开 CSV 文件失败");
return 1;
}
char line[256];
while(fgets(line, sizeof(line), fp)) {
char *token = strtok(line, ",");
while(token) {
printf("%s ", token);
token = strtok(NULL, ",");
}
printf("\n");
}
fclose(fp);
return 0;
}
说明:读取 CSV 文件每行内容,并使用 strtok 分割数据。
例 67 — 二进制文件读写
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int id;
float value;
} Data;
int main(void) {
Data d = {1, 3.14f};
FILE *fp = fopen("data.bin", "wb");
if(fp == NULL) {
perror("打开文件失败");
return 1;
}
fwrite(&d, sizeof(Data), 1, fp);
fclose(fp);
Data d2;
fp = fopen("data.bin", "rb");
if(fp == NULL) {
perror("打开文件失败");
return 1;
}
fread(&d2, sizeof(Data), 1, fp);
fclose(fp);
printf("读取二进制数据:id = %d, value = %f\n", d2.id, d2.value);
return 0;
}
说明:示范如何写入和读取二进制数据结构。
例 68 — 文件定位(fseek 和 ftell)
#include <stdio.h>
int main(void) {
FILE *fp = fopen("output.txt", "r");
if(fp == NULL) {
perror("打开文件失败");
return 1;
}
fseek(fp, 0, SEEK_END);
long pos = ftell(fp);
printf("文件大小:%ld 字节\n", pos);
fclose(fp);
return 0;
}
说明:利用 fseek 定位文件尾,并用 ftell 获取文件大小。
例 69 — 文件错误处理示例
#include <stdio.h>
int main(void) {
FILE *fp = fopen("nonexistent.txt", "r");
if(fp == NULL) {
perror("错误");
return 1;
}
fclose(fp);
return 0;
}
说明:演示打开文件失败时的错误处理。
例 70 — 简单日志记录功能(写日志到文件)
#include <stdio.h>
#include <time.h>
int main(void) {
FILE *logfile = fopen("log.txt", "a");
if(logfile == NULL) {
perror("打开日志文件失败");
return 1;
}
time_t now = time(NULL);
fprintf(logfile, "Log entry at %s", ctime(&now));
fclose(logfile);
printf("日志已记录。\n");
return 0;
}
说明:将当前时间戳写入日志文件,作为简单日志记录示例。
位操作与数值运算(例 71 ~ 80)
例 71 — 位操作基本演示(AND, OR, XOR, NOT)
#include <stdio.h>
int main(void) {
unsigned int a = 5, b = 9;
printf("a & b = %u\n", a & b);
printf("a | b = %u\n", a | b);
printf("a ^ b = %u\n", a ^ b);
printf("~a = %u\n", ~a);
return 0;
}
说明:演示常用的位操作符的使用。
例 72 — 使用位操作判断奇偶性
#include <stdio.h>
int main(void) {
int n;
printf("请输入一个整数:");
scanf("%d", &n);
if(n & 1)
printf("%d 是奇数。\n", n);
else
printf("%d 是偶数。\n", n);
return 0;
}
说明:通过 n & 1 判断整数奇偶。
例 73 — 统计整数中1的个数(位计数)
#include <stdio.h>
int countSetBits(unsigned int n) {
int count = 0;
while(n) {
count += n & 1;
n >>= 1;
}
return count;
}
int main(void) {
unsigned int n;
printf("请输入一个非负整数:");
scanf("%u", &n);
printf("二进制中 1 的个数:%d\n", countSetBits(n));
return 0;
}
说明:统计整数二进制表示中 1 的个数。
例 74 — 判断一个数是否是 2 的幂(位运算实现)
#include <stdio.h>
#include <stdbool.h>
bool isPowerOfTwo(unsigned int n) {
return n && !(n & (n - 1));
}
int main(void) {
unsigned int n;
printf("请输入一个整数:");
scanf("%u", &n);
printf("%u %s 2 的幂。\n", n, isPowerOfTwo(n) ? "是" : "不是");
return 0;
}
说明:利用 n & (n - 1) 判断是否为 2 的幂。
例 75 — 位旋转操作(左旋转和右旋转)
#include <stdio.h>
unsigned int rotateLeft(unsigned int n, int d) {
return (n << d) | (n >> (32 - d));
}
unsigned int rotateRight(unsigned int n, int d) {
return (n >> d) | (n << (32 - d));
}
int main(void) {
unsigned int n = 0x12345678;
printf("原数:0x%X\n", n);
printf("左旋 8 位:0x%X\n", rotateLeft(n, 8));
printf("右旋 8 位:0x%X\n", rotateRight(n, 8));
return 0;
}
说明:演示整数的位旋转操作。
例 76 — 反转一个整数的所有位(32位整数)
#include <stdio.h>
unsigned int reverseBits(unsigned int n) {
unsigned int result = 0;
for (int i = 0; i < 32; i++) {
result <<= 1;
result |= (n & 1);
n >>= 1;
}
return result;
}
int main(void) {
unsigned int n = 0xF0F0F0F0;
printf("反转前:0x%X\n", n);
printf("反转后:0x%X\n", reverseBits(n));
return 0;
}
说明:逐位反转一个 32 位整数的二进制表示。
例 77 — 检测系统字节序(大小端)
#include <stdio.h>
#include <stdbool.h>
bool isLittleEndian() {
unsigned int x = 1;
return *((char*)&x) == 1;
}
int main(void) {
printf("系统是 %s 字节序。\n", isLittleEndian() ? "小端" : "大端");
return 0;
}
说明:通过检查低地址字节判断系统字节序。
例 78 — 位掩码提取示例
#include <stdio.h>
int main(void) {
unsigned int number = 0xDEADBEEF;
// 提取中间 8 位:位 16~23
unsigned int mask = 0x00FF0000;
unsigned int extracted = (number & mask) >> 16;
printf("提取的值:0x%X\n", extracted);
return 0;
}
说明:利用位掩码提取指定区域的比特位。
例 79 — 快速幂(使用位运算实现)
#include <stdio.h>
long long fastPow(long long base, long long exp) {
long long result = 1;
while(exp > 0) {
if(exp & 1)
result *= base;
base *= base;
exp >>= 1;
}
return result;
}
int main(void) {
long long base, exp;
printf("请输入底数和指数:");
scanf("%lld %lld", &base, &exp);
printf("结果:%lld\n", fastPow(base, exp));
return 0;
}
说明:采用快速幂算法高效计算大整数幂。
例 80 — 打印整数的二进制表示(位操作实现)
#include <stdio.h>
void printBinary(unsigned int n) {
for (int i = 31; i >= 0; i--) {
printf("%u", (n >> i) & 1);
if(i % 8 == 0)
printf(" ");
}
printf("\n");
}
int main(void) {
unsigned int n;
printf("请输入一个整数:");
scanf("%u", &n);
printBinary(n);
return 0;
}
说明:利用位移和掩码打印 32 位整数的二进制表示,每 8 位分隔一次。
实用算法与综合实例(例 81 ~ 90)
例 81 — 后缀表达式求值(逆波兰表达式)
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define STACK_MAX 100
typedef struct {
int data[STACK_MAX];
int top;
} Stack;
void initStack(Stack *s) {
s->top = -1;
}
int push(Stack *s, int value) {
if(s->top >= STACK_MAX - 1)
return 0;
s->data[++(s->top)] = value;
return 1;
}
int pop(Stack *s, int *value) {
if(s->top < 0)
return 0;
*value = s->data[(s->top)--];
return 1;
}
int evaluatePostfix(const char *expr) {
Stack s;
initStack(&s);
for(int i = 0; expr[i] != '\0'; i++) {
if(isdigit(expr[i])) {
push(&s, expr[i] - '0');
} else if(expr[i] == ' ') {
continue;
} else {
int val2, val1;
pop(&s, &val2);
pop(&s, &val1);
switch(expr[i]) {
case '+': push(&s, val1 + val2); break;
case '-': push(&s, val1 - val2); break;
case '*': push(&s, val1 * val2); break;
case '/': push(&s, val1 / val2); break;
}
}
}
int result;
pop(&s, &result);
return result;
}
int main(void) {
char expr[256];
printf("请输入逆波兰表达式(数字和运算符之间以空格分隔):\n");
fgets(expr, sizeof(expr), stdin);
printf("结果:%d\n", evaluatePostfix(expr));
return 0;
}
说明:使用栈数据结构求解后缀表达式。
例 82 — 中缀表达式转后缀表达式并求值
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define STACK_MAX 100
typedef struct {
char data[STACK_MAX];
int top;
} CharStack;
void initCharStack(CharStack *s) {
s->top = -1;
}
void pushChar(CharStack *s, char c) {
s->data[++(s->top)] = c;
}
char popChar(CharStack *s) {
return s->data[(s->top)--];
}
char peekChar(CharStack *s) {
return s->data[s->top];
}
int precedence(char op) {
if(op == '+' || op == '-')
return 1;
if(op == '*' || op == '/')
return 2;
return 0;
}
void infixToPostfix(const char *infix, char *postfix) {
CharStack s;
initCharStack(&s);
int j = 0;
for (int i = 0; infix[i] != '\0'; i++) {
if(isdigit(infix[i])) {
postfix[j++] = infix[i];
} else if(infix[i] == ' ') {
postfix[j++] = ' ';
} else {
while(s.top != -1 && precedence(peekChar(&s)) >= precedence(infix[i]))
postfix[j++] = popChar(&s);
pushChar(&s, infix[i]);
}
}
while(s.top != -1)
postfix[j++] = popChar(&s);
postfix[j] = '\0';
}
int evaluateExpression(const char *expr) {
// 直接调用前面例81的后缀求值函数
return evaluatePostfix(expr);
}
// 此处复用例81中的 evaluatePostfix() 实现
int main(void) {
char infix[256], postfix[256];
printf("请输入中缀表达式(单字符操作数):\n");
fgets(infix, sizeof(infix), stdin);
infixToPostfix(infix, postfix);
printf("后缀表达式为:%s\n", postfix);
printf("计算结果:%d\n", evaluateExpression(postfix));
return 0;
}
说明:先将中缀表达式转换为后缀表达式,再利用后缀求值方法计算结果。
例 83 — 简易命令行计算器(循环读取输入)
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char line[256];
printf("简单计算器(输入 exit 退出):\n");
while(1) {
printf(">>> ");
if(fgets(line, sizeof(line), stdin) == NULL)
break;
if(strncmp(line, "exit", 4) == 0)
break;
double a, b;
char op;
if(sscanf(line, "%lf %c %lf", &a, &op, &b) == 3) {
switch(op) {
case '+': printf("结果:%lf\n", a + b); break;
case '-': printf("结果:%lf\n", a - b); break;
case '*': printf("结果:%lf\n", a * b); break;
case '/':
if(b != 0)
printf("结果:%lf\n", a / b);
else
printf("错误:除数为0\n");
break;
default: printf("不支持的运算符。\n");
}
} else {
printf("输入格式错误,请重试。\n");
}
}
return 0;
}
说明:通过循环不断读取用户输入,实现持续计算功能。
例 84 — 矩阵乘法
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int m, n, p;
printf("请输入矩阵 A 的行数和列数:");
scanf("%d %d", &m, &n);
printf("请输入矩阵 B 的列数(A 的列数 = B 的行数):");
scanf("%d", &p);
int **A = malloc(m * sizeof(int *));
int **B = malloc(n * sizeof(int *));
int **C = malloc(m * sizeof(int *));
for(int i = 0; i < m; i++) {
A[i] = malloc(n * sizeof(int));
C[i] = calloc(p, sizeof(int));
}
for(int i = 0; i < n; i++)
B[i] = malloc(p * sizeof(int));
printf("请输入矩阵 A:\n");
for(int i = 0; i < m; i++)
for(int j = 0; j < n; j++)
scanf("%d", &A[i][j]);
printf("请输入矩阵 B:\n");
for(int i = 0; i < n; i++)
for(int j = 0; j < p; j++)
scanf("%d", &B[i][j]);
// 计算矩阵乘法:C = A * B
for(int i = 0; i < m; i++)
for(int j = 0; j < p; j++)
for(int k = 0; k < n; k++)
C[i][j] += A[i][k] * B[k][j];
printf("结果矩阵 C:\n");
for(int i = 0; i < m; i++) {
for(int j = 0; j < p; j++)
printf("%d ", C[i][j]);
printf("\n");
}
// 释放内存
for(int i = 0; i < m; i++) { free(A[i]); free(C[i]); }
for(int i = 0; i < n; i++) free(B[i]);
free(A); free(B); free(C);
return 0;
}
说明:动态分配二维数组,并实现矩阵乘法运算。
例 85 — 矩阵快速幂求斐波那契数(2×2 矩阵)
#include <stdio.h>
#include <stdlib.h>
typedef struct {
long long m[2][2];
} Matrix;
Matrix multiply(Matrix a, Matrix b) {
Matrix c = {{{0,0},{0,0}}};
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
for (int k = 0; k < 2; k++)
c.m[i][j] += a.m[i][k] * b.m[k][j];
return c;
}
Matrix matrixPow(Matrix a, int n) {
Matrix result = {{{1,0},{0,1}}};
while(n) {
if(n & 1)
result = multiply(result, a);
a = multiply(a, a);
n >>= 1;
}
return result;
}
int main(void) {
int n;
printf("请输入斐波那契数的项数:");
scanf("%d", &n);
if(n == 0) {
printf("0\n");
return 0;
}
Matrix base = {{{1,1},{1,0}}};
Matrix result = matrixPow(base, n-1);
printf("斐波那契数 F(%d) = %lld\n", n, result.m[0][0]);
return 0;
}
说明:利用矩阵快速幂实现高效计算斐波那契数列。
例 86 — Dijkstra 算法求最短路径(单源最短路径)
#include <stdio.h>
#include <limits.h>
#include <stdbool.h>
#define V 5
int minDistance(int dist[], bool sptSet[]) {
int min = INT_MAX, min_index;
for (int v = 0; v < V; v++)
if (!sptSet[v] && dist[v] <= min) {
min = dist[v];
min_index = v;
}
return min_index;
}
void dijkstra(int graph[V][V], int src) {
int dist[V];
bool sptSet[V] = {false};
for (int i = 0; i < V; i++)
dist[i] = INT_MAX;
dist[src] = 0;
for (int count = 0; count < V - 1; count++) {
int u = minDistance(dist, sptSet);
sptSet[u] = true;
for (int v = 0; v < V; v++)
if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX
&& dist[u] + graph[u][v] < dist[v])
dist[v] = dist[u] + graph[u][v];
}
printf("顶点 距离\n");
for (int i = 0; i < V; i++)
printf("%d \t %d\n", i, dist[i]);
}
int main(void) {
int graph[V][V] = {
{0, 10, 0, 5, 0},
{0, 0, 1, 2, 0},
{0, 0, 0, 0, 4},
{0, 3, 9, 0, 2},
{7, 0, 6, 0, 0}
};
dijkstra(graph, 0);
return 0;
}
说明:使用 Dijkstra 算法计算给定图从源点的最短路径。
例 87 — 拓扑排序(Kahn 算法)
#include <stdio.h>
#include <stdlib.h>
#define MAX_VERTICES 100
typedef struct {
int *data;
int front, rear;
int size;
} Queue;
void initQueue(Queue *q, int size) {
q->data = malloc(size * sizeof(int));
q->front = 0;
q->rear = -1;
q->size = size;
}
int isEmpty(Queue *q) {
return q->rear < q->front;
}
void enqueue(Queue *q, int value) {
q->data[++(q->rear)] = value;
}
int dequeue(Queue *q) {
return q->data[(q->front)++];
}
void topologicalSort(int graph[MAX_VERTICES][MAX_VERTICES], int V, int inDegree[]) {
Queue q;
initQueue(&q, V);
for (int i = 0; i < V; i++)
if(inDegree[i] == 0)
enqueue(&q, i);
printf("拓扑排序结果:");
while(!isEmpty(&q)) {
int u = dequeue(&q);
printf("%d ", u);
for (int v = 0; v < V; v++) {
if(graph[u][v]) {
inDegree[v]--;
if(inDegree[v] == 0)
enqueue(&q, v);
}
}
}
printf("\n");
free(q.data);
}
int main(void) {
int V = 6;
// 邻接矩阵表示有向图
int graph[MAX_VERTICES][MAX_VERTICES] = {0};
// 手动构造图
graph[5][2] = 1; graph[5][0] = 1;
graph[4][0] = 1; graph[4][1] = 1;
graph[2][3] = 1;
graph[3][1] = 1;
int inDegree[MAX_VERTICES] = {0};
for (int i = 0; i < V; i++)
for (int j = 0; j < V; j++)
if(graph[i][j])
inDegree[j]++;
topologicalSort(graph, V, inDegree);
return 0;
}
说明:使用 Kahn 算法实现拓扑排序,适用于有向无环图。
例 88 — “猜数字”游戏
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void) {
int number, guess, attempts = 0;
srand((unsigned)time(NULL));
number = rand() % 100 + 1;
printf("猜数字游戏(1~100):\n");
do {
printf("请输入你的猜测:");
scanf("%d", &guess);
attempts++;
if(guess < number)
printf("太小了!\n");
else if(guess > number)
printf("太大了!\n");
else
printf("恭喜你,猜对了!共猜了 %d 次。\n", attempts);
} while(guess != number);
return 0;
}
说明:实现一个交互式的猜数字小游戏。
例 89 — 简易“石头剪子布”游戏
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void) {
srand((unsigned)time(NULL));
int choice, comp = rand() % 3;
printf("请选择:0-石头,1-剪刀,2-布:");
scanf("%d", &choice);
printf("电脑选择:%s\n", comp==0?"石头":comp==1?"剪刀":"布");
if(choice == comp)
printf("平局!\n");
else if((choice == 0 && comp == 1) || (choice == 1 && comp == 2) || (choice == 2 && comp == 0))
printf("你赢了!\n");
else
printf("你输了!\n");
return 0;
}
说明:模拟“石头剪子布”游戏,随机生成电脑选择。
例 90 — “井字棋”游戏(简易版)
#include <stdio.h>
#include <stdlib.h>
char board[3][3];
void initBoard() {
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
board[i][j] = ' ';
}
void printBoard() {
printf("\n");
for (int i = 0; i < 3; i++) {
printf(" %c | %c | %c ", board[i][0], board[i][1], board[i][2]);
if(i < 2)
printf("\n---|---|---\n");
}
printf("\n");
}
int checkWin() {
for (int i = 0; i < 3; i++) {
if(board[i][0] != ' ' &&
board[i][0] == board[i][1] &&
board[i][1] == board[i][2])
return 1;
if(board[0][i] != ' ' &&
board[0][i] == board[1][i] &&
board[1][i] == board[2][i])
return 1;
}
if(board[0][0] != ' ' &&
board[0][0] == board[1][1] &&
board[1][1] == board[2][2])
return 1;
if(board[0][2] != ' ' &&
board[0][2] == board[1][1] &&
board[1][1] == board[2][0])
return 1;
return 0;
}
int main(void) {
initBoard();
int row, col, moves = 0;
char player = 'X';
while(moves < 9) {
printBoard();
printf("玩家 %c,请输入行和列(0-2):", player);
scanf("%d %d", &row, &col);
if(row < 0 || row >= 3 || col < 0 || col >= 3 || board[row][col] != ' ') {
printf("无效输入,请重试。\n");
continue;
}
board[row][col] = player;
moves++;
if(checkWin()) {
printBoard();
printf("玩家 %c 获胜!\n", player);
return 0;
}
player = (player == 'X') ? 'O' : 'X';
}
printBoard();
printf("平局!\n");
return 0;
}
说明:实现一个简易的 3x3 井字棋游戏。
杂项与拓展练习(例 91 ~ 100)
例 91 — 利用 clock() 实现简单计时器
#include <stdio.h>
#include <time.h>
int main(void) {
clock_t start, end;
start = clock();
// 模拟耗时操作
for(long i = 0; i < 100000000; i++);
end = clock();
double duration = (double)(end - start) / CLOCKS_PER_SEC;
printf("耗时:%f 秒\n", duration);
return 0;
}
说明:使用 clock() 函数测量程序运行时间。
例 92 — 递归生成 Gray Code 序列(打印 n 位 Gray Code)
#include <stdio.h>
#include <math.h>
void generateGray(int n, int num) {
if(n == 0) {
printf("%0*d\n", 1, num);
return;
}
generateGray(n - 1, num);
generateGray(n - 1, num ^ (1 << (n - 1)));
}
int main(void) {
int n;
printf("请输入 Gray Code 位数:");
scanf("%d", &n);
int total = pow(2, n);
for (int i = 0; i < total; i++)
generateGray(n, i);
return 0;
}
说明:递归生成并打印 n 位 Gray Code 序列。
例 93 — 使用 qsort() 对结构体数组排序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int id;
char name[50];
} Person;
int compare(const void *a, const void *b) {
return ((Person*)a)->id - ((Person*)b)->id;
}
int main(void) {
Person people[3] = {{3, "Charlie"}, {1, "Alice"}, {2, "Bob"}};
qsort(people, 3, sizeof(Person), compare);
for (int i = 0; i < 3; i++)
printf("ID: %d, Name: %s\n", people[i].id, people[i].name);
return 0;
}
说明:利用标准库函数 qsort 对结构体数组按 id 进行排序。
例 94 — 使用 bsearch() 实现二分查找(查结构体数组)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int id;
char name[50];
} Person;
int compare(const void *a, const void *b) {
return ((Person*)a)->id - ((Person*)b)->id;
}
int main(void) {
Person people[3] = {{1, "Alice"}, {2, "Bob"}, {3, "Charlie"}};
int key = 2;
Person target = {key, ""};
Person *found = bsearch(&target, people, 3, sizeof(Person), compare);
if(found)
printf("找到: ID = %d, Name = %s\n", found->id, found->name);
else
printf("未找到\n");
return 0;
}
说明:利用 bsearch 在已经排序的结构体数组中查找指定元素。
例 95 — 可变参数函数示例(自定义简单打印函数)
#include <stdio.h>
#include <stdarg.h>
void myPrint(const char *format, ...) {
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
}
int main(void) {
myPrint("输出整型:%d, 浮点:%f, 字符串:%s\n", 10, 3.14, "Hello");
return 0;
}
说明:使用 stdarg.h 实现可变参数函数,模拟 printf 部分功能。
例 96 — 实现自定义字符串分割(使用 strtok)
#include <stdio.h>
#include <string.h>
int main(void) {
char str[256];
printf("请输入一行文本:");
fgets(str, sizeof(str), stdin);
char *token = strtok(str, " ,.-\n");
printf("分割结果:\n");
while(token != NULL) {
printf("%s\n", token);
token = strtok(NULL, " ,.-\n");
}
return 0;
}
说明:利用 strtok() 函数分割字符串,演示字符串处理技巧。
例 97 — 打印系统环境变量(利用 getenv)
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char *path = getenv("PATH");
if(path != NULL)
printf("PATH = %s\n", path);
else
printf("获取 PATH 环境变量失败。\n");
return 0;
}
说明:通过 getenv 获取并打印环境变量。
例 98 — 动态分配二维数组(矩阵)
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int rows, cols;
printf("请输入行数和列数:");
scanf("%d %d", &rows, &cols);
int **matrix = malloc(rows * sizeof(int *));
for (int i = 0; i < rows; i++)
matrix[i] = malloc(cols * sizeof(int));
// 初始化矩阵
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
matrix[i][j] = i * cols + j;
// 输出矩阵
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++)
printf("%d ", matrix[i][j]);
printf("\n");
}
for (int i = 0; i < rows; i++)
free(matrix[i]);
free(matrix);
return 0;
}
说明:演示如何动态分配二维数组并释放内存。
例 99 — 条件编译和宏定义示例
#include <stdio.h>
#define DEBUG 1
int main(void) {
#ifdef DEBUG
printf("调试模式开启\n");
#endif
printf("程序运行中...\n");
return 0;
}
说明:利用条件编译和宏定义控制调试信息输出。
例 100 — 内联函数示例(C99 inline 关键字)
#include <stdio.h>
inline int add(int a, int b) {
return a + b;
}
int main(void) {
int result = add(5, 3);
printf("内联函数计算:%d\n", result);
return 0;
}
说明:展示 inline 函数的基本用法,提示编译器内联扩展。
结语
本文提供了从基础语法、数组字符串操作、各类排序与查找算法、数据结构实现、递归与经典问题、指针与动态内存、文件 I/O 及位运算,再到实用算法和拓展练习的 100 个经典 C 语言例题。
每个例题均给出完整的源码和简要说明,适合初学者练习和进阶者查漏补缺。希望读者能够通过这些实例,深入理解 C 语言的精髓与实际应用。
如果有任何问题或改进建议,欢迎在评论区交流讨论,共同进步!
祝大家编程愉快,码力不断提升!