贝蒂的函数小课堂~

2023-12-13 20:27:32

目录

1.函数的概念:

2.函数的分类:

? ? 2.1库函数

? ?2.2自定义函数?

3.自定义函数:?

? ? 3.1 语法

? ? 3.2 实例

4.函数的参数:

? ? ?4.1 实际参数?

? ? ?4.2 形式参数

? ? ?4.3 实参与形参的关系

5.嵌套调用和链式访问:

? ?5.1函数的嵌套调用

? ?5.2函数的链式访问?

6.函数的定义与声明:

? ?6.1 函数的定义

? ?6.2 函数的声明

7.函数的迭代与递归 :

? ? 7.1函数的迭代

? ? 7.2函数的递归?

? ? ?7.3递归问题


1.函数的概念:

? ? ? ? ? 在数学中我们就知道了函数这个概念,而C语言同样引入了函数这个概念,那C语言的函数到底是什么样的呢~

? ? ? ? ? 在C语言中,函数也叫子程序,它是一段可以重复使用的代码,用来独立地完成某个功能,它可以接收用户传递的数据,也可以不接收。?

2.函数的分类:

? ? 2.1库函数

? ? ?C语?标准中规定了C语?的各种语法规则,C语?并不提供库函数;C语?的国际标准ANSIC规定了?些常?的函数的标准,被称为标准库,那不同的编译器?商根据ANSI提供的C语?标准就给出了?系列函数的实现。这些函数就被称为库函数。

? ? ?比如说我们前面学习的printf和scanf都是库函数,它的头文件时<stdio.h>。但是我们今天的主题不是讲解库函数,如果大家想学习其他库函数,可以去以下网站学习:

? ?(1)?菜鸟教程

? ?(2)C 标准库头文件

? ?2.2自定义函数?

? ? ??自定义函数是由程序员自主设计的函数,和库函数一样有函数名、返回类型、形式参数等,今天我们的目标就是学习如何写自定义函数。?

3.自定义函数:?

? ? 3.1 语法

dataType? functionName(形式参数)

{
? ? //body
}

  • dataType 是返回值类型,它可以是C语言中的任意数据类型,例如 int、float、char 等。
  • functionName 是函数名,它是标识符的一种,命名规则和标识符相同。函数名后面的括号( )不能少。
  • body 是函数体,它是函数需要执行的代码,是函数的主体部分。即使只有一个语句,函数体也要由{ }包围。
  • 如果有返回值,在函数体中使用?return?语句返回。return 出来的数据的类型要和 dataType 一样。

? ? 3.2 实例

? ? ? ? ? ?我们先写一个简单的加法函数:

#include<stdio.h>
int Add(int a, int b)
//函数名Add
//两个形式参数a,b,类型都是int
//返回类型也是int
{
	int c = 0;
	c = a + b;
	return c;//返回a+b的和
}
int main()
{
	int a, b;
	scanf("%d%d", &a, &b);
	int ret = Add(a, b);
	printf("两个数和为%d\n", ret);
	return 0;
}

输入:2? 3

输出:两个数和为5?

? ? ? ? ? 当然我们也可以优化一下

int Add(int a, int b)
{
	return a + b;//直接返回
}

? ? ? ? 贝蒂说:“虽然这样的加法计算我们也可以在主函数里实现,但是大家发现没有,函数可以重复使用,如果计算多组数据时,函数明显更加简洁流畅~”?

4.函数的参数:

? ? ?4.1 实际参数?

? ? ?? ? ?顾名思义,实际参数就是实际存在的参数,也就是主函数main调用函数时传给它的参数,也就是上面主函数中的a,b。

? ? ?4.2 形式参数

? ? ? ??? 同理,形式参数其实就是形式上的参数,也就是上面加法函数Add中的a,b。它并不是实际存在的,在未使用时并不会向内存申请空间,形式参数只有在函数被调?的过程中为了存放实参传递过来的值,才向内存申请空间,这个过程就是形式的实例化。

? ? ?4.3 实参与形参的关系

? ? ? ? ? 在介绍实参和形参关系时,我们先看看下面这段代码

#include<stdio.h>
void swap(int x, int y)//返回类型为void表示不返回值
{
    int temp = 0;//定义一个临时变量
    temp = x;//把x的值赋给temp
    x = y;//把y的值赋给x
    y = temp;//把temp的值赋给y,完成交换操作
}
int main()
{
    int a = 0;
    int b = 0;
    scanf("%d %d", &a, &b);
    printf("交换前:a=%d,b=%d\n", a, b);
    swap(a, b);//交换函数
    printf("交换后:a=%d,b=%d\n", a, b);
    return 0;
}

? ? ? ?那么交换后的输出是多少呢~?

?输入:3 5?

?输出:3 5

? ? ? 为什么交换的值还是不变呢,我们可以通过调试来观察一下?

? ? ?通过调试,我们发现a与x,b与y只是在数值上相同,他们地址是完全不同的,他们在两个独立的内存空间互不影响,对x,y交换根本不会改变a,b的值。并且函数在调用完成之后,函数所申请的内存空间会归还系统~

? ? 所以我们总结实参与形参的关系是:

? ? 形参只是实参的?份临时拷?,对形参改变根本不会影响实参

? ? 贝蒂说:“那我们该如何通过函数改变实参的值呢,这个问题先留一个悬念,贝蒂会在指针的章节为大家解答哒”

5.嵌套调用和链式访问:

? ?5.1函数的嵌套调用

? ? 我们在前面已经学习了选择结构和循环结构的嵌套使用,那函数嵌套调用又是怎样的呢。其实,简单来说,就是函数中也可以调用函数~

? ? ?举个例子,让我们看看下面这段代码

void print2()
{
	printf("hello world\n");
}
void print1()
{
	print2();//调用print2函数
}
int main()
{
	print1();//调用print1函数
}

?输出:hello world

? ?贝蒂说:“其实我们平常在主函数main中使用库函数printf,scanf,就是一种嵌套调用哦`”?

? ?5.2函数的链式访问?

? ? ? 链式访问简单来说就是将?个函数的返回值作为另外?个函数的参数,像链条?样将函数串起来就是函数的链式访问。

? ? ?举例:

?这是strlen的函数声明:size_t strlen(const char *str)?

#include <stdio.h>
int main()
{
	printf("%d\n", strlen("abcdef"));
    //根据strlen的返回值,我们就可以直接将其作为printf的参数
    //这就是一种简单的链式访问
	return 0;
}

输出:6?

6.函数的定义与声明:

? ?6.1 函数的定义

? ? 函数的定义就是指函数具体的实现过程,交代函数具体功能的实现

? ? 比如我们前面写的加法函数具体实现的过程就是函数的定义

int Add(int a, int b)
{
	return a + b;//直接返回
}

? 但是特别注意函数不能嵌套定义

int add(int x, int y)//加法函数
{
    return x + y;
    void print()
    {
        ....;//嵌套定义
    }
}

? ?6.2 函数的声明

? ? ? ?不知道大家注意到一个细节没有,就是贝蒂在写函数时候,会把函数放在主函数之前,那如果放在主函数之后会怎么样呢,让我们实验一下吧~

int main()
{
	int a, b;
	scanf("%d%d",&a,&b);
	int ret = Add(a, b);
	printf("%d", ret);
	return 0;
}
int Add(int x, int y)
{
	return x + y;
}

? ? ?一运行就会报这个警告,这个警告的意思就是说Add函数未定义,那为什么说Add未定义呢,原来是程序从上往下进行的,在遇到Add函数之前,会先执行主函数中的Add,此时程序根本不知道Add的含义,所以会报警告。

? ? ?那如何消除这个警告呢~,其实我只需要加一个声明,让程序提前知道有这个函数。

int Add(int x, int y);//函数声明
int main()
{
	int a, b;
	scanf("%d%d",&a,&b);
	int ret = Add(a, b);
	printf("%d", ret);
	return 0;
}
int Add(int x, int y)
{
	return x + y;
}
int Add(int , int );//声明写出这样也是可以的

? ? ? ?贝蒂说:“函数的调??定要满足,先声明后使?是,而函数的定义也是?种特殊的声明,所以如果函数定义放在调?之前也是可以的。”

7.函数的迭代与递归 :

? ? 7.1函数的迭代

? ? ? ?(1)什么是迭代

? ? ?「迭代 iteration」是一种重复执行某个任务的控制结构。在迭代中,程序会在满足一定的条件下重复执行某段代码,直到这个条件不再满足。我们学习过的while,for,do-while循环结构就是一种迭代。

? ? 7.2函数的递归?

? ? ? (1)什么是递归

?「递归 recursion」是一种算法策略,通过函数调用自身来解决问题。它主要包含两个阶段。
1. 递:程序不断深入地调用自身,通常传入更小或更简化的参数,直到达到“终止条件”。
2. 归:触发“终止条件”后,程序从最深层的递归函数开始逐层返回,汇聚每一层的结果。


? ? ( 2)递归的三个要素。
1. 终止条件:用于决定什么时候由“递”转“归”。
2. 递归调用:对应“递”,函数调用自身,通常输入更小或更简化的参数。
3. 返回结果:对应“归”,将当前递归层级的结果返回至上一层。

? ? ? (3)实例

利用递归计算1+2+3+4+....+n?

int recur(int n)
{
	// 终止条件
	if (n == 1)
	{
		return 1;
	}
	// 递:递归调用
	return n + recur(n - 1);
}

? ? ?7.3递归问题

输??个整数m,打印这个按照顺序打印整数的每?位。
?如:
输?:1234 输出:1 2 3 4
输?:520 输出:5 2 0

#include <stdio.h>
void print(int n)
{
    if (n > 9)
    {
        print(n / 10);
    }
    printf("%d ", n % 10);
}
int main()
{
    int n = 0;
    scanf("%d", &n);
    print(n);
    return 0;
}

代码分析:

void print(int n)//输入1234
{
    if (n > 9)//1234大于9
    {
        print(n / 10);//将123传入下个递归
    }
    printf("%d ", n % 10);//归的第四步,输出4
}
void print(int n)//传入123
{
    if (n > 9)//123大于9
    {
        print(n / 10);//将12传入下个递归
    }
    printf("%d ", n % 10);//归的第二步,输出3
}
void print(int n)//传入12
{
    if (n > 9)//12大于9
    {
        print(n / 10);//将1传入下个递归
    }
    printf("%d ", n % 10);//归的第一步,输出2
}
void print(int n)//传入1
{
    if (n > 9)//1不大于9
    {
        print(n / 10);
    }
    printf("%d ", n % 10);//输出1,开始‘归’
}

?贝蒂说:“递归的思考方式一般较为复杂,大家需要仔细琢磨哦~”

?

文章来源:https://blog.csdn.net/Bettysweetyaaa/article/details/134969872
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。