CAPL 编程系列教程 - 第十五期:函数的定义与调用 (基础)

 CAPL 编程系列教程的第十五期内容,开始讲解 CAPL 中的一个核心概念:函数的定义与调用 (Function Definition and Call)

CAPL 编程系列教程 - 第十五期:函数的定义与调用 (基础)

一、 课程回顾与本期目标

  • 回顾: 前面学习了 CAPL 的基础语法,包括数据类型、变量、运算符、分支结构和循环结构。
  • 本期目标: 学习如何在 CAPL 中定义自己的函数以及如何调用这些函数。
  • 核心概念:
    • 函数 (Function): 本质上是为了完成一个特定功能 (Function) 而组织起来的一段代码块。
    • 目的:
      • 提高代码重用性: 将常用或特定的功能封装起来,避免重复编写代码。
      • 模块化: 将大型程序分解为多个功能独立的模块(函数),使代码结构更清晰,易于管理和维护。
  • 与 C/C++ 的关系: CAPL 的函数定义与 C 语言几乎完全一致,但也借鉴了 C++ 的一些特性(如重载,本期未详述)。

二、 函数的定义 (Defining a Function)

  1. 基本语法:
    Code snippet
    <return_type> FunctionName(<parameter_list>) {
        // Function body (statements implementing the function's logic)
        // [return return_value;] // Optional return statement
    }
    
  • 定义位置: 函数定义必须在事件处理代码块(如 on key)之外,通常与其他函数定义或全局变量定义放在同一层级。
  • 组成部分:
    • return_type (返回值类型):
      • 指定函数执行完毕后返回给调用者的数据的类型(如 int, float, char, struct Point 等)。
      • void: 如果函数不返回任何值,则使用关键字 void 作为返回值类型。
      • CAPL 特点: 如果函数不返回任何值,void 关键字可以省略 。如果在 CAPL 代码中看到函数名前面没有类型,就等同于 void
    • FunctionName (函数名):
      • 自定义的函数的名称,用于后续调用。
      • 必须符合 CAPL 的标识符命名规则。
    • parameter_list (形式参数列表 / 形参):
      • 放在函数名后的小括号 ()小括号必须存在
      • 用于接收调用者传递给函数的数据。
      • 列表包含零个或多个参数声明,多个参数用逗号 , 分隔。
      • 每个参数声明格式为 DataType ParameterName (如 float a, int b)。
      • 形参 (Formal Parameter): 定义函数时声明的参数,它们是函数内部使用的局部变量,起到占位作用,等待调用时接收实际值。
      • 无参数: 如果函数不需要接收任何数据,参数列表为空,但小括号 () 仍需保留(如 MyFunction())。
    • { Function body } (函数体):
      • 花括号 {} 内的代码块,包含实现函数具体功能的语句。
      • 函数体可以包含变量定义、运算、流程控制、调用其他函数等。
      • 局部变量: 在函数体内定义的变量是局部变量,仅在该函数内部有效。定义规则同事件处理块,必须在代码块开头声明。推荐声明和赋值分开。
    • return 语句:
      • 功能: 用于结束函数的执行,并可选择性地将一个值返回给调用者。
      • 带返回值: return expression; 计算 expression 的值,并将其作为函数的返回值。返回值的类型必须与函数定义时声明的 return_type 兼容。
      • 不带返回值: return; (或省略 return 语句) 用于结束 void 函数的执行。
      • 非必须: 如果函数声明为 void,可以省略 return 语句,函数会在执行完最后一条语句后自动结束。如果声明了非 void 返回类型,则通常必须return 语句返回一个兼容类型的值。

三、 函数的调用 (Calling a Function)

  1. 基本语法: FunctionName(<argument_list>);
  • 调用位置: 可以在事件处理代码块(如 on key)、其他函数体内部,或者 CAPL 的特定执行上下文中调用函数。
  • 方式: 使用函数名加上小括号 () 来调用。
  • argument_list (实际参数列表 / 实参):
    • 放在调用时的小括号 () 内,提供给函数的值。
    • 实参的数量、类型和顺序必须与函数定义时的形参列表匹配
    • 实参可以是常量、变量或表达式。
  • 执行流程:
    • 当程序执行到函数调用语句时,会将实参的值按顺序传递(赋值)给函数定义中的形参
    • 程序的控制权转移到被调用函数的函数体第一条语句开始执行。
    • 函数体执行完毕(遇到 return 或执行到末尾)。
    • 如果函数有返回值,return 语句会将返回值传递回调用点,函数调用表达式本身的值就是这个返回值。
    • 程序的控制权返回到调用语句之后的位置继续执行。
  • 使用返回值:
    • 可以将函数调用的结果赋值给一个变量:float r = power(2.5, 3);
    • 可以直接在表达式中使用函数调用的结果:write("结果是 %d", power(4, 4)); (如果需要类型转换,如 (int)power(4, 4))。

四、 示例:求 A 的 B 次方 (power 函数)

Code snippet
// --- 函数定义 ---
float power(float a, int b) // 返回 float, 接收 float a 和 int b
{
  float p; // 局部变量:用于存储乘积
  int i;   // 局部变量:循环计数

  p = 1; // 初始化乘积为 1

  // 使用 for 循环计算 a 的 b 次方
  for (i = 0; i < b; i++) {
    p *= a; // 等价于 p = p * a;
  }

  return p; // 返回计算结果
}

// --- 事件处理块 (调用函数) ---
on key 'a'
{
  float r; // 用于接收返回值的局部变量

  // 调用函数并将返回值赋给 r
  r = power(2.5, 3); // 计算 2.5 的 3 次方
  write("2.5 的 3 次方为: %.4f", r); // 输出结果

  // 直接在 write 函数中调用 power 函数
  write("4 的 4 次方为: %d", (int)power(4, 4)); // 计算 4 的 4 次方,并将 float 结果转为 int 输出
}

五、 总结与后续

  • 本期学习了 CAPL 中函数定义和调用的基本语法和概念,这是实现代码复用和模块化的基础。
  • 理解了形参和实参的区别,以及返回值的概念和 return 语句的用法。
  • 下一期将继续深入讲解函数的其他方面。