【C語言】第7章 用函式實現模組化程式設計
第7章 用函式實現模組化程式設計
輸出以下的結果,用函式呼叫實現。 ****************** How do you do! ****************** #include <stdio.h> int main() { void print_star(); void print_message(); print_star(); print_message(); print_star(); return 0; } void print_star() { printf(“******************\n”); } void print_message() { printf(“ How do you do!\n”); }
為什麼要用函式
說明:
1、一個C程式由一個或多個程式模組組成,每一個程式模組作為一個源程式檔案。對較大的程式,一般不希望把所有內容全放在一個檔案中,而是將它們分別放在若干個原始檔中,由若干個源程式檔案組成一個C程式。這樣便於分別編寫、分別編譯,提高除錯效率。一個源程式檔案可以為多個C程式共用。
2、一個源程式檔案由一個或多個函式以及其他有關內容(如預處理指令、資料宣告與定義等)組成。一個源程式檔案是一個編譯單位,在程式編譯時是以源程式檔案為單位進行編譯的,而不是以函式為單位進行編譯的。
3、C程式的執行是從main函式開始的,如果在main函式中呼叫其他函式,在呼叫後流程返回到main函式,在main函式中結束整個程式的執行。
4、所有函式都是平行的,即在定義函式時是分別進行的,是互相獨立的。一個函式並不從屬於另一個函式,即函式不能巢狀定義。函式間可以互相呼叫,但不能呼叫main函式。main函式是被作業系統呼叫的。
5、從使用者使用的角度看,函式有兩種。
庫函式,它是由系統提供的,使用者不必自己定義而直接使用它們。應該說明,不同的C語言編譯系統提供的庫函式的數量和功能會有一些不同,當然許多基本的函式是共同的。
使用者自己定義的函式。它是用以解決使用者專門需要的函式。
6、從函式的形式看,函式分兩類。
無參函式。無參函式一般用來執行指定的一組操作。無參函式可以帶回或不帶回函式值,但一般以不帶回函式值的居多。
有參函式。在呼叫函式時,主調函式在呼叫被呼叫函式時,通過引數向被呼叫函式傳遞資料,一般情況下,執行被呼叫函式時會得到一個函式值,供主調函式使用。
C語言要求,在程式中用到的所有函式,必須“先定義,後使用”
指定函式名字、函式返回值型別、函式實現的功能以及引數的個數與型別,將這些資訊通知編譯系統。
輸入兩個整數,要求輸出其中值較大者。要求用函式來找到大數。
int max(int x,int y)
{
int z;
z=x>y?x:y;
return(z);
}
————————————————————————————————————————
#include <stdio.h>
int main()
{ int max(int x,int y);
int a,b,c;
printf(“two integer numbers: ");
scanf(“%d,%d”,&a,&b);
c=max(a,b);
printf(“max is %d\n”,c);
}
int max(int x, int y)
{
int z;
z=x>y? x:y;
return(z);
}
輸入兩個實數,用一個函式求出它們之和。
#include <stdio.h>
int main()
{ float add(float x, float y);
float a,b,c;
printf("Please enter a and b:");
scanf("%f,%f",&a,&b);
c=add(a,b);
printf("sum is %f\n",c);
return 0;
}
float add(float x,float y)
{ float z;
z=x+y;
return(z);
}
輸入4個整數,找出其中最大的數。用函式的巢狀呼叫來處理。
#include <stdio.h>
int main()
{ int max4(int a,int b,int c,int d);
int a,b,c,d,max;
printf(“4 interger numbers:");
scanf("%d%d%d%d",&a,&b,&c,&d);
max=max4(a,b,c,d);
printf("max=%d \n",max);
return 0;
}
int max4(int a,int b,int c,int d)
{ int max2(int a,int b);
int m;
m=max2(a,b);
m=max2(m,c);
m=max2(m,d);
return(m);
}
int max2(int a,int b)
{ if(a>=b) return a;
else return b;
}
函式的遞迴呼叫
在呼叫一個函式的過程中又出現直接或間接地呼叫該函式本身,稱為函式的遞迴呼叫。
C語言的特點之一就在於允許函式的遞迴呼叫。
例7.6 有5個學生坐在一起
問第5個學生多少歲?他說比第4個學生大2歲
問第4個學生歲數,他說比第3個學生大2歲
問第3個學生,又說比第2個學生大2歲
問第2個學生,說比第1個學生大2歲
最後問第1個學生,他說是10歲
請問第5個學生多大
#include <stdio.h>
int main()
{
int age(int n);
printf("NO.5,age:%d\n",age(5));
return 0;
}
int age(int n)
{
int c;
if(n==1)
c=10;
else
c=age(n-1)+2;
return(c);
}
用遞迴方法求n!。
#include <stdio.h>
int main()
{ int fac(int n);
int n; int y;
printf("input an integer number:");
scanf("%d",&n);
y=fac(n);
printf("%d!=%d\n",n,y);
return 0;
}
int fac(int n)
{ int f;
if(n<0)
printf("n<0,data error!");
else if(n==0 | | n==1)
f=1;
else f=fac(n-1)*n;
return(f);
}
Hanoi(漢諾)塔問題。古代有一個梵塔,塔內有3個座A、B、C,開始時A座上有64個盤子,盤子大小不等,大的在下,小的在上。有一個老和尚想把這64個盤子從A座移到C座,但規定每次只允許移動一個盤,且在移動過程中在3個座上都始終保持大盤在下,小盤在上。在移動過程中可以利用B座。要求程式設計序輸出移動一盤子的步驟。
思路:
要把64個盤子從A座移動到C座,需要移動大約264 次盤子。一般人是不可能直接確定移動盤子的每一個具體步驟的
老和尚會這樣想:假如有另外一個和尚能有辦法將上面63個盤子從一個座移到另一座。那麼,問題就解決了。此時老和尚只需這樣做:
(1) 命令第2個和尚將63個盤子從A座移到B座
(2) 自己將1個盤子(最底下的、最大的盤子)從A座移到C座
(3) 再命令第2個和尚將63個盤子從B座移到C座
將n個盤子從A座移到C座可以分解為以下3個步驟:
(1) 將A上n-1個盤藉助C座先移到B座上
(2) 把A座上剩下的一個盤移到C座上
(3) 將n-1個盤從B座藉助於A座移到C座上
編寫程式。
用hanoi函式實現第1類操作(即模擬小和尚的任務)
用move函式實現第2類操作(模擬大和尚自己移盤)
函式呼叫hanoi(n,one,two.three)表示將n個盤子從“one”座移到“three”座的過程(藉助“two”座)
函式呼叫move(x,y)表示將1個盤子從x 座移到y 座的過程。x和y是代表A、B、C座之一,根據每次不同情況分別取A、B、C代入
#include <stdio.h>
int main()
{ void hanoi(int n,char one, char two,char three);
int m;
printf(“the number of diskes:");
scanf("%d",&m);
printf("move %d diskes:\n",m);
hanoi(m,'A','B','C');
}
void hanoi(int n, char one, char two, char three)
{ void move(char x,char y);
if(n==1)
move(one,three);
else
{ hanoi(n-1,one,three,two);
move(one,three);
hanoi(n-1,two,one,three);
}
}
void move(char x,char y)
{
printf("%c-->%c\n",x,y);
}
有一個一維陣列score,內放10個學生成績,求平均成績。
#include <stdio.h>
int main()
{ float average(float array[10]);
float score[10], aver; int i;
printf("input 10 scores:\n");
for(i=0;i<10;i++)
scanf("%f",&score[i]);
printf("\n");
aver=average(score);
printf("%5.2f\n",aver);
return 0;
}
float average(float array[10])
{ int i;
float aver,sum=array[0];
for(i=1;i<10;i++)
sum=sum+array[i];
aver=sum/10;
return(aver);
}
有兩個班級,分別有35名和30名學生,呼叫一個average函式,分別求這兩個班的學生的平均成績。
#include <stdio.h>
int main()
{ float average(float array[ ],int n);
float score1[5]={98.5,97,91.5,60,55};
float score2[10]={67.5,89.5,99,69.5,77,89.5,76.5,54,60,99.5};
printf(“%6.2f\n”,average(score1,5));
printf(“%6.2f\n”,average(score2,10));
return 0;
}
float average(float array[ ],int n)
{ int i;
float aver,sum=array[0];
for(i=1;i<n;i++)
sum=sum+array[i];
aver=sum/n;
return(aver);
}
用選擇法對陣列中10個整數按由小到大排序。
#include <stdio.h>
int main()
{ void sort(int array[],int n);
int a[10],i;
printf("enter array:\n");
for(i=0;i<10;i++) scanf("%d",&a[i]);
sort(a,10);
printf("The sorted array:\n");
for(i=0;i<10;i++) printf("%d ",a[i]);
printf("\n");
return 0;
}
void sort(int array[],int n)
{ int i,j,k,t;
for(i=0;i<n-1;i++) // i取值0-8
{ k=i;
for(j=i+1;j<n; j++)
if(array[j]<array[k]) k=j;
t=array[k];
array[k]=array[i];
array[i]=t;
}
}
有一個3×4的矩陣,求所有元素中的最大值。
#include <stdio.h>
int main()
{ int max_value(int array[][4]);
int a[3][4]={{1,3,5,7},{2,4,6,8},{15,17,34,12}};
printf(“Max value is %d\n”, max_value(a));
return 0;
}
int max_value(int array[][4])
{ int i,j,max;
max = array[0][0];
for (i=0; i<3; i++)
for(j=0; j<4; j++)
if (array[i][j]>max) max = array[i][j];
return (max);
}
區域性變數和全域性變數
定義變數可能有三種情況:
在函式的開頭定義
在函式內的複合語句內定義
在函式的外部定義
區域性變數
在一個函式內部定義的變數只在本函式範圍內有效
在複合語句內定義的變數只在本複合語句範圍內有效
在函式內部或複合語句內部定義的變數稱為“區域性變數”
全域性變數
在函式內定義的變數是區域性變數,而在函式之外定義的變數稱為外部變數
外部變數是全域性變數(也稱全程變數)
全域性變數可以為本檔案中其他函式所共用
有效範圍為從定義變數的位置開始到本原始檔結束
有一個一維陣列,內放10個學生成績,寫一個函式,當主函式呼叫此函式後,能求出平均分、最高分和最低分。
#include <stdio.h>
float Max=0,Min=0;
int main()
{ float average(float array[ ],int n);
float ave,score[10]; int i;
printf("Please enter 10 scores:\n");
for(i=0;i<10;i++)
scanf("%f",&score[i]);
ave=average(score,10);
printf("max=%6.2f\nmin=%6.2f\n
average=%6.2f\n",Max,Min,ave);
return 0;
}
float average(float array[ ],int n)
{ int i; float aver,sum=array[0];
Max=Min=array[0];
for(i=1;i<n;i++)
{ if(array[i]>Max) Max=array[i];
else if(array[i]<Min) Min=array[i];
sum=sum+array[i];
}
aver=sum/n;
return(aver);
}
動態儲存方式與靜態儲存方式
從變數值存在的時間(即生存期)觀察,變數的儲存有兩種不同的方式:靜態儲存方式和動態儲存方式
靜態儲存方式是指在程式執行期間由系統分配固定的儲存空間的方式
動態儲存方式是在程式執行期間根據需要進行動態的分配儲存空間的方式
-
自動變數(auto變數)
區域性變數,如果不專門宣告儲存類別,都是動態地分配儲存空間的
呼叫函式時,系統會給區域性變數分配儲存空間,呼叫結束時就自動釋放空間。因此這類區域性變數稱為自動變數
自動變數用關鍵字auto作儲存類別的宣告
int f(int a)
{
auto int b,c=3;
┇
}
-
靜態區域性變數(static區域性變數)
希望函式中的區域性變數在函式呼叫結束後不消失而繼續保留原值,即其佔用的儲存單元不釋放,在下一次再呼叫該函式時,該變數已有值(就是上一次函式呼叫結束時的值),這時就應該指定該區域性變數為“靜態區域性變數”,用關鍵字static進行宣告
例7.16 考察靜態區域性變數的值。
#include <stdio.h>
int main()
{ int f(int);
int a=2,i;
for(i=0;i<3;i++)
printf(“%d\n”,f(a));
return 0;
}
int f(int a)
{ auto int b=0;
static c=3;
b=b+1;
c=c+1;
return(a+b+c);
}
每呼叫一次,開闢新a和b,但c不是
輸出1到5的階乘值。
#include <stdio.h>
int main()
{ int fac(int n);
int i;
for(i=1;i<=5;i++)
printf(“%d!=%d\n”,i,fac(i));
return 0;
}
int fac(int n)
{ static int f=1;
f=f*n;
return(f);
}
若非必要,不要多用靜態區域性變數
-
暫存器變數(register變數)
一般情況下,變數(包括靜態儲存方式和動態儲存方式)的值是存放在記憶體中的
暫存器變數允許將區域性變數的值放在CPU中的暫存器中
現在的計算機能夠識別使用頻繁的變數,從而自動地將這些變數放在暫存器中,而不需要程式設計者指定
全域性變數都是存放在靜態儲存區中的。因此它們的生存期是固定的,存在於程式的整個執行過程
一般來說,外部變數是在函式的外部定義的全域性變數,它的作用域是從變數的定義處開始,到本程式檔案的末尾。在此作用域內,全域性變數可以為程式中各個函式所引用。
-
在一個檔案內擴充套件外部變數的作用域
外部變數有效的作用範圍只限於定義處到本檔案結束。
如果用關鍵字extern對某變數作“外部變數宣告”,則可以從“宣告”處起,合法地使用該外部變數
呼叫函式,求3個整數中的大者。
#include <stdio.h>
int main()
{ int max( );
extern int A,B,C;
scanf(“%d %d %d”,&A,&B,&C);
printf("max is %d\n",max());
return 0;
}
int A ,B ,C;
int max( )
{ Int m;
m=A>B?A:B;
if (C>m) m=C;
return(m);
}
-
將外部變數的作用域擴充套件到其他檔案
如果一個程式包含兩個檔案,在兩個檔案中都要用到同一個外部變數Num,不能分別在兩個檔案中各自定義一個外部變數Num
應在任一個檔案中定義外部變數Num,而在另一檔案中用extern對Num作“外部變數宣告”
在編譯和連線時,系統會由此知道Num有“外部連結”,可以從別處找到已定義的外部變數Num,並將在另一檔案中定義的外部變數num的作用域擴充套件到本檔案
給定b的值,輸入a和m,求a*b和am的值。
檔案file1.c:
#include <stdio.h>
int A;
int main()
{ int power(int);
int b=3,c,d,m; scanf("%d,%d",&A,&m);
c=A*b;
printf("%d*%d=%d\n",A,b,c);
d=power(m);
printf("%d**%d=%d\n",A,m,d);
return 0;
}
檔案file2.c:
extern A;
int power(int n)
{ int i,y=1;
for(i=1;i<=n;i++)
y*=A;
return(y);
}
-
將外部變數的作用域限制在本檔案中
有時在程式設計中希望某些外部變數只限於被本檔案引用。這時可以在定義外部變數時加一個static宣告。
一般為了敘述方便,把建立儲存空間的變數宣告稱定義,而把不需要建立儲存空間的宣告稱為宣告
內部函式與外部函式
如果一個函式只能被本檔案中其他函式所呼叫,它稱為內部函式。
在定義內部函式時,在函式名和函式型別的前面加static,即:
static 型別名 函式名(形參表)
如果在定義函式時,在函式首部的最左端加關鍵字extern,則此函式是外部函式,可供其他檔案呼叫。
如函式首部可以為
extern int fun (int a, int b)
如果在定義函式時省略extern,則預設為外部函式
有一個字串,內有若干個字元,今輸入一個字元,要求程式將字串中該字元刪去。用外部函式實現。
思想:
分別定義3個函式用來輸入字串、刪除字元、輸出字串
按題目要求把以上3個函式分別放在3個檔案中。main函式在另一檔案中,main函式呼叫以上3個函式,實現題目的要求
#include <stdio.h>
int main()
{ extern void enter_string(char str[]);
extern void delete_string(char str[], char ch);
extern void print_string(char str[]);
char c,str[80];
enter_string(str);
scanf(“%c”,&c);
delete_string(str,c);
print_string(str);
return 0;
}
————————————————————————————————
void enter_string(char str[80])
{ gets(str); }
————————————————————————————————
void delete_string(char str[],char ch)
{ int i,j;
for (i=j=0;str[i]!='\0';i++)
if (str[i]!=ch) str[j++]=str[i];
str[j]='\0';
}
————————————————————————————————
void print_string(char str[])
{ printf("%s\n",str); }