【C语言督学训练营 第七天】一文拿下C语言函数

前言

废话不多说,直接上干货!王道yyds!!!每一集都会扫到我的盲区!在这里插入图片描述

一、函数概念

1.函数的声明与定义

下面例中有两个c文件, func.c是子函数printstar和l print_message 的实现,也称定义; main.c是 main 函数, func.h中存放的是标准头文件的声明和 main 函数中调用的两个子函数的声明,如果不在头文件中对使用的函数进行声明,那么在编译时会出现警告(函数声明的作用是告诉编译器先不要报错,我的实现在后面),下面几段代码是分文件的形式写的,在一个大型项目中,往往有多人进行,开发,分文件写代码可以大大的提高我们的开发效率。在进行编译的时候也可以提高编译效率。

这里有一点就是,如果引入官方库我们使用<>,如果引入自己写的库我们用" " (作为了解不考)
func.h文件

#include <stdio.h>
#include <stdlib.h>
int printstar(int i);//函数声明
void print_message();

func.c文件

#include "func.h"
int printstar(int i)//i即为形式参数
{
    
    
	printf("**************大大*大****\n");
	printf("printstar %d\n",i);
	return i+3;
}

void print_message()//可以调用printstar
{
    
    
	printf( "how do you do\n");
	printstar(3);
}

main.c文件

#include "func.h"
int main()
{
    
    
	int a=10;
	a=printstar(a);
	print_message();
	printstar(a);
	return 0;
}

函数的声明与定义的差异如下:

  • (1)函数的定义是指:对函数功能的确立,包括指定函数名、函数值类型、形参及其类型、函数体等,它是一个完整的、独立的函数单位。
  • (2)函数的声明是指:把函数的名字、函数类型及形参的类型、个数和顺序通知编译系统,以便在调用该函数时编译系统能正确识别函数并检查调用是否合法。

隐式声明:C语言中有几种声明的类型名可以省略。例如,函数如果不显式地声明返回值的类型,那么它默认返回整型;使用旧风格声明函数的形式参数时,如果省略参数的类型,那么编译器默认它们为整型.然而,依赖隐式声明并不是好的习惯,因为隐式声明容易让代码的读者产生疑问:编写者是否是有意遗漏了类型名?还是不小心忘记了?显式声明能够清楚地表达意图!

C语言的编译和执行具有以下特点。

  • (1)一个C程序由一个或多个程序模块组成,每个程序模块作为一个源程序文件。对于较大的程序,通常将程序内容分别放在若干源文件中,再由若干源程序文件组成一个C程序.这样处理便于分别编写、分别编译,进而提高调试效率(复试有用).一个源程序文件可以为多个C程序共用。
  • (2)一个源程序文件由一个或多个函数及其他有关内容(如命令行、数据定义等)组成.一个源程序文件是一个编译单位,在程序编译时是以源程序文件为单位而不是以函数为单位进行编译的.main.c和 func.c分别单独编译,在链接成为可执行文件时, main中调用的函数printstar和 print_message才会通过链接去找到函数定义的位置.
  • (3)C程序的执行是从main函数开始的,如果在main函数中调用其他函数,那么在调用后会返回到main函数中,在 main函数中结束整个程序的运行。
  • (4)所有函数都是平行的,即仕疋乂图效的足力门加万H调甲但不能调用main函数.并不从属于另一函数,即函数个昵歆去足人。P四双 s以etmgoeane 函数而 print messagemain函数是由系统调用的,上述例子的main函数中调用print_message 函数,而print_message 函数中又调用printstar函数,我们把这种调用称为嵌套调用.

2.函数的分类与调用

从用户角度来看,函数分为如下两种。
(1)标准函数:即库函数,这是由系统提供的,用户不必自己定义的函数,可以直接使用它们,如 printf 函数、scanf函数。不同的C,系统提供的库函数的数量和功能会有一些不同,但许多基本的函数是相同的.
(2)用户自己定义的函数:用以解决用户的专门需要。从函数的形式看,函数分为如下两类。
(1)无参函数:一般用来执行指定的一组操作。在调用无参函数时,主调函数不向被调用函数传递数据。
无参函数的定义形式如下:
在这里插入图片描述
在上述代码中, print_message就是无参函数.

(2)有参函数:主调函数在调用被调用函数时,通过参数向被调用函数传递数据.有参函数的定义形式如下:
在这里插入图片描述
在上述代码中,printstar就是有参函数,int i对应的i为形式参数,主调函数和被调用函数之间存在数据传递关系。

二、函数中的变量

函数之间常常要有数据的传递,而最常见的数据传递方式就是通过变量进行传递!理顺变量的局部关系可以使我们写的代码更加健壮。函数间数据传递方式常见有以下几种!
在这里插入图片描述
下面看一个例子主函数main与print函数通过全局变量i进行数据传递。

#include <stdio.h>
int i=10;//全局变量
void print(int a){
    
    
	printf( "print i=%d\n",i);
}
int main(){
    
    
	{
    
    
		int j=5;
	}//局部变量的有效范围是离自己最近的花括号
	printf( "main i=%d\n",i);
	i=5;
	print(i);
	return O;
}

打印结果:
10
5
如果局部变量与全局变量重名,那么将采取就近原则,即实际获取和修改的值是局部变量的值。

#include <stdio.h>
int i=10;//全局变量
void print(int a){
    
    
	printf( "print i=%d\n",i);
}
int main(){
    
    
	printf( "main i=%d\n",i);
	int i=5;
	print(i);
	return O;
}

打印结果:
10
10
局部变量只在最近的花括号之内起作用,下面代码会抛出异常!

#include <stdio.h>
int main(){
    
    
	{
    
    
		int j=5;
	}//局部变量的有效范围是离自己最近的花括号
	printf( "main j=%d\n",j);
	return O;
}

在这里插入图片描述

1.形参与实参

关于形参与实参的一些说明如下。

  • (1)定义函数中指定的形参,如果没有函数调用,那么它们并不占用内存中的存储单元,只有在发生函数调用时,函数 print中的形参才被分配内存单元。在调用结束后,形参所占的内存单元也会被释放。
  • (2)实参可以是常量、变量或表达式,但要求它们有确定的值,例如, print(i+3)在调用时将实参的值i+3赋给形参。print函数可以有两个形参,如print (int a , int b)
  • (3)在被定义的函数中,必须指定形参的类型。如果实参列表中包含多个实参,那么各参数间用逗号隔开,实参与形参的个数应相等,类型应匹配,且实参与形参应按顺序对应,一一传递数据。
  • (4)实参与形参的类型应相同或赋值应兼容。
  • (5)实参向形参的数据传递是单向“值传递”,只能由实参传给形参,而不能由形参传回给实参。在调用函数时,给形参分配存储单元,并将实参对应的值传递给形参,调用结束后,形参单元被释放,实参单元仍保留并维持原值。
  • (6)形参相当于局部变量,因此不能再定义局部变量与形参同名,否则会造成编译不通。

2.局部变量与全局变量

局部变量
在一个函数内部定义的变量称内部变量,它只在本函数范围内有效,只有在本函数内才能使用这些变量,又称局部变量。
关于局部变量需要注意如下几点:

  • (1)主函数中定义的变量只在主函数中有效,而不因为在主函数中定义而在整个文件或程序中有效。主函数也不能使用其他函数中定义的变量。
  • (2)不同函数中可以使用相同名字的变量,它们代表不同的对象,互不干扰。
  • (3)形式参数也是局部变量。
  • (4)在一个函数内部,可以在复合语句中定义变量,这些变量只在本复合语句中有效,这种复合语句也称“分程序”或“程序块”.例子中的 int j=5就是如此,只在离自己最近的花括号内有效,若离开花括号,则在其下面使用该变量会造成编译不通。
  • (5)注意一个细节,for循环的小括号内定义的int i,在离开for 循环后,是不可以再次使用的.

外部变量
函数之外定义的变量称为外部变量.外部变量可以为本文件中的其他函数共用,它的有效范围是从定义变量的位置开始到本源文件结束,所以也称全程变量。
关于全局变量需要注意如下几点:

  • (1)全局变量在程序的全部执行过程中都占用存储单元,而不是仅在需要时才开辟单元。
  • (2)使用全局变量过多会降低程序的清晰性。在各个函数执行时都可能改变外部变量的值,程序容易出错,因此要有限制地使用全局变量(初试时尽量不用)。
  • (3)因为函数在执行时依赖于其所在的外部变量,如果将一个函数移到另一个文件中,那么还要将有关的外部变量及其值一起移过去.然而,如果该外部变量与其他文件的变量同名,那么就会出现问题,即会降低程序的可靠性和通用性,C语言一般要求把程序中的函数做成一个封闭体,除可以通过“实参→形参”的渠道与外界发生联系外,没有其他渠道。
  • 有些公司禁止使用全局变量!!!

三、使用函数的几种方式

函数间的调用关系是,由主函数调用其他函数,其他函数也可以互相调用.同一个函数可以被一个或多个函数调用任意次,如图所示。

在这里插入图片描述

1.嵌套调用

有两个函数,其中一个函数调用了另一个函数,前者称为调用函数,后者称为被调函数!
C语言中的函数不支持嵌套定义,支持嵌套调用!

#include "func.h"
int printstar(int i)//i即为形式参数
{
    
    
	printf("**************大大*大****\n");
	printf("printstar %d\n",i);
	return i+3;
}

void print_message()//可以调用printstar
{
    
    
	printf( "how do you do\n");
	printstar(3);
}

如代码段所示,print_message嵌套调用了printstar。

2.递归调用

我们把函数自身调用自身的操作,称为递归函数,递归函数一定要有结束条件,否则会产生死循环!如果存在两个或者多个函数互相调用并形成一个环的话也称为递归调用。
递归可以使编码变得简单,降低编程的难度。比如接下来的题目:假如有n个台阶,一次只能上1个台阶或2个台阶,请问走到第n个台阶有几种走法?题目不算难,主要先找到递归的式子,然后找到终止条件,最终编码!
在这里插入图片描述

//
// Created by Zhu Shichong on 2023/1/9.
//
#include <stdio.h>
int runs(n){
    
    
    if(n==1||n==2){
    
    
        return n;
    }
    return runs(n-2)+runs(n-1);
}
int main() {
    
    
    int n;
    scanf("%d",&n);
    printf("%d", runs(n));
    return 0;
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/apple_51931783/article/details/129893769