嵌入式团队培训_函数

数学上的函数 z = f(x,y) 因变量 = 函数名(自变量,自变量)
计算机的函数 返回值(=)函数名(参数,参数/函数指针) {函数主体}

void  f (int x,int y) ;
int   f(int x,int y);
int*  f(int x,int y);
int*  f(int x,int(*fun)(int y, int z);//了解即可

一、概念以及为什么使用函数?

函数:所有的命令都封装在一个块内。每个块都会执行特定的任务。
为什么:使用函数让程序更加模块化,从而提高程序代码的可读性,方便后期修改,完善。

例如:读入一系列数字,再分类这些数字,在找出这些数字的平均值,最后打印柱状图。

int main() {
	//需要的参数声明或初始化
	float list[SIZE];
	//1.读入一系列数字
	readList(list,SIZE);
	//2.分类这些数字
	sort(list,SIZE);
	//3.计算数字的平均值
	average(list,SIZE);
	//4.打印柱状图
	barGraph(list,SIZE);

	return 0;
}

主函数: main()——该函数是程序启动后,第一个执行的函数,即程序的入口。 其他所有函数都是 main()函数的子函数,但一个函数只能被定义一次,可以根据需要被多次的声明和调用。

二、返回值

(1)返回值的类型可以是 void 或者任何对象类型。
(2)函数无法返回函数或数组。然而,可以定义一个函数的返回值为指针,并将该指针指向一个函数或数组。

return 0和exit(0)的区别

exit(0);//退出程序
return 0;//退出函数

三、函数名

小驼峰形式:readList(list,SIZE);
或者ANSI C风格:read_list(list,SIZE);

四、参数

函数定义时用的变量叫形参
传递给函数的中形参值或变量叫实参

/**
 * 计算圆的周长
 * @param r 半径
 * @return 圆周长
 */
double circle( double r) {    // 这里r 是形参 形参一定是一个变量
	return PI * 2 * r; //返回值的类型一定是定义的函数类型,这里是double
}

int main() {
	double a = 12.2;
	double C = circle(2.1111); //a 是实参,实参可以是你变量,也可以是常量
	printf("图的周长为:%lf\n", C);
	sayhello("inx");
}

注意:
1形参在未出现函数调用时,他们并不占用内存单元,只有在发生函数调用的时候形参才被分配内存,函数调用完成后,形参所占的内存被释放
2实参可以是变量,常量或者表达式
double C = circle(a); double C = circle(2.1111); double C = circle((2.1111 + a) / 2);
3形参与实参的数据类型一定要可兼容

4.在C语言中,实参与形参的数据传递是“值传递”,即单向传递,只由实参传递给形参,而不能由形参传递给实参。值传递时,实参不变。

注:如果函数的参数是个数组,或者字符串的时候,那么是可以通过形参修改实参的值,(引用传递)

五、值传递、址传递和引用传递

简单的例子。函数swap用来交换两个数的值。

(1)值传递,虽然传递了参数,但是变量本身的值并没有做交换。实际上参数m和n在传入函数之前还复制了里面的内容,并把内容交给一个临时的内存,然后在内部执行交换操作后,只是临时内存m和n做了交换,可见值传递只是传递了实参中的值,在函数内部也无法修改外部的实际参数。

在swap函数执行语句的最前面,隐含地存在m=m; n=n;这两条语句,这样就便于理解了。当m,n把值赋给函数中m,n之后,对函数中的m,n不论再做什么操作,都不会影响到m,n(主函数中的)本身

#include<stdio.h>

/**
 * 交换两个值
 * @param m 第一个值
 * @param n 第二个值
 */
void swap(int m,int n) {
	m = m + n;
	n = m - n;
	m = m - n;
}

int main() {
	int m = 2,n = 3;
	swap(m,n);
	printf("%d %d\n",m,n);
	return 0;
}

(2)地址传递,与值传递的分析一样,我们同样可以设想,在swap函数里,隐含地存在m=&m; n=&n;这两条语句,这表示m的地址代入到了m,n的地址代入到了n。这样一来,对*m, *n的操作就是m,n本身的操作。所以主函数中的m,n的值被对调了。

#include<stdio.h>

/**
 * 交换两个值
 * @param m 指向第一个值的指针
 * @param n 指向第二个值的指针
 */
void swap(int* m,int* n) {

    *m = *m + *n;
    *n = *m - *n;
    *m = *m - *n;
}

int main() {

    int m = 2,n = 3;
    swap(&m, &n);
    printf("%d %d\n",m,n);

    return 0;
}

(3)引用传递先看函数的声明和调用的写法,函数调用和值传递的写法是一样的,但是函数声明是不一样的。
声明:swap (int &m, int &n)
函数调用:swap (m, n)

因为定义的x,y前面有&取地址符,调用函数swap时,m,n分别代替了m,n,即函数中的m,n分别引用了主函数中的m,n变量。因此,函数里的操作,实际上是对实参m,n本身的操作,其值发生了对调。

#include<stdio.h>

/**
 * 交换两个值
 * @param m 第一个值的引用
 * @param n 第二个值的引用
 */

void swap(int &m,int &n){
	m=m+n;
	n=m-n;
	m=m-n;
}

int main(){
	int m=2,n=3;
	swap(m,n);
	printf("%d %d\n",m,n);
	return 0;
}

六、递归函数

函数可以调用自己,这就叫函数的递归:

注意:
1.递归函数必须有结束条件。
2.当函数在一直递推,直到遇到结束条件后返回

所以递归要有两个要素,结束条件与递推关系

#include <stdio.h>

/**
 * 计算斐波那契数列
 * @param num 斐波那契数列的项数
 * @return 斐波那契数列值
 */
long fibonacci( long num )
{
	//结束条件
    if ( num == 0 || num == 1 ) {
        return num;
	} else {
		//递推关系式fibonacci(num ) = fibonacci( num -1 ) + fibonacci( num -2 ) (n > 2)
        return fibonacci( num -1 ) + fibonacci( num -2 );
    }
}

int main() {
    long number;

    puts("请输入斐波那契数列的项数: ");
    scanf("%ld", &number);


    printf("斐波那契数列第%ld项为: %ld\n", number, fibonacci( number ) );
    return 0;
}

递归的优缺点

  1. 递归给某些编程问题提供了最简单,易懂的方法。
  2. 但是一个有缺陷的递归会很快耗尽计算机的资源,递归的程序难以理解和维护,且当数据过多过大时,程序执行时间会很长。

七、总结

函数作为工具类知识点,重点是要在平时开发编程中习惯性的运用函数编程,体现模块化的设计思想。

八、作业

函数作业题:代码规范,注释清楚(函数功能,参数,返回值),代码仅供参考,有更好的算法就写自己的算法。

代码注释例如:

/**
 * (函数功能):
 * @param (参数含义)
 * @return (返回值含义)
 */

Description1
本来题目到上一题就结束了,不过周五的某个上午,Nemaleswang接到了BOOS上级XL老(yuan)师(zhang)的电话,他语重心常的对Nemaleswang说这次的题目要出好啊,尽量帮他筛选出来蓝桥杯能拿省三的同学,妈呀,省三不是会暴力就行了嘛,于是Nemaleswang不屑于出这些简单题,于是甩锅给了小玩,小玩也很难受啊,于是他随便找了两道题就敷衍了最后的这两道暴力题(都告诉你是暴力了你还要怎样?)

第一题:小玩去餐馆吃饭,这里有两种主食,一种是noodle,我们用n表示,分为1、2、3三种尺寸分别代表小份、中份、大份,价格分别是3,6,8
另外一种是rice,我们用r表示,分为1、2、3三种尺寸分别代表小份、中份、大份,价格分别是10,12,18
现在小玩点了n份吃的,问小玩一共吃了多少钱的食物

Input
第一行一个整数n,代表小玩点了多少份吃的
接下来n行,每行一个字符s(要么是n,要么是r),代表面食或者米饭,一个整数(只能是1,2,3)代表这一份吃的的尺寸(小玩可以无限买吃的,不要管重复不重复)
Output
输出小玩买这些吃的的价格
Sample Input 1
2
r 1
n 2
Sample Output 1
16
Hint
对于100%的数据,n <= 50

Description2 给你t组数据每组两个数n和m,让你求n的m次方有多少位数。

Input
多组数据,第一行一个整数t(1<=t<=100),接下来t行每行两个空格隔开的数n和m。(0<n=<10000000,0=<m<10)
Output
n的m次方有多少位数
Sample Input 1
5
10 5
5 3
6 7
11 2
13 6
Sample Output 1
6
3
6
3
7

Description3 给定一个长度为n(0< n<
=10000)的序列,保证每一个序列中的数字a[i]是小于maxlongint的非负整数 ,编程要求求出整个序列中第k大的数字减去第k小的数字的值m(提示:用数组先排序),并判断m是否为质数。(0< k< =n)

Input
输入格式: 第一行为2个数n,k(含义如上题) 第二行为n个数,表示这个序列
Output
输出格式: 如果m为质数则 第一行为’YES’(没有引号) 第二行为这个数m 否则 第一行为’NO’ 第二行为这个数m
Sample Input 1
5 2
1 2 3 4 5
Sample Output 1
YES
2
提示
对于第K大的详细解释 :
如果一个序列为1 2 2 2 3
第1大 为3
第2大 为2
第3大 为2
第4大 为2
第5大 为1
第K小与上例相反
另外需要注意的是
最小的质数是2, 如果小于2的话, 按不是质数处理

发布了47 篇原创文章 · 获赞 18 · 访问量 4857

猜你喜欢

转载自blog.csdn.net/qq_43605085/article/details/102694571
今日推荐