如何編寫有多個返回值的C語言函式
1引言
筆者從事C語言教學多年,在教學中學生們常常會問到如何編寫具有多個返回值的C語言函式。編寫有多個返回值的函式是所有C語言教材裡均沒有提到的知識點,但在實際教學與應用的過程中我們都有可能會遇到這樣的問題。有學生也嘗試了不少方法:如把多個需要返回的值作相應的處理後變成一個可以用return語句返回的資料,再在主調函式中拆開返回的資料使之變成幾個值;或者把需要返回多個值的一個函式分開幾個函式去實現多個值的返回。這些方法雖然最終都能實現返回要求的多個值,但從程式演算法的合理性與最優化方面去考慮,顯然不理想。我們知道C語言函式的返回值是通過函式中的return語句來實現的,可是每呼叫一次函式,return語句只能返回一個值。那麼當我們希望從一個函式中返回多個值時,用什麼方法去實現比較合理呢?在教學過程中,我建議學生跳出對return語句的定勢思維,一步步引導學生通過幾種間接方式實現多個返回值的C語言函式。以下是筆者在教學過程中引導學生採用的三種不同方法編寫多個返回值的C語言函式。
2方法1:利用全域性變數
分析:全域性變數作為C語言的一個知識點,雖然我們都瞭解它的特點,但在實際教學過程中應用得並不是很多。由於全域性變數的作用域是從定義變數開始直到程式結束,而對於編寫有多個返回值的C語言函式,我們可以考慮把要返回的多個值定義成全域性變數。當函式被呼叫時,全域性變數被更改,我們再把更改後的全域性變數值應用於主調函式中。函式被呼叫後被更改後的全域性變數值即為函式的數個返回值。下面以一個例項演示該方法的應用。
例項1:編寫函式求3個數中的最大值與最小值。
方法:把最大值、最小值分別定義成2個全域性變數max、min,在使用者自定義函式中把求出來的最大值與最小值分別賦給全域性變數max、min。函式呼叫完畢後全域性變數的max、min值即儲存了函式要求返回的值。程式參考程式碼如下:
#include "stdio.h"
#include "conio.h"
int max,min;/*定義兩個全域性變數用於儲存函式返回值*/
void max_min(int a,int b,int c) /*定義求最大最小值的函式*/
{max=min=a; /*初始化最大最小值*/
if(max if(max if(min>b)min=b;
if(min>c)min=c;
}
main()
{int x,y,z;
printf(" 請輸入3個整數:\n");
scanf("%d,%d,%d",&x,&y,&z);
max_min(x,y,z) ;/*呼叫求最大值與最小值的函式*/
printf("三個數中的最大值為:%d;最小值為:%d",max,min);/*輸出最大值與最小值*/
getch();
}
除錯結果如下:
請輸入3個整數:
5,-6,2
三個數中的最大值為:5;最小值為:-6
注意:該方法雖然可以實現有多個返回值的函式,但由於全域性變數不能保證值的正確性(因為其作用域是全域性,所以程式範圍內都可以修改它的值,如果出現錯誤將非常難以發現),並且全域性變數增加了程式間模組的耦合,所以該方法要慎用。
3方法2:傳遞陣列指標
分析:在教學過程中,我們知道C語言函式引數的傳遞方式有值傳遞與地址傳遞。當進行值傳遞時,主調函式把實參的值複製給形參,形參獲得從主調函式傳遞過來的值執行函式。在值傳遞過程中被調函式引數值的更改不能導致實參值的更改。而如果是地址傳遞,由於傳遞過程中從實參傳遞過來的是地址,所以被調函式中形參值的更改會直接導致實參值的更改。因此,我們可以考慮把多個返回值作為陣列元素定義成一個數組的形式,並使該陣列的地址作為函式的形式引數,以傳址方式傳遞陣列引數。函式被呼叫後,形引數組元素改變導致實參改變,我們再從改變後的實引數組元素中獲得函式的多個返回值。以下例項演示該方法的應用。
例項2:編寫函式求一維整形陣列的最大值與最小值,並把最大值與最小值返回給主調函式。
方法:以指標方式傳遞該一維陣列的地址,然後把陣列的最大值與陣列的第一個元素交換,把陣列的最小值與最後一個元素交換。函式被呼叫完畢後,實引數組中的第一元素為陣列的最大值,實引數組中最後一個元素為陣列的最小值,從而實現返回陣列的最大值與最小值的功能。程式參考程式碼如下:
#include "stdio.h"
#include "conio.h"
void max_min(int *ptr,int n) /*定義求陣列最大值最小值的函式,傳遞陣列指標*/
{int i,j,k;/*j儲存最大值所在位置,k儲存最小值所在位置*/
int *temp;/*用於交換位置*/
*temp=*ptr;
for(i=0;i {
if(*ptr<*(ptr+i))/*最大值與第一個元素進行交換*/
{
k=i;
*temp=*ptr;
*ptr=*(ptr+k);
*(ptr+k)=*temp ;
}
if(*(ptr+n-1)>*(ptr+i))/*最小值與最後一個元素進行交換*/
{
j=i;
*temp =*(ptr+n-1);
*(ptr+n-1)=*(ptr+j);
*(ptr+j)= *temp ;}
}
}
/*呼叫最大最小值函式*/
main()
{
int A[6],i;
for(i=0;i<6;i++)
scanf("%d",&A[i]);
max_min(A,6);
printf("max=%d, min=%d\n \n",A[0],A[5]);
getch();
}
除錯結果如下:
請輸入6個整形數,以空格隔開:
5 8 9 32 -6 4
max=32,min=-6
注意:該方法適用於多個返回值的資料型別一致的情況。當返回值資料型別不一致時,不適用該方法。
4方法3:傳遞結構體指標
分析:結構體作為教學中的一個難點,教材對它介紹的內容並不多,應用的例項更是少之又少,所以學生對於結構體普遍掌握情況不理想。其實,編寫返回多個值的C語言函式,也可以考慮採用結構體的方式去實現。通過方法2,我們知道如果返回的數個數值的資料型別不一致,可以通過定義全域性變數實現有多個返回值的C語言函式,也可以考慮把要求返回的數個值定義成一個結構體,然後同樣以傳遞結構體指標方式把結構體的指標傳遞給形參結構體指標,那麼函式中對形參結構體的修改即是對實參結構體的修改,函式被呼叫後獲取的實參結構體成員即為函式的多個返回值,下面以例項演示該方法的應用。
例項3:編寫一個使用者自定義函式,允許使用者錄入學生的基本資訊(包括學號、姓名、所屬班級、總評成績),並返回這些基本資訊給主調函式。
方法:把學生基本資訊定義成一個結構體,在使用者自定義函式中傳遞該結構體的指標,則自定義函式中對結構體成員的錄入操作即是對實參結構體成員的錄入操作,從而實現多個返回值。參考程式碼如下:
#include "stdio.h"
#include "conio.h"
struct inf{/*定義學生結構體,分別包含成員學號、姓名、班別、總評成績*/
char xh[12];
char name[20];
char class[15];
int chj;
};
main(void)
{
struct inf a1; /*定義學生結構體型別變數*/
void xxxx(struct inf *ptr);
printf("請輸入學號,姓名,班別,總評成績,以空格隔開:\n") ;
xxxx(&a1);/*呼叫函式,以學生結構體型別變數地址作為實參*/
printf("學號:%s,姓名: %s,班別:%s,總評成績:%d",a1.xh, a1.name,a1.class,a1.chj);
getch();
}
void xxxx(struct inf *ptr)/*該函式實現對結構體成員資料的錄入操作*/
{
char xh1[12],name1[20],class1[15];
int chj1;
scanf("%s%s%s%d",xh1,name1,class1,&chj1);
strcpy(ptr->xh,xh1);
strcpy(ptr->name,name1);
strcpy(ptr->class,class1);
ptr->chj=chj1;
}
除錯結果如下:
請輸入學號,姓名,班別,總評成績,以空格隔開:
200102LiLi200185
學號:200102,姓名: LiLi,班別:2001,總評成績:85
注意:當函式要求返回的多個值是相互聯絡的或者返回的多個值資料型別不一致時可以採用該方法。
5結束語
對於以上這三種方法,如果想要返回的數個值資料型別一致,可以考慮採用方法2;而對於不同資料型別的返回值,如果各個數值之間是相互聯絡的,則方法3較為合適;方法1雖然在很多情況下都可以實現多個返回值的C語言函式,但畢竟全域性變數應用過程中有很多危險,要慎重使用。
通過對以上幾種方法的分析講解,在教學過程中,學生再遇到這樣的問題時,就能根據返回值的情況選擇合適的途徑去實現多個返回值的C語言函式。另外,如果再遇到類似的無法用教材知識點去直接解決的問題時,他們基本都能舉一反三地嘗試採用間接方式去解決。
參考文獻
[1] 譚浩強. C程式設計(第二版)[M]. 北京:清華大學出版社,1999.
[2] 薛萬鵬譯. C程式設計教程[M]. 北京:機械工業出版社,2000.
[3] 鄧勁生譯. Visual C++程式設計師實用大全[M]. 北京:中國水利水電出版社,2005.