c语言必背18个经典程序

99ANYc3cd6
预计阅读时长 50 分钟
位置: 首页 C语言 正文

每个程序都包含 题目描述、核心思路、代码示例知识点总结

c语言必背18个经典程序
(图片来源网络,侵删)

第一部分:基础语法与流程控制

"Hello, World!" 程序描述**:编写一个程序,在屏幕上打印 "Hello, World!"。

核心思路:这是所有编程语言的第一个程序,目的是让你成功搭建并运行一个C语言环境,使用 printf 函数进行标准输出。

#include <stdio.h>
int main() {
    printf("Hello, World!\n");
    return 0;
}

知识点总结

  • #include <stdio.h>:包含标准输入输出库,以便使用 printf 函数。
  • int main():C程序的入口函数。
  • printf():格式化输出函数。
  • \n:换行符。
  • return 0;:表示程序正常结束。

两数交换描述**:交换两个变量的值。

核心思路:不能直接交换,需要一个临时变量作为“中转站”,这是最基本、最安全的交换方法。

#include <stdio.h>
int main() {
    int a = 10, b = 20, temp;
    printf("交换前: a = %d, b = %d\n", a, b);
    temp = a; // 1. 将a的值存入temp
    a = b;    // 2. 将b的值赋给a
    b = temp; // 3. 将temp的值(原a的值)赋给b
    printf("交换后: a = %d, b = %d\n", a, b);
    return 0;
}

知识点总结

  • 变量声明与赋值。
  • 使用临时变量进行数据交换。
  • printf 的格式化输出。

判断奇偶数描述**:输入一个整数,判断它是奇数还是偶数。

核心思路:利用取模运算 ,一个数如果能被2整除(即 num % 2 == 0),就是偶数,否则是奇数。

#include <stdio.h>
int main() {
    int num;
    printf("请输入一个整数: ");
    scanf("%d", &num);
    if (num % 2 == 0) {
        printf("%d 是偶数,\n", num);
    } else {
        printf("%d 是奇数,\n", num);
    }
    return 0;
}

知识点总结

  • scanf 函数用于从键盘读取输入。
  • (取模/求余)运算符。
  • if-else 条件判断语句。

判断闰年描述**:输入一个年份,判断是否是闰年。

核心思路:闰年的判断规则:

  1. 能被4整除,但不能被100整除,或者
  2. 能被400整除。
    #include <stdio.h>

int main() { int year; printf("请输入一个年份: "); scanf("%d", &year);

if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
    printf("%d 是闰年,\n", year);
} else {
    printf("%d 不是闰年,\n", year);
}
return 0;
**知识点总结**:
*   复杂的 `if-else` 条件判断。
*   逻辑运算符 `&&` (与)、`||` (或)、`!` (非)。
---
### 第二部分:循环结构
#### 5. 乘法口诀表描述**:在屏幕上打印出9x9的乘法口诀表。
**核心思路**:使用双重循环(嵌套循环),外层循环控制行(1到9),内层循环控制列(1到当前行数)。
```c
#include <stdio.h>
int main() {
    for (int i = 1; i <= 9; i++) { // 外层循环,控制行
        for (int j = 1; j <= i; j++) { // 内层循环,控制列
            printf("%d*%d=%-2d ", j, i, i * j); // %-2d 用于对齐
        }
        printf("\n"); // 每行结束后换行
    }
    return 0;
}

知识点总结

  • for 循环和嵌套循环。
  • printf 的格式化输出,%-2d 表示左对齐,占2个字符宽度。

求最大公约数描述**:输入两个正整数,求它们的最大公约数。

核心思路:使用 辗转相除法(欧几里得算法),用较大数除以较小数,将余数作为新的除数,原来的除数作为新的被除数,直到余数为0,此时的除数就是最大公约数。

#include <stdio.h>
int main() {
    int a, b, temp;
    printf("请输入两个正整数: ");
    scanf("%d %d", &a, &b);
    // 确保a是较大的数
    if (a < b) {
        temp = a;
        a = b;
        b = temp;
    }
    while (b != 0) { // 辗转相除
        temp = a % b;
        a = b;
        b = temp;
    }
    printf("最大公约数是: %d\n", a);
    return 0;
}

知识点总结

  • while 循环。
  • 辗转相除法算法。
  • 变量交换技巧。

求最小公倍数描述**:输入两个正整数,求它们的最小公倍数。

核心思路:利用公式:最小公倍数 = 两数之积 / 最大公约数,所以可以先求出GCD,再计算LCM。

#include <stdio.h>
int main() {
    int a, b, gcd, lcm, temp;
    printf("请输入两个正整数: ");
    scanf("%d %d", &a, &b);
    int original_a = a, original_b = b; // 保存原始值用于计算LCM
    // 求GCD
    if (a < b) {
        temp = a;
        a = b;
        b = temp;
    }
    while (b != 0) {
        temp = a % b;
        a = b;
        b = temp;
    }
    gcd = a;
    // 求LCM
    lcm = (original_a * original_b) / gcd;
    printf("最大公约数是: %d\n", gcd);
    printf("最小公倍数是: %d\n", lcm);
    return 0;
}

知识点总结

  • GCD和LCM的关系。
  • 算法的组合使用。

水仙花数描述**:找出所有3位的水仙花数,水仙花数是指一个3位数,其各位数字立方和等于它本身。

核心思路:遍历所有的3位数(100-999),对每个数,分离出其百位、十位和个位,然后计算立方和并判断是否等于原数。

#include <stdio.h>
#include <math.h> // 使用pow函数需要此头文件
int main() {
    int i, a, b, c;
    printf("3位的水仙花数有:\n");
    for (i = 100; i < 1000; i++) {
        a = i / 100;       // 百位
        b = (i / 10) % 10; // 十位
        c = i % 10;        // 个位
        if (i == pow(a, 3) + pow(b, 3) + pow(c, 3)) {
            printf("%d\n", i);
        }
    }
    return 0;
}

知识点总结

  • for 循环遍历。
  • 利用整数除法和取模运算分离数字的各位。
  • math.h 库中的 pow() 函数(或自己写 a*a*a)。

第三部分:数组与字符串

数组元素求和与平均值描述**:定义一个整型数组,计算数组中所有元素的和及平均值。

核心思路:遍历数组,用一个累加器变量把所有元素加起来,最后用总和除以元素个数得到平均值。

#include <stdio.h>
int main() {
    int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int sum = 0;
    double average;
    int n = sizeof(arr) / sizeof(arr[0]); // 计算数组元素个数
    for (int i = 0; i < n; i++) {
        sum += arr[i];
    }
    average = (double)sum / n; // 注意类型转换
    printf("数组元素的和为: %d\n", sum);
    printf("数组元素的平均值为: %.2f\n", average);
    return 0;
}

知识点总结

  • 数组的定义和初始化。
  • sizeof 操作符计算数组大小和元素个数。
  • for 循环遍历数组。
  • 数据类型转换 (double),避免整数除法。

数组元素查找(线性查找)描述**:在数组中查找一个指定的数,如果找到则输出其位置,否则输出“未找到”。

核心思路:线性查找,从数组的第一个元素开始,依次与目标值比较,直到找到或遍历完整个数组。

#include <stdio.h>
int main() {
    int arr[] = {15, 2, 7, 9, 12, 5};
    int n = sizeof(arr) / sizeof(arr[0]);
    int target, found = 0; // found作为标志位
    printf("请输入要查找的数: ");
    scanf("%d", &target);
    for (int i = 0; i < n; i++) {
        if (arr[i] == target) {
            printf("找到了!数字 %d 在数组的第 %d 个位置,\n", target, i + 1);
            found = 1;
            break; // 找到后立即退出循环
        }
    }
    if (!found) {
        printf("未找到数字 %d,\n", target);
    }
    return 0;
}

知识点总结

  • 数组的遍历和比较。
  • break 语句的使用。
  • 使用标志位(found)来控制流程。

数组排序(冒泡排序)描述**:使用冒泡排序算法对数组进行升序排序。

核心思路:重复地遍历数组,比较相邻的两个元素,如果它们的顺序错误(前一个比后一个大)就交换它们,这个过程就像气泡一样,大的数会“浮”到数组的末端。

#include <stdio.h>
void bubbleSort(int arr[], int n) {
    for (int i = 0; i < n - 1; i++) { // 外层循环控制排序轮数
        for (int j = 0; j < n - 1 - i; j++) { // 内层循环进行相邻比较
            if (arr[j] > arr[j + 1]) {
                // 交换
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}
int main() {
    int arr[] = {64, 34, 25, 12, 22, 11, 90};
    int n = sizeof(arr) / sizeof(arr[0]);
    printf("排序前的数组: ");
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
    bubbleSort(arr, n);
    printf("排序后的数组: ");
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
    return 0;
}

知识点总结

  • 冒泡排序算法的实现。
  • 双重嵌套循环。
  • 函数的定义与调用,传递数组作为参数。
  • 代码模块化思想。

字符串反转描述**:输入一个字符串,将其反转后输出。

核心思路:使用两个指针,一个指向字符串开头,一个指向结尾,交换两个指针所指的字符,然后让两个指针分别向中间移动,直到它们相遇或交错。

#include <stdio.h>
#include <string.h> // 使用strlen需要此头文件
void reverseString(char str[]) {
    int length = strlen(str);
    int i, j;
    char temp;
    for (i = 0, j = length - 1; i < j; i++, j--) {
        temp = str[i];
        str[i] = str[j];
        str[j] = temp;
    }
}
int main() {
    char str[100];
    printf("请输入一个字符串: ");
    fgets(str, sizeof(str), stdin); // 安全地读取一行,包括空格
    // 去掉fgets可能读取的换行符
    str[strcspn(str, "\n")] = 0;
    reverseString(str);
    printf("反转后的字符串: %s\n", str);
    return 0;
}

知识点总结

  • 字符数组和字符串处理。
  • strlen() 函数求字符串长度。
  • fgets()scanf("%s") 的区别(fgets更安全,能读取空格)。
  • 双指针算法在字符串处理中的应用。

第四部分:函数与递归

判断素数(质数)描述**:编写一个函数,判断一个数是否为素数。

核心思路:素数是指只能被1和它本身整除的大于1的自然数,一个简单的优化是,只需判断从2到 sqrt(num) 之间是否有能整除 num 的数即可。

#include <stdio.h>
#include <math.h> // 使用sqrt函数
// 函数声明
int isPrime(int num);
int main() {
    int num;
    printf("请输入一个正整数: ");
    scanf("%d", &num);
    if (isPrime(num)) {
        printf("%d 是素数,\n", num);
    } else {
        printf("%d 不是素数,\n", num);
    }
    return 0;
}
// 函数定义
int isPrime(int num) {
    if (num <= 1) {
        return 0; // 1及以下的数不是素数
    }
    for (int i = 2; i <= sqrt(num); i++) {
        if (num % i == 0) {
            return 0; // 如果能被整除,则不是素数
        }
    }
    return 1; // 是素数
}

知识点总结

  • 函数的定义、声明和调用。
  • 素数的数学定义和优化算法。
  • math.h 库中的 sqrt() 函数。
  • 函数返回值(0代表假,1代表真)。

斐波那契数列描述**:打印斐波那契数列的前n项,斐波那契数列:1, 1, 2, 3, 5, 8, 13...

核心思路:有两种经典方法:

  1. 迭代法(循环):从第3项开始,每一项都是前两项之和,效率高。
  2. 递归法F(n) = F(n-1) + F(n-2),代码简洁,但效率低,有大量重复计算。 这里展示两种方法。
    // 方法一:迭代法(推荐)
    void fibonacci_iterative(int n) {
    int t1 = 1, t2 = 1, nextTerm;
    printf("斐波那契数列前 %d 项 (迭代法): \n", n);
    for (int i = 1; i <= n; ++i) {
        printf("%d ", t1);
        nextTerm = t1 + t2;
        t1 = t2;
        t2 = nextTerm;
    }
    printf("\n");
    }

// 方法二:递归法 int fibonacci_recursive(int n) { if (n <= 1) { return n; } else { return fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2); } }

int main() { int n; printf("请输入要打印的项数: "); scanf("%d", &n);

// 调用迭代法
fibonacci_iterative(n);
// 调用递归法(打印前n项)
printf("斐波那契数列前 %d 项 (递归法): \n", n);
for (int i = 0; i < n; i++) {
    printf("%d ", fibonacci_recursive(i));
}
printf("\n");
return 0;
**知识点总结**:
*   迭代算法(循环)。
*   **递归算法**:函数调用自身。
*   递归的边界条件和递推关系。
*   理解递归的效率问题。
---
### 第五部分:指针与内存管理
#### 15. 使用指针实现数组排序描述**:使用指针变量来访问和交换数组元素,实现冒泡排序。
**核心思路**:与普通数组版本类似,但所有对数组的访问都通过指针来完成,这能让你更深刻地理解指针和数组的关系。
```c
#include <stdio.h>
void bubbleSortWithPointer(int *arr, int n) {
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - 1 - i; j++) {
            // 使用指针比较和交换
            if (*(arr + j) > *(arr + j + 1)) {
                int temp = *(arr + j);
                *(arr + j) = *(arr + j + 1);
                *(arr + j + 1) = temp;
            }
        }
    }
}
int main() {
    int arr[] = {64, 34, 25, 12, 22, 11, 90};
    int n = sizeof(arr) / sizeof(arr[0]);
    printf("排序前的数组: ");
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
    bubbleSortWithPointer(arr, n); // 传递数组名(即首元素地址)
    printf("排序后的数组: ");
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
    return 0;
}

知识点总结

  • 指针与数组的关系:arr[i] 等价于 *(arr + i)
  • 通过指针操作数组元素。
  • 指针作为函数参数。

动态内存分配描述**:在程序运行时,根据用户输入的大小动态地创建一个数组,并对其进行操作,最后释放内存。

核心思路:使用 malloc (memory allocate) 函数在堆上申请内存空间,使用完毕后,必须用 free 函数释放,否则会造成内存泄漏。

#include <stdio.h>
#include <stdlib.h> // 使用malloc和free需要此头文件
int main() {
    int n;
    int *arr; // 声明一个指针变量
    printf("请输入数组的大小: ");
    scanf("%d", &n);
    // 动态分配内存
    arr = (int *)malloc(n * sizeof(int));
    if (arr == NULL) { // 检查内存是否分配成功
        printf("内存分配失败!\n");
        return 1;
    }
    // 使用数组
    printf("请输入 %d 个整数:\n", 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);
    arr = NULL; // 好习惯,防止悬垂指针
    printf("内存已释放,\n");
    return 0;
}

知识点总结

  • malloc 函数:在堆上动态分配内存。
  • free 函数:释放动态分配的内存。
  • 内存泄漏的概念及其危害。
  • 指针在动态内存管理中的核心作用。

第六部分:结构体与文件操作

结构体数组与排序描述**:定义一个包含学生姓名和成绩的结构体,创建一个结构体数组,并按成绩从高到低排序。

核心思路:定义 struct,创建结构体数组,在排序时,比较的是结构体成员(成绩),交换的是整个结构体。

#include <stdio.h>
#include <string.h>
// 定义学生结构体
struct Student {
    char name[50];
    float score;
};
// 按成绩降序排序的函数
void sortStudents(struct Student students[], int n) {
    struct Student temp;
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - 1 - i; j++) {
            if (students[j].score < students[j + 1].score) {
                // 交换整个结构体
                temp = students[j];
                students[j] = students[j + 1];
                students[j + 1] = temp;
            }
        }
    }
}
int main() {
    struct Student students[3] = {
        {"张三", 85.5},
        {"李四", 92.0},
        {"王五", 78.5}
    };
    int n = sizeof(students) / sizeof(students[0]);
    printf("排序前的学生信息:\n");
    for (int i = 0; i < n; i++) {
        printf("姓名: %s, 成绩: %.1f\n", students[i].name, students[i].score);
    }
    sortStudents(students, n);
    printf("\n按成绩排序后的学生信息:\n");
    for (int i = 0; i < n; i++) {
        printf("姓名: %s, 成绩: %.1f\n", students[i].name, students[i].score);
    }
    return 0;
}

知识点总结

  • struct 的定义和使用。
  • 结构体数组的创建和初始化。
  • 结构体成员的访问( 操作符)。
  • 结构体变量的赋值和交换。

文件的读写描述**:将一组数据写入一个文本文件,然后再从该文件中读取并显示出来。

核心思路

  1. 写入文件:使用 fopen 以写模式("w")打开文件,fprintf 写入数据,fclose 关闭文件。
  2. 读取文件:使用 fopen 以读模式("r")打开文件,fscanf 读取数据,fclose 关闭文件。
    #include <stdio.h>

int main() { // --- 写入文件 --- FILE *writeFile; writeFile = fopen("data.txt", "w"); // "w" 表示写模式,如果文件不存在则创建 if (writeFile == NULL) { printf("无法打开文件进行写入!\n"); return 1; } fprintf(writeFile, "Hello, File!\n"); fprintf(writeFile, "这是一个测试文件,\n"); fprintf(writeFile, "数字: %d\n", 12345); fclose(writeFile); printf("数据已成功写入 data.txt 文件,\n");

// --- 读取文件 ---
FILE *readFile;
char buffer[100];
int number;
readFile = fopen("data.txt", "r"); // "r" 表示读模式
if (readFile == NULL) {
    printf("无法打开文件进行读取!\n");
    return 1;
}
printf("\n--- 从文件读取的数据 ---\n");
while (fgets(buffer, sizeof(buffer), readFile) != NULL) { // 逐行读取
    printf("%s", buffer);
}
// 也可以使用 fscanf 读取特定格式
// rewind(readFile); // 将文件指针重置到开头
// fscanf(readFile, "数字: %d", &number);
// printf("读取到的数字是: %d\n", number);
fclose(readFile);
printf("\n文件读取完毕,\n");
return 0;

**知识点总结**:
*   `FILE` 指针的概念。
*   `fopen`, `fclose`, `fprintf`, `fscanf`, `fgets` 等文件操作函数。
*   文件打开模式(`"r"`, `"w"`, `"a"` 等)。
*   文件操作的错误检查。
---
### 总结与建议
这18个程序是C语言学习的基石,当你能独立、熟练地写出并理解它们时,说明你已经掌握了C语言的核心知识。
**学习建议**:
1.  **亲手敲**:不要只看,一定要亲手在编译器里敲出来,运行并观察结果。
2.  **多思考**:理解每个程序背后的逻辑和算法,而不仅仅是记住代码。
3.  **勤修改**:尝试修改这些程序,比如改变输入、调整算法、增加功能,看看会发生什么。
4.  **重实践**:在理解的基础上,尝试自己不看答案,独立完成这些程序。
祝你学习顺利!
-- 展开阅读全文 --
头像
dede ispart
« 上一篇 今天
织梦前台首页重新布局
下一篇 » 今天

相关文章

取消
微信二维码
支付宝二维码

目录[+]