当前位置:网站首页>编程旅行之函数

编程旅行之函数

2022-04-23 13:57:00 糜邙

Hello!各位小伙伴大家好啊!本章将会带领大家了解函数的有关知识,本节会分为两个部分来讲解,希望对大家有所帮助


前言

本章会介绍函数有哪一些与一些注意事项


一、函数的分类

函数分为:库函数和自定义函数
我们分别展开讲述

1.库函数

首先是库函数,什么是库函数呢?
库函数是将函数封装入库,供用户使用的一种方式,但是库函数不能直接使用,要将库函数使用所在的文件名加入到#include<>里面才能使用该库函数

举两个例子:
1.

#include<stdio.h>
#include<string.h>
int main()
{
    
	char arr1[] = "1234567";
	char arr2[] = "#######";
	char arr3[] = {
     0 };
	char arr4[] = "#####";
	strcpy(arr2, arr1);
	printf("%s\n", arr2);
	strcpy(arr3, arr1);
	printf("%s\n", arr3);
	strcpy(arr4, arr1);
	printf("%s\n", arr4);
	return 0;
}

在这里插入图片描述
我们来一一分析这个程序,strcpy是一个拷贝函数,把拷贝的目的地放在前面,拷贝原码地点放在后面(顺序不能反)。因为strcpy是一个库函数,要引头文件string才能继续使用,string使用方法可在MSDN处查找,里面是英文,如果小伙伴们看不懂可以下一个欧陆词典,将鼠标放在不会的单词就会自动翻译出来,十分好用。接下来我们继续,可用看到上述程序会报错,这是因为数组在拷贝的时候内存不够了,从而报错,最新的vs编译器尽管报错也可以继续编译,但这种程序是存在问题的,我们要合理安排内存空间。
2.

#include<stdio.h>
#include<string.h>
int main()
{
    
	char arr1[] = "1234567";
	memset(arr1, '@', 4);
	printf("%s\n", arr1);
	char arr2[] = "1234567";
	memset(arr2+3, '@', 4);
	printf("%s\n", arr2);
	return 0;
}

在这里插入图片描述这个库函数memset与strcpy一样要引用头文件string,而memset函数作用是替换,这个函数可以把你原代码想要被替换的内容替换成为你想要的代码,这个函数用法是,括号最左边是你要更换内容的起始地址,中间就是你要替换成什么内容,最右边就是你要替换内容的数量,如上图所示。
小结:库函数在使用的时候引用头文件就可以使用了,每个库函数的作用都可以在MSDN处查找,使用比较方便


二、自定义函数

这个就比较复杂了,我们一步一步来讲

#include<stdio.h>
int add(int a, int b)//传值调用:传数值
{
    
	return a + b;//函数括号中的变量称为形参(形式参数),形参只有函数被调用才实例化(分配内存单元),形参在函数调用完就销毁了
}
void swep(int* a, int* b)//传址调用:传地址
{
    
	int c = *a;//在传参的时候,形参是实参的一份临时拷贝,他有自己开辟的内存空间,改变形参不会改变实参
	*a = *b;
	*b = c;
}
int main()
{
    
	int a = 0;
	int b = 0;
	scanf("%d %d", &a, &b);//函数后面括号里面的变量是实参(实际参数),实参都是具有确定值的,方便进行传参
	printf("交换前的值:%d %d\n", a, b);
	swep(&a, &b);
	printf("交换后的值:%d %d\n", a, b);
	int ret = add(a, b);
	printf("a与b的和:%d\n", ret);
	return 0;
}

图中的add与swep就是我们自定义的函数

自定义函数涉及到传参,在主函数里面定义一个函数,后面括号放的就是实际参数也就是实参,将自定义函数实现时函数括号里面就是由实际参数传参得到的形式参数也就是形参。在程序进行到自定义函数时,自定义函数才开辟空间运行,运行结束后立刻销毁。在实现自定义函数的时候,形参是实参的一份临时拷贝,它有独立的空间,改变形参的值不会改变实参的值,所以在要改变实参的情况下,要进行传址调用
注意:函数可以嵌套调用,但是不能嵌套定义
正确方法:

int add(int x,int y)
{
    
	return x+y;
	sub(a,b);
}
int main()
{
    
	return 0;
}

错误方法:

int add(int x,int y)
{
    
	return x+y;
	int sub(int a,int b)
	{
    
		return x-y;
	}
}
int main()
{
    
	return 0;
}

上面的错误就是嵌套定义,小伙伴们一定要牢记,函数可以嵌套调用,不可嵌套定义


2.链式访问

int main()
{
    
	int len = strlen("abcdef");
	printf("%d\n",strlen("abcdef"));
	return 0;
}

上图中,strlen的返回值作为printf函数的参数。链式访问像一个链条一样把函数串起来
在这里插入图片描述
这个图片里面也是链式访问,那么为什么结果是这样的呢?我们一起来看看
第一行打印结果是:
12345
6
2
这是因为第一行第三个printf打印出来的数字是12345加一个回车键,一共是6个元素,这六个元素作为第一行第二个printf的参数,所以第二个printf打印的结果是6加一个回车键,而这个结果作为第一个printf的参数来进行打印,6加回车键是两个元素,最后打印出2就是这么来的
第二行打印结果是:
12345 6 2
与第一行打印结果同理,只不过第一行结果后面有换行做为元素参与打印
而第二行是将空格作为元素参与打印
第三行打印结果是:
1234551
因为第三行%d后面没有任何内容,所以说,第三个printf打印数字有多少个就是多少个,没有多余内容,所以在第二个printf看来有5个元素,第一个printf看来就只有一个元素


三、函数的声明和定义

函数在调用的时候先要声明,这一点要十分注意,不管函数调不调用都要先声明,然后再定义,最后才调用
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
函数声明是在头文件声明,然后在1.c文件定义,在2.c文件引入头文件就可以调用函数了
上面图片就是,add函数在add.h文件声明,在add.c文件定义,在test.c文件引用头文件然后调用


四、函数的递归与迭代

1、递归:

递归有两个必要要求,这两个要求都有递归不一定编译正确,但是没有这两个要求一定编译不正确

第一:递归一定有一个限制条件,当满足限制条件的时候递归将不再继续进行
第二:每递归一次,都会接近递归的限制条件

这两个条件必不可少

输入一个数,比如123456,输出1 2 3 4 5 6,我们可以用循环来打印,但是这里用递归更方便点

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

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
递归就是函数调用本身,本题的思路就是首先判断输入数字大不大于9,大于9就说明是两位数,进入if语句,直到数字递归到小于9之后依次打印返回数字


2、迭代

循环属于迭代,但是迭代不只是循环
求一个斐波那契数
斐波那契数列就是从第三个数开始,前两个数之和等于下一个数:
1,1,2,3,5,8,13,21,34,55…

#include<stdio.h>
int fib(int n)
{
    
	if (n <= 2)
	{
    
		return 1;
	}
	else
		return fib(n - 1) * fib(n - 2);
}
int main()
{
    
	int n = 0;
	scanf("%d", &n);
	int ret = fib(n);
	printf("%d\n", ret);
	return 0;
}

用递归的方法会发现当输入数字较大时计算机会算很长时间,这就很不方便,如果用迭代的方法是不是会快一点呢?我们试试看

#include<stdio.h>
int fib(int n)
{
    
	int a = 1;
	int b = 1;
	int c = 1;//当输入n小于3时,斐波那契数是1,将c初始化为1可以直接打印出1来
	while (n >= 3)
	{
    
		c = a + b;//第一个数是a,第二个数是b,求和得到第三数c,再将a和b代表的数字整体向后移动1,求c,也就是
	//第二次循环,第二个数是a,第三个数是b,求和得到第四数c
	//第三次循环,第三个数是a,第四个数是b,求和得到第五数
		//依次循环,直到求出第n个数字
		a = b;
		b = c;
		n--;//每次迭代一次后就减少一次迭代
	}
	return c;
}
int main()
{
    
	int n = 0;
	scanf("%d", &n);
	int ret = fib(n);
	printf("%d\n", ret);
	return 0;
}

在这里插入图片描述

可以看出来,迭代在进行运算较大数字的时候,虽然答案是错误的,但是速度快效率高,可以快速得出结果,所以说斐波那契数用迭代更加方便一点
递归和迭代要根据实际情况来选择用什么方法来进行

好了,以上就是本期内容,谢谢各位小伙伴们观看了,希望对小伙伴们都有所帮助,我们下期再见啦!

版权声明
本文为[糜邙]所创,转载请带上原文链接,感谢
https://blog.csdn.net/kdjjdjdjjejje128/article/details/124351050