模块化编程第1讲(10-24日上课简记)

**

真心话大冒险:讲真,带了10几年的编程语言课程,今年是最努力、最认真准备的一年,大数据专业的学生,你要是不好好学,真心对不起我!

**
本讲主要讲述为何要模块化(模块化之美)、C语言如何实现模块化(函数)、如何定义一个函数(以main为例)、如何使用自定义的函数(函数的调用)。

主题1.诸葛亮之痛

  • 同学们都看过《三国演义》吧,还深深地记得诸葛亮和司马懿二人吧。 诸葛亮的处事风格:事无巨细,事必躬亲!
    最终结果:累死五丈原!在他去世不久,苦心经营的蜀国也随之灰飞烟灭。 司马懿的处事风格:任务分工,各尽其责!
    最终结果:为儿子建立晋朝奠定了坚实的基础。 其实,这二人的处事风格也代表着C语言程序设计的两种风格。

诸葛亮式的程序设计风格——仅有一个main函数,main函数就好比是诸葛亮,所有的程序代码都在该函数中。

  • 初学时,我们需要解决的问题都比较容易,因而写的代码都比较简单,可以都放在main函数中。如果我们越来越牛,要解决复杂的问题呢?
  • 所有的代码都放在main函数中的话,它将异常庞大,可读性、维护性都将成为噩梦。

那么,一个函数中适合放多少行代码呢?

  • 1986年IBM的研究结果:多数有错误的函数大于500行。
  • 1991年对148000行代码的研究表明:小于143行的函数更易于维护。

所以说,要解决复杂的问题,需要采用分而治之的策略:将复杂问题分解为若干个简单的问题,把实现若干个简单问题的功能分解到不同的模块中。其实,分而治之的策略在方方面面已得到广泛应用。
例如: 国家——>省份——市——>县——>乡——>村——>组——>户

主题2. 在C语言程序设计中,如何实现模块呢?

答:通过函数来实现的。

  • 问题:那么,什么是函数呢?
  • 简答:大家都知道main函数,所以也知道了函数的大概模样。其实,为了共同解决一个复杂的问题,main函数还需要帮手——若干个子函数,子函数各司其职,完成独立的功能。各个子函数和main函数通力合作,完成一件大事情!这就是分工与合作的艺术之美。

2.1 C语言函数的分类

  • ANSI/ISO C定义的标准库函数(使用时,必须在程序开头把定义该函数的头文件包含进来);我们熟知的scanf、printf、sqrt等等。
    第三方库函数:不在标准范围内,能扩充C语言的功能,由其他厂商自行开发的C语言函数库(针对某个应用);
    用户自定义函数。(讲述的重点)

2.2 那么,用户如何定义一个函数呢?

我们先来看一下老朋友main函数。

在这里插入图片描述

其实,子函数和main函数长得差不多。编个函数实现求两个整数的最大值。子函数如下:

int GetMax(int i,int j) //()里面有了两个变量,它们的作用是什么呢?
{
	int max=j;
	if(i>j)
		max=i;
	return max;
}

2.3 如何使用用户定义的函数呢?

  • 如果要通过GetMax函数来计算最大值,我们该怎么做呢?

  • 众所周知,C语言执行程序的入口是main函数,所以我们必须再编写一个main函数,GetMax函数的功能是找出两个整数中的最大者,这两个整数从何而来?来自GetMax还是main还是二者均可?不同的来源有何优缺点?上课再谈,大家可自行考虑下,老师推荐数据要来自main。完整的程序如下:

#include<stdio.h>
int GetMax(int i,int j)
{
	int t=j;
	if(i>j)
		t=i;
	return t;
}
int main()
{
	int a,b,max;
	scanf("%d%d",&a,&b);
	max=GetMax(a,b);
	printf("%d\n",max);
	return 0;
}

重点分析:

  • (1)GetMax中的int i和int j有何作用?
  • (2)main函数中语句:max=GetMax(a,b);的作用?
  • (3)GetMax函数的返回值一定是int吗?换成double会怎样?在不需要返回值的情况下,return语句还需要吗?

问题:自定义一个函数,该函数的功能是:输出语句I love life! 并写出完整的程序,调用该函数n次。
子函数无需任何返回值,就是实现一个输出语句的功能,所以没有return语句,函数的返回值类型是void。具体如下:

#include<stdio.h>
void p_sentence()
{
	printf("I love life!\n");
}
int main()
{
	int i,n;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	    p_sentence();
	return 0;
}

试想:如果该子函数输出的语句要由main函数传递,那该如何编写程序呢?

2.4 使用用户定义的函数有何好处呢?

当我们使用一个函数时,我们最关心的是这个函数的功能,使用它的时候,需要提供什么输入参数,它给我计算出来的最终结果是什么。至于它如何求得这个最终结果,也即函数内部实现细节我们不必关心。这就是封装带来的好处。来看个实例再细细体会下。
实例:计算x的n次方。

#include<stdio.h>
long Fun(int x,int n)
{
	int i;
	long result=1;
	for(i=1;i<=n;i++)
		result*=x;
	return result;
}
int main()
{
	int x,n;
	long ret;
	scanf("%d%d",&x,&n);
	ret=Fun(x,n);
	printf("%ld\n",ret);
	return 0;
}
  • 分析:main函数中的x,n 和Fun函数中的x,n是一回事吗?

** - 其实,Fun是一个封装好的函数,我们不用关心它内部的实现细节,只需关心它的功能是什么、要使用它的功能需要提供什么参数、它能给我们输出什么结果即可。就像Fun,我们知道它的功能是求x的n次方,我们只需提供x和n的值,获取最终计算结果即可,至于该函数是如何计算出x的n次方,调用者(该程序中main函数调用了Fun,所以main就称为调用者)不必管。

  • 如果有其他人在编程时也需要计算x的n次方,那么Fun函数它直接拷贝即可,注意下接口就可以使用了函数封装也大大提高代码的复用性。**

进一步:假如要计算X0+X1+X2+…+Xn的结果。
我们已知Fun函数的功能是计算x的n次方,所以在主函数的每次循环语句中,只需提供这两个参数就可获得结果。。

#include<stdio.h>
long Fun(int x,int n)
{
	int i;
	long result=1;
	for(i=1;i<=n;i++)
		result*=x;
	return result;
}
int main()
{
	int x,n;
	long ret=0;
	scanf("%d%d",&x,&n);
	for(i=0;i<=n;i++)
	    ret+=Fun(x,i);
	printf("%ld\n",ret);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/lvcongying0601/article/details/83304149
今日推荐