C 编程中的函数示例:递归和内联

⚡ 智能摘要

在 C 语言编程中,函数是可重用的代码块,它将大型程序拆分成更小的子程序,从而更容易理解、测试和修改。每个函数都包含声明、定义和调用三个部分。

  • 🧩 函数的功能是什么: 函数将可重用的指令分组,从而将大型程序分解成更小、更易于管理的子程序,这些子程序也更容易调试。
  • 📚 两种类型: printf 和 scanf 等库函数是现成的,而用户自定义函数是由程序员编写的。
  • 📝 三个部分: 使用函数涉及函数的声明或原型、函数的定义或函数体以及运行该函数的调用。
  • 🎯 参数: 值按位置传递,默认情况下按值传递,因此原始变量在被调用函数内部保持不变。
  • 🌐 范围: 局部变量只存在于其函数内部,而全局变量和静态变量则在整个程序中或函数调用之间保持其值不变。
  • 🤖 人工智能辅助: GitHub Copilot 和 AI 助手可以生成 C 函数脚手架,建议返回类型,并标记缺失的返回值或不匹配的参数。

C 编程中的函数

C 中的函数是什么?

C 编程中的函数 函数是可重用的代码块,它使程序更易于理解和测试,并且无需更改调用程序即可轻松修改。函数将代码分割并模块化,从而获得更好、更高效的结果。简而言之,一个大型程序被分割成多个子程序,这些子程序以函数的形式被调用。

C 中的函数是什么

当你将一个大型程序划分为多个函数时,单独管理每个函数就变得很容易了。每当程序中出现错误时,你都可以轻松调查有问题的函数并只纠正那些错误。你可以在需要时轻松调用和使用函数,这会自动节省时间和空间。

库与用户定义函数

每个“C”程序至少有一个函数,即主函数,但程序可以有任意数量的函数。C 中的 main() 函数是程序的起点。

在“C”编程中,函数分为两种类型:

  1. 库函数
  2. 用户定义函数

C 语言中的库函数和用户定义函数之间的区别在于,我们不需要为库函数编写代码。它已经存在于头文件中,我们总是在程序的开头包含头文件。您只需键入函数的名称并将其与正确的语法一起使用即可。Printf、scanf 是库函数的示例。

而用户定义函数是一种函数类型,我们必须编写一个函数主体,并在需要该函数在程序中执行某些操作时调用该函数。

C 中的用户定义函数始终由用户编写,但后来它可以成为“C”库的一部分。这是“C”编程的一大优势。

C 编程功能分为三个活动,例如,

  1. 功能声明
  2. 功能定义
  3. 函数调用

功能声明

函数声明是指为程序编写一个名称。它是代码中使用函数的必要步骤。在函数声明中,我们只需指定要在程序中使用的函数的名称,就像声明变量一样。除非在程序中声明,否则我们无法使用函数。函数声明也称为“函数原型”。

函数声明(称为原型)通常在 main() 函数上方进行,并采用一般形式:

return_data_type function_name (data_type arguments);
  • return_data_type: 是返回给调用语句的值函数的数据类型。
  • 函数名后面跟着括号
  • 参数名称及其数据类型声明可以选择性地放在括号内。

我们考虑以下程序,该程序展示了如何声明立方函数来计算整数变量的立方值

#include <stdio.h>
/*Function declaration*/
int add(int a,b);
/*End of Function declaration*/
int main() {

请记住,函数不一定返回值。在这种情况下,使用关键字 void。

例如,output_message函数声明表明该函数不返回值:void output_message();

功能定义

函数定义意味着只编写函数主体。函数主体由执行特定任务的语句组成。函数主体由单个语句或语句块组成。它也是函数的必需部分。

int add(int a,int b)	//function body	
{
	int c;
	c=a+b;
	return c;
}

函数调用

函数调用是指在程序需要时调用函数。每当我们调用一个函数时,它都会执行其设计的操作。函数调用是程序的可选部分。

  result = add(4,5);

以下是完整的代码:

#include <stdio.h>
int add(int a, int b);	//function declaration
int main()
{
	int a=10,b=20;
	int c=add(10,20); 	//function call
	printf("Addition:%d\n",c);
	getch();
}
int add(int a,int b)	//function body
{
	int c;
	c=a+b;
	return c;
}

输出:

Addition:30

功能参数

函数的参数用于接收函数调用所需的值。它们按位置匹配;第一个参数传递给第一个参数,第二个参数传递给第二个参数,依此类推。

默认情况下,参数按值传递,即将数据的副本传递给被调用函数。实际传递的变量不会改变。

我们考虑以下程序,它演示了按值传递的参数:

int add (int x, int y); 
int main() {
  int a, b, result;
  a = 5;
  b = 10;
  result = add(a, b);
  printf("%d + %d\ = %d\n", a, b, result);
return 0;}
int add (int x, int y) { 
x += y;
  return(x);}

程序输出为:

5 + 10 = 15

请记住,传递给 add 函数的 a 和 b 的值不会改变,因为只有它的值被传递给了参数 x。

变量范围

变量作用域是指变量在程序代码内的可见性。

在 C 语言中,函数内部声明的变量是该代码块的局部变量,不能在函数外部引用。然而,在所有函数外部声明的变量是全局变量,可以从整个程序访问。在程序顶部使用 `#define` 声明的常量也可以从整个程序访问。我们考虑以下程序,该程序在主函数和用户自定义函数中都打印了全局变量的值:

#include <stdio.h>
int global = 1348;
void test();
int main() {
  printf("from the main function : global =%d \n", global);
  test () ;
return 0;}

void test (){
printf("from user defined function : global =%d \n", global);}

结果:

from the main function : global =1348
from user defined function : global =1348

我们讨论项目细节:

变量范围

  1. 我们声明一个整数全局变量,以 1348 作为初始值。
  2. 我们声明并定义一个 test() 函数,它既不接受参数也不返回值。此函数仅打印全局变量值,以证明全局变量可以在程序的任何地方访问。
  3. 我们在主函数中打印全局变量。
  4. 我们调用测试函数来打印全局变量值。

在 C 语言中,当参数传递给函数形参时,该形参将作为局部变量,在退出函数时将被销毁。

当您使用 全局变量,请谨慎使用它们,因为它们可能会导致错误,并且它们可能会在程序的任何地方发生变化。使用前应对其进行初始化。

静态变量

静态变量具有局部作用域。但是,它们在退出函数时不会被销毁。因此,静态变量会永久保留其值,并且可以在重新进入函数时访问。静态变量在声明时初始化,需要前缀 static。

以下程序使用静态变量:

#include <stdio.h>
void say_hi();
int main() {    
  int i;
  for (i = 0; i < 5; i++) { say_hi();}
   return 0;}
void say_hi() {
  static int calls_number = 1;
  printf("Hi number %d\n", calls_number);
  calls_number ++; }

程序显示:

Hi number 1
Hi number 2
Hi number 3
Hi number 4
Hi number 5

递归函数

考虑一个数的阶乘,计算方法如下:6! = 6 * 5 * 4 * 3 * 2 * 1。

此计算通过重复计算事实 * (事实 -1) 直到事实等于 1 来完成。

递归函数是一种调用自身并包含退出条件以完成递归调用的函数。在阶乘数计算的情况下,退出条件是事实等于 1。递归通过“堆叠”调用来工作,直到退出条件为真。

例如:

#include <stdio.h>
int factorial(int number);
int main() {    
  int x = 6;
  printf("The factorial of %d is %d\n", x, factorial(x)); 
  return 0;}
int factorial(int number) {
 if (number == 1)    return (1); /* exiting condition */
  else
    return (number * factorial(number - 1));
}

程序显示:

 The factorial of 6 is 720

在这里,我们讨论计划细节:

递归函数

  1. 我们声明一个递归阶乘函数,该函数接受一个整数参数并返回该参数的阶乘。该函数将调用自身并减少数字,直到退出或达到基本条件。当条件为真时,先前生成的值将相互相乘,并返回最终的阶乘值。
  2. 我们声明并初始化一个值为“6”的整数变量,然后通过调用阶乘函数打印其阶乘值。

请参考下图以更好地理解递归机制,该机制包括不断调用函数自身,直到满足基本情况或停止为止。ping 条件满足后,我们收集之前的值:

递归函数

内联函数

C 语言中的函数用于存储最常用的指令。它用于模块化程序。

每当调用一个函数时,指令指针就会跳转到函数定义处。执行完一个函数后,指令指针会回到跳转到函数定义处的语句。

每当我们使用函数时,我们都需要额外的 指针 head 跳转到函数定义并返回到语句。为了消除这种指针头的需要,我们使用内联函数。

在内联函数中,函数调用直接被实际的程序代码取代。它不会跳转到任何块,因为所有操作都在内联函数内部执行。

内联函数主要用于小计算。当涉及大量计算时,它们并不适用。

内联函数与普通函数类似,只是在函数名前添加了关键字 inline。内联函数使用以下语法创建:

inline function_name ()
{
    //function definition
}

让我们编写一个程序来实现内联函数。

inline int add(int a, int b)		//inline function declaration
{
	return(a+b);
}
int main()
{
	int c=add(10,20);
	printf("Addition:%d\n",c);
	getch();
}

输出:

Addition: 30

上面的程序演示了如何使用内联函数对两个数字进行加法运算。如我们所见,我们只在内联函数中返回了两个数字的加法,而无需编写任何额外的代码。在函数调用期间,我们只需传递要执行加法的值即可。

常见问题

按值调用会将参数复制到函数中,因此更改仅限于局部变量,原始变量保持不变。按引用调用则通过指针传递变量地址,使函数可以直接修改调用者的原始数据。

实际参数是调用者在函数调用期间传递的真实值或变量。形式参数是函数定义中接收它的占位符。它们按位置匹配,第一个参数对应第一个参数,第二个参数对应第二个参数。

AC 函数直接返回一个值。要返回多个结果,可以将它们封装在一个结构体中,填充一个数组,或者将指针作为参数传递,以便函数将每个结果写入调用者自己的变量中。

函数带来了可重用性,使得一个代码块可以多次运行;同时,函数也带来了模块化,将大型程序拆分成更小的部分。此外,函数还能提高代码可读性,简化测试和调试,并将复杂的细节隐藏在单个名称背后,从而节省开发时间。

main() 函数是每个 C 程序开始执行的入口点。操作系统会首先调用它,其返回值通常为 0,表示程序执行成功。main() 函数可能需要 argc 和 argv 来接收命令行参数。

递归适用于具有自然重复结构的问题,例如树遍历或阶乘,可以生成更简洁、更清晰的代码。迭代通常运行速度更快,内存占用更少,因为它避免了重复调用。如果追求代码清晰,则选择递归;如果追求处理大规模输入时的性能,则选择迭代。

是的。AI 代码助手可以根据纯文本提示编写 C 函数,建议参数和返回类型,并标记诸如缺少返回值或参数不匹配之类的错误。但务必在使用生成的函数之前对其进行编译和测试。

GitHub 副驾驶 它会根据函数名或简短注释自动补全 C 函数,并建议添加声明、循环和递归调用。它通常会在 `main()` 函数上方添加一个匹配的函数原型,但您仍然需要检查其逻辑。

总结一下这篇文章: