• 【重拾C语言】五、模块化程序设计——函数(定义、调用、参数传递、结果返回、函数原型;典例:打印字符图形、验证哥德巴赫猜想)


    目录

    前言

    五、模块化程序设计——函数

    5.1 计算三角形的重心

    5.2 函数

    5.2.1 函数定义

    5.2.2 函数调用

    a. 函数调用的形式和过程

    b. 参数传递

    值传递

    指针传递

    c. 函数结果返回

    5.2.3 函数原型(先调用后定义)

    5.3 程序设计实例

    5.3.1 打印字符图形

    5.3.2 哥德巴赫猜想

    5.4  程序调试


            

    前言

            本文介绍了模块化程序设计——函数,其中包括如何定义函数、函数的调用形式和过程、参数传递(值传递和指针传递)、函数结果的返回以及函数原型的使用。具体的程序设计实例有打印字符图形和验证哥德巴赫猜想。

    五、模块化程序设计——函数

            在C语言中,我们可以使用函数实现模块化程序设计,将一些独立功能的部分写成单独的函数,使得程序更加结构化和清晰。

    5.1 计算三角形的重心

            我们可以根据给定的三角形顶点坐标(x1, y1)、(x2, y2)和(x3, y3)来计算三角形的重心。重心G的坐标计算公式如下:

    %203

    %203

            以下是使用C语言实现的函数:

    1. #include
    2. void centroid(float x1, float y1, float x2, float y2, float x3, float y3, float *Gx, float *Gy) {
    3. *Gx = (x1 + x2 + x3) / 3;
    4. *Gy = (y1 + y2 + y3) / 3;
    5. }
    6. int main() {
    7. float x1, y1, x2, y2, x3, y3, Gx, Gy;
    8. scanf("%f%f%f%f%f%f", &x1, &y1, &x2, &y2, &x3, &y3);
    9. centroid(x1, y1, x2, y2, x3, y3, &Gx, &Gy);
    10. printf("Centroid of the triangle is: (%.2f, %.2f)\n", Gx, Gy);
    11. return 0;
    12. }

            (关于指针的使用详见本系列后文)

    5000e8803af74907b15718782e829d1b.png

    5.2 函数

    5.2.1 函数定义

            函数定义包括返回值类型、函数名、参数列表以及函数体。

    1. 类型符 函数名(形式参数表) {
    2. 函数体
    3. }

            其中,返回类型符指定了函数返回的数据类型,可以是基本数据类型(如int、char、float等)或自定义的数据类型。函数名是函数的标识符,用于在程序中调用该函数。参数列表是一组用逗号分隔的参数,可以包含零个或多个参数,每个参数包括参数类型和参数名。函数体是函数的具体实现代码,包括一系列语句和操作。以上面 centroid 函数为例:

            函数的目的是计算一个三角形的质心坐标。它接受6个输入参数,分别是三角形的3个顶点的x和y坐标(x1, y1, x2, y2, x3, y3),以及两个指针变量(float *Gxfloat *Gy),用于存储计算得到的质心的x和y坐标。

            在函数体中,通过将三个顶点的x坐标相加并除以3,将结果存储在*Gx指向的内存位置中,表示质心的x坐标。同样,将三个顶点的y坐标相加并除以3,将结果存储在*Gy指向的内存位置中,表示质心的y坐标。

            请注意,在C语言中,函数的声明和定义可以分开进行,即可以在程序的开头声明函数的原型(函数名、参数列表和返回类型),然后在后面的位置实现函数的定义。这种分离的方式可以提供更好的代码组织和模块化。

    (详见5.2.3 函数原型)

    5.2.2 函数调用

    函数名(实际参数表)

            函数调用是在主函数或其他函数中使用已定义的函数。通过函数名和实际参数列表来调用函数。例如,在 main 函数中,我们调用了 centroid 函数并传入了6个实际参数和2个用于存储结果的指针。

    • 定义一个函数后,就可以在程序中调用这个函数:
      • 标准库函数:在程序的最前面用#include命令包含相应的头文件。
      • 自定义函数:程序中必须有相对应的函数定义。

    a. 函数调用的形式和过程

            在C语言中,函数调用通过函数名和实际参数列表的形式进行。函数调用的一般形式是:

    函数名(参数1, 参数2, ...);

            其中,函数名是要调用的函数的名称,参数是传递给函数的输入值。

    函数调用的过程如下:

    • 程序执行到函数调用的位置时,会跳转到被调用函数的起始位置。
    • 在被调用函数中,执行函数体中的语句,处理传递进来的参数。
    • 如果函数有返回值,计算并返回结果。
    • 执行完函数体中的语句后,返回到函数调用的下一条语句,继续执行。

    b. 参数传递

            在C语言中,函数参数可以通过值传递(传递参数的副本)或指针传递(传递参数的地址)的方式进行传递。

    • 值传递

      • 当使用值传递方式传递参数时,函数内部对参数的修改不会影响到函数外部的变量。即函数内部操作的是参数的副本。
    • 指针传递

      • 当使用指针传递方式传递参数时,函数内部可以通过指针来访问和修改函数外部的变量。通过传递变量的地址,函数可以直接对原始变量进行操作。

    (关于指针相关知识详见后文)

    c. 函数结果返回

    • 函数可以有返回值,也可以没有返回值。函数的返回值通过 return 语句来指定。
    • 函数的返回值可以是任意基本类型(如整数、浮点数等),也可以是指针类型或结构体类型。
    • 在函数中使用 return 语句将结果返回给调用函数。返回值可以直接返回,也可以存储在变量中后再返回。

    例如,以下是一个函数的示例,它计算两个整数的和并返回结果:

    1. int add(int a, int b) {
    2. int sum = a + b;
    3. return sum;
    4. }

    在调用该函数时,可以将返回值赋给一个变量:

    int result = add(3, 5);

            在这个例子中,函数 add 接收两个整数参数 a 和 b,计算它们的和并将结果返回。函数调用 add(3, 5) 的结果为 8,然后将返回值 8 赋给变量 result

    5.2.3 函数原型(先调用后定义)

            函数原型是函数定义的简化形式,用于告诉编译器函数的信息,包括函数的返回值类型、函数名和参数列表(包括参数类型和参数名)。函数原型的目的是在函数调用之前提供函数的声明,让编译器知道函数的存在及其参数和返回值的类型

            在C语言中,函数原型的语法形式为:

    返回值类型 函数名(参数列表);

            例如,对于之前提到的 centroid 函数,可以编写函数原型如下:

    void centroid(float x1, float y1, float x2, float y2, float x3, float y3, float *Gx, float *Gy);

            通过提供函数原型,我们可以在主函数之前声明函数,使得编译器能够正确地解析函数调用,并检查函数调用的参数类型和返回值类型的匹配性。这提高了程序的可读性和可维护性。在本例5.1中,函数原型可以省略,因为我们把 centroid 函数放在 main 函数的前面

            在程序的开头声明函数的原型:

    1. #include
    2. void centroid(float x1, float y1, float x2, float y2, float x3, float y3, float *Gx, float *Gy);
    3. int main() {
    4. float x1, y1, x2, y2, x3, y3, Gx, Gy;
    5. scanf("%f%f%f%f%f%f", &x1, &y1, &x2, &y2, &x3, &y3);
    6. centroid(x1, y1, x2, y2, x3, y3, &Gx, &Gy);
    7. printf("Centroid of the triangle is: (%.2f, %.2f)\n", Gx, Gy);
    8. return 0;
    9. }
    10. void centroid(float x1, float y1, float x2, float y2, float x3, float y3, float *Gx, float *Gy) {
    11. *Gx = (x1 + x2 + x3) / 3;
    12. *Gy = (y1 + y2 + y3) / 3;
    13. }

    5.3 程序设计实例

    5.3.1 打印字符图形

    1. #include
    2. void printCharacterPattern(int n) {
    3. int i, j, space;
    4. // 打印上半部分
    5. for (i = 1; i <= n; i++) {
    6. // 打印空格
    7. for (space = 1; space <= n - i; space++) {
    8. printf(" ");
    9. }
    10. // 打印字母
    11. for (j = 1; j <= (2 * i) - 1; j++) {
    12. printf("%c ", 'A' + i - 1);
    13. }
    14. printf("\n");
    15. }
    16. // 打印下半部分
    17. for (i = n - 1; i >= 1; i--) {
    18. // 打印空格
    19. for (space = 1; space <= n - i; space++) {
    20. printf(" ");
    21. }
    22. // 打印字母
    23. for (j = 1; j <= (2 * i) - 1; j++) {
    24. printf("%c ", 'A' + i - 1);
    25. }
    26. printf("\n");
    27. }
    28. }
    29. int main() {
    30. int n;
    31. printf("Enter the number of lines: ");
    32. scanf("%d", &n);
    33. printf("\n");
    34. printCharacterPattern(n);
    35. return 0;
    36. }

    32473cceb74b44738c89417ae7a099a8.png

    5.3.2 哥德巴赫猜想

            哥德巴赫猜想:任意一个大于2的偶数都可以表示成两个素数之和。我们可以编写一个函数,找到两个素数,使它们的和等于一个给定的偶数。

    1. #include
    2. int isPrime(int number) {
    3. int i;
    4. if (number <= 1) {
    5. return 0;
    6. }
    7. for (i = 2; i <= number / 2; i++) {
    8. if (number % i == 0) {
    9. return 0;
    10. }
    11. }
    12. return 1;
    13. }
    14. void verifyGoldbachConjecture(int n) {
    15. int i, flag = 0;
    16. if (n % 2 != 0 || n <= 2) {
    17. printf("Invalid input! Please enter an even number greater than 2.\n");
    18. return;
    19. }
    20. for (i = 2; i <= n / 2; i++) {
    21. if (isPrime(i) && isPrime(n - i)) {
    22. printf("%d = %d + %d\n", n, i, n - i);
    23. flag = 1;
    24. }
    25. }
    26. if (flag == 0) {
    27. printf("The Goldbach conjecture is not verified for the number %d.\n", n);
    28. }
    29. }
    30. int main() {
    31. int n;
    32. printf("Enter an even number greater than 2: ");
    33. scanf("%d", &n);
    34. verifyGoldbachConjecture(n);
    35. return 0;
    36. }
    • 在上面的代码中,定义了两个函数:isPrimeverifyGoldbachConjecture
      • isPrime函数用于检查一个数是否是素数;
      • verifyGoldbachConjecture函数用于验证哥德巴赫猜想。
        • 首先检查输入是否为一个大于2的偶数,然后通过遍历所有可能的素数对来验证猜想。如果找到满足猜想的素数对,则打印出相应的表示;如果找不到满足猜想的素数对,则输出相应的提示信息。

    32bd39e552134a9cbf772e35d6eba00a.png

    5.4  程序调试

    ChatGPT:

            程序调试是指对程序进行测试和排除错误的过程。在程序开发过程中,经常会出现各种错误,比如语法错误、逻辑错误、运行时错误等。调试的目标是找出程序中存在的错误并修复它们,确保程序能够按照预期的方式运行。

    下面是一些常见的程序调试技术和方法:

    1. 打印调试信息:通过在关键位置插入打印语句,输出变量的值或程序执行到达的位置,以便观察程序的执行过程和状态,从而找出问题所在。

    2. 使用调试器:调试器是一种工具,可以用来逐步执行程序、观察变量的值、检查内存和寄存器的状态,以及跟踪程序的执行流程。通过调试器,可以更深入地分析程序的运行情况和定位错误。

    3. 单元测试:编写针对程序中单个函数或模块的测试用例,验证其是否按照预期工作。通过逐个测试函数,可以逐步排查错误并验证程序的正确性。

    4. 边界值测试:针对程序处理数据的边界情况进行测试,包括最大值、最小值、边界条件等。边界值测试可以揭示一些潜在的问题,如数组越界、整数溢出等。

    5. 追踪错误:对于运行时错误,可以使用追踪技术来定位错误发生的位置。可以通过观察错误信息、栈跟踪和日志等来追踪错误的来源,进而修复问题。

    6. 代码审查:请同事或其他开发人员对代码进行审查,有时候他们能够发现你忽略的问题或提出改进的建议。

            在进行程序调试时,建议采用自底向上的方法,逐步调试和测试程序的不同部分,确保每个部分的正确性,最后再整体进行测试。

  • 相关阅读:
    Linux磁盘分区快速上手(讲解详细)
    26装饰器3(在面向对象的过程中使用装饰器)
    【SpringCloud微服务项目学习-mall4cloud项目(1)】——环境部署,构建与运行
    Blazor前后端框架Known-V1.2.2
    公钥密码学Public-Key Cryptography
    如何做好迭代回顾4/4
    crossover23.6闪亮登场发布啦,2023最新功能解析
    用R语言模拟混合制排队随机服务排队系统
    SqlServer如何将mdf、ldf文件导入数据库—两种解决方法
    【二叉树】层数最深叶子节点的和
  • 原文地址:https://blog.csdn.net/m0_63834988/article/details/133580009