1. 程式人生 > >模組化程式設計第1講(10-24日上課簡記)

模組化程式設計第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;
}