函数原来要这样用?

C语言函数

1 前言

本博客主要在于告诉那些,不明确函数的意义的,或者说编码比较不规范的朋友们关于函数的使用。

所以默认大家有一点点的函数和编程基础,也就是知道函数最最基本的用法的朋友们

2 何为函数

在讲我关于函数的认识之前,我想先引入一点编程基本方面的介绍。

2.1 如何编程

明确一点,编程最基本重要的有两点

1 基本语法 也就是我们最基本的if else while for switch语句,以及数据类型等,基于基本语法,我们才能操作这个语言

2 编程思想 这是我认为的重中之重,因为流程控制语句大同小异,所有编程语言都有,只需适应一下语法就可以,而编程思想则是超脱其上,有好的编程思想,无论你换成什么语言,几乎都可以很快的开发编程出自己想要的东西

2.1.1 基本语法方面

不同语言的基本语法不同,文档和资料非常的多,建议熟悉一门面向对象的语言后,入门其他语言的话只要查询文档,csdn等等的都可以,先不用费大力气去看视频,这方面我不多展开。

2.1.2 编程思想方面

我们学习计算机,学习编程,其实就是为了利用编程解决实际生活中的问题,那么到底如何发展出好的编程思想?

首先 编程是为了解决问题,而解决问题,自然就需要解决步骤。将复杂问题拆分成一个个简单的小问题,然后利用编程解决一个个简单的小问题,再把他们组合起来,我们就解决了比较复杂的问题。

这就是我认为的最基础的编程思想, 也就是 功能拆分

比如管理的层级肯定也是分为不同层级的,同层级的管理也会有许多不同的部门。

再比如出门,需要穿衣服,部分朋友需要化妆。这就是出门中的两大步,而基于这两步,化妆底下还有很多小步骤,穿衣服底下也要涉及到小步骤。我们只是运用了自己的能力把他们组合并最终解决了出门这一件事

所以 功能的拆分 模块化 并协同配合 其实是无处不在的。

那么这就意味着,我们写代码之前,脑子里第一个想的一定不是各种if else,数据类型怎么组合。

而是我的整个解决方案需要分为几步,每步具体要怎么做,需不需要再分成小步骤。

更复杂的项目还需要你抽象出现实生活中的东西对应的模型结构,比如人有年龄,四肢等,这方面也就是结构体以及类 存在的价值

结论,先把代码逻辑打通,抽象出功能层,再开始写代码 在思考项目模块的构成这个过程中,自然就会慢慢养成编程的思想

这时候,解决方案的步骤和函数的联系就出来了,每个步骤都是一个功能,一个功能,就会对应一个函数

3.例子

抛出需求,我现在需要实现一个计算器,需要能够计算两位数的加减乘除。那么我们开始写第一份代码。为了方便,我的计算数就不用scanf赋值了,我直接写成变量。

3.1 demo1

#include <stdio.h>    
int main(void)      
{
	int a = 2, b = 3;
	char operation = '+';
	switch (operation)
	{
	case '+':
		printf("%d\n", a + b);//加
		break;
	case '-':
		printf("%d\n", a - b);//减
		break;
	case '*':
		printf("%d\n", a * b);//乘
		break;
	case '/':
		printf("%d\n", a / b);//除
		break;
	default:
		printf("未知\n");
		break;
	}
}

代码很简单,也能运行,问题解决,唉编程就这? 可别这么说,代码是可以运行也很好看懂,但是因为我们这个程序很简单,全部的代码都写在主函数里,倒也能够阅读,可是当程序规模变大后呢,100甚至几百行的代码,放在主函数里,那是一场灾难,很快你就会遇到一种情况就是,如果出bug了,你需要在几百行里寻找修改的地方,如果要增加新的功能,你也需要在几百行的代码去寻找增加功能的位置并写下对应的代码。

所以我们进行第一次的改进

  • 抽取函数。

3.2 demo2

#include <stdio.h>    
void calculator();
int main(void)      
{
	calculator();
}

void calculator() {
	int a = 2, b = 3;
	char operation = '+';
	switch (operation)
	{
	case '+':
		printf("%d\n", a + b);
		break;
	case '-':
		printf("%d\n", a - b);
		break;
	case '*':
		printf("%d\n", a * b);
		break;
	case '/':
		printf("%d\n", a / b);
		break;
	default:
		printf("未知\n");
		break;
	}
}

显然,计算器应该是实现数字计算的功能,一个功能就是一个函数,那我们的第一次改进,直接把逻辑代码全部,主函数瞬间清晰,如果我们要在主函数里继续写其他代码,只需要在一行calculator();底下写即可。

但这样,正确了吗?当我想要计算的数不是2和3时,我还是需要去calculator函数里修改变量a,b非常不方便,理由有两点

1 变量ab是什么,程序简单的时候我一看就知道变量ab在干嘛,程序复杂的时候呢?一堆abcde的变量命名,只会让代码越来越冗杂难懂。建议变量名像operation一样,一看就知道,这个变量是 “操作” 的意思。

2 多余的局部变量 当一个函数的局部变量越来越多时,我们也会越看越乱,如果可以的话,请省去他们。

所以我们需要做出第二次改动

修改变量ab的传参位置,以及变量名称

写出计算机看得懂的代码不是本事,写出同行人甚至外行人轻易看得懂的代码才厉害

3.3 demo3

#include <stdio.h>    
void calculator(int num1, int num2, char operation);
int main(void)      
{
	calculator(3,2,'+');
}

//num1,num2操作数  
//oepration为操作方式
void calculator(int num1,int num2, char operation ) {
	switch (operation)
	{
	case '+':
		printf("%d\n", num1 + num2);
		break;
	case '-':
		printf("%d\n", num1 - num2);
		break;
	case '*':
		printf("%d\n", num1 * num2);
		break;
	case '/':
		printf("%d\n", num1 / num2);
		break;
	default:
		printf("未知\n");
		break;
	}
}

记住,每次修改完代码,都要测试一次是否还能正常运行,哪怕只修改了一小步。

小的步子可以更快的前进,请保持你的代码处于可工作的状态,小步修改累计起来就可以大大改善系统的设计。也方便在你的修改出问题时及时定位(来自书 重构)

这里我们就实现了方便的传参,去除了糟糕的局部变量,不需要考虑函数内部的实现就可以得出结果。

但如同计算器这种,**我们其实更需要获得它的结果,而不是直接在函数里进行打印。**以及,写到这是不是有感受到,计算器是一个功能,计算器可以加减乘除,那么加减乘除,是不是也是四个不同的功能。分析完毕,我们进行第四次的改造

  • 改变返回值
  • 抽取加减乘除功能

3.4 demo4

依然遵守好的变量命名规范

#include <stdio.h>    
//计算器
int calculator(int num1, int num2, char operation);
//加
int add(int num1, int num2);
//减
int sub(int num1, int num2);
//乘
int mul(int num1, int num2);
//除
int div(int num1, int num2);

int main(void)      
{
	printf("%d", calculator(3,4,'+'));
}

//num1,num2操作数  
//oepration为操作方式
int calculator(int num1,int num2, char operation ) {
	switch (operation)
	{
	case '+':	
		return add(num1, num2);
	case '-':
		return sub(num1, num2);
	case '*':
		return mul(num1, num2);
	case '/':
		return div(num1, num2);
	default:
		printf("未知\n");
		return -1;
	}
}

int add(int num1,int num2) {
	return num1 + num2;
}

int sub(int num1, int num2) {
	return num1 - num2;
}

int mul(int num1, int num2) {
	return num1 * num2;
}

int div(int num1, int num2) {
	return num1 / num2;
}

看完这个代码可能就会有人有意见了,你这每个函数里也就一行代码,有必要吗?诚然,一行代码的话问题不大,有没有想过如果我们做的不是这种简单的计算器,而是复杂一点的计算器呢,或者是一些其他的复杂项目呢,不把小功能抽取出来,你的代码只会越来越长,越来越难以管理。

比如你的学生管理系统,全部写成一个函数的话,只会看得你头皮发麻,我们至少需要把学生的增删改查抽象成对应的函数,然后再在学生管理系统这个函数里进行 switch 或者if else的分支对应

写到这我们的重构基本结束了,如果还要修改的话,就利用函数指针等的,写回调函数,如果大家想看的话,我再继续做

现在我们的结构非常的清晰明了。 计算器函数里,有加减乘除四个方法,而这四个方法,也有对应的函数进行处理。

每个功能一个函数,大功能里的小功能,自然也是一个函数

回顾一下我们都做了什么吧。

  • 1:抽取逻辑代码
  • 2:改变变量命名
  • 3:分解模块

大致方向对函数的处理一般就是这么几步,可以很好的帮助我们写出容易拓展的,复用性高的函数,比如以后其他地方需要单独加法不需要计算器,我们只要一个add函数拿去用就行,不用再写一次里面的逻辑。

请一定要记住一点,我这里为了方便实现,只是拿的这种简单的代码举例子,所以函数看起来很简单甚至没必要提取。

但是以后大家面临的可能是几百行的代码。一个函数里也会有几十行左右的代码(我认为超过50或者100行的函数,那就是可以继续抽取函数进行功能划分的)

比如我们现在需要加一个处理平方的功能,只需要在switch里加一个平方分支,然后复用我们的乘法函数,如这个例子。

可以看出。我们通过在平方函数里调用乘法函数,很方便的实现了平方的功能。千万别问为什么不用 return num*num。当然也可以了,只是以后我们面临的代码规模肯定不是这样简单的。这里只是举例子!!!

int square(int num){
	return mul(num, num)
}

所以说!!!如何处理好函数真的是一件非常重要的事情。如果你不希望自己写的复杂代码过两天就看不懂的话,那么一定要做到哦

这里再次提出基本点

1:抽取逻辑代码

2:改变变量命名

3:分解功能模块,协同配合

4:去除多余的局部变量

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

这里煤球

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值