?? 第8章 函 數(shù).txt
字號:
......
return ret_code;
}
在上例中,函數(shù)open_customer_table()是一個外部函數(shù),它可以被任何模塊調(diào)用,而函數(shù)open_customer_indexes()是一個內(nèi)部函數(shù),它永遠不會被其它模塊調(diào)用。之所以這樣說明這兩個函數(shù),是因為函數(shù)open_customer_indexes()只需被函數(shù)open_customer_table()調(diào)用,即只需在上例所示的源文件中使用。
請參見:
8.1 什么時候說明函數(shù)?
8.2 為什么要說明函數(shù)原型?
8.3 一個函數(shù)可以有多少個參數(shù)?
8.5 如果一個函數(shù)沒有返回值,是否需要加入return語句?
在C語言中,用void關(guān)鍵字說明的函數(shù)是沒有返回值的,并且也沒有必要加入return語句。
在有些情況下,一個函數(shù)可能會引起嚴重的錯誤,并且要求立即退出該函數(shù),這時就應(yīng)該加入一個return語句,以跳過函數(shù)體內(nèi)還未執(zhí)行的代碼。然而,在函數(shù)中隨意使用return語句是一種不可取的編程習(xí)慣,因此,退出函數(shù)的操作通常應(yīng)該盡量集中和簡潔。
請參見:
8.8 用PASCAL修飾符說明的函數(shù)與普通C函數(shù)有什么不同?
8.9 exit()和return有什么不同?
8.6 怎樣把數(shù)組作為參數(shù)傳遞給函數(shù)?
在把數(shù)組作為參數(shù)傳遞給函數(shù)時,有值傳遞(by value)和地址傳遞(by reference)兩種方式。在值傳遞方式中,在說明和定義函數(shù)時,要在數(shù)組參數(shù)的尾部加上一對方括號([]),調(diào)用函數(shù)時只需將數(shù)組的地址(即數(shù)組名)傳遞給函數(shù)。例如,在下例中數(shù)組x[]是通過值傳遞方式傳遞給byval_func()函數(shù)的:
# include <atdio.h>
voidbyval_func(int[]); /*the byval_func() function is passed an
integer array by value * /
void main (void);
void main (void)
{
int x[10];
int y;
/* Set up the integer array. * /
for (y=0; y<10; y++)
x[y] = y;
/* Call byval_func() ,passing the x array by value. * /
byval_func(x);
}
/* The byval_function receives an integer array by value. * /
void byval_func(int i[])
{
int y;
/* print the content: of the integer array. * /
for (y=0; y<10; y++)
printf("%d\n", i[y]);
}
在上例中,定義了一個名為x的數(shù)組,并對它的10個元素賦了初值。函數(shù)byval_func()的說明如下所示:
intbyval_func(int []);
參數(shù)int[]告訴編譯程序byval_func()函數(shù)只有一個參數(shù),即一個由int類型值組成的數(shù)組。在調(diào)用byval_func()函數(shù)時,只需將數(shù)組的地址傳遞給該函數(shù),即:
byval_func(x);
在值傳遞方式中,數(shù)組x將被復(fù)制一份,復(fù)制所得的數(shù)組將被存放在棧中,然后由byval_func()函數(shù)接收并打印出來。由于傳遞給byal_func()函數(shù)的是初始數(shù)組的一份拷貝,因此在byval_func()函數(shù)內(nèi)部修改傳遞過來的數(shù)組對初始數(shù)組沒有任何影響。
值傳遞方式的開銷是非常大的,其原因有這樣幾點:第一,需要完整地復(fù)制初始數(shù)組并將這份拷貝存放到棧中,這將耗費相當(dāng)可觀的運行時間,因而值傳遞方式的效率比較低;第二,初始數(shù)組的拷貝需要占用額外的內(nèi)存空間(棧中的內(nèi)存);第三,編譯程序需要專門產(chǎn)生一部分用來復(fù)制初始數(shù)組的代碼,這將使程序變大。
地址傳遞方式克服了值傳遞方式的缺點,是一種更好的方式。在地址傳遞方式中,傳遞給函數(shù)的是指向初始數(shù)組的指針,不用復(fù)制初始數(shù)組,因此程序變得精練和高效,并且也節(jié)省了棧中的內(nèi)存空間。在地址傳遞方式中,只需在函數(shù)原型中將函數(shù)的參數(shù)說明為指向數(shù)組元素數(shù)據(jù)類型的一個指針。請看下例:
# include <atdio. h>
void conat_func(const int* );
void main (void);
void main(void)
{
int x[10];
int y;
/* Set up the integer array. * /
for (y=0; y<10; y++)
x[y] = y;
/* Call conat_func(), passing the x array by reference. */
conat_func(x);
}
/*The const_function receives an integer array by reference.
Notice that the pointer i? declared aa const, which renders
it unmodif table by the conat_funcO function. * /
void conat_func(conat int* i)
{
int y;
/ * print the contents of the integer array. * /
for (y=0; y<10; y++)
printf(""%d\n", *(i+y));
}
在上例中,同樣定義了一個名為x的數(shù)組,并對它的10個元素賦了初始值。函數(shù)const_func()的說明如下所示:
int const_func(const int·);
參數(shù)constint·告訴編譯程序const_func()函數(shù)只有一個參數(shù),即指向一個int類型常量的指針。在調(diào)用const_func()函數(shù)時,同樣只需將數(shù)組的地址傳遞給該函數(shù),即:
const_rune(x);
在地址傳遞方式中,沒有復(fù)制初始數(shù)組并將其拷貝存放在棧中,const_rune()函數(shù)只接收到指向一個int類型常量的指針,因此在編寫程序時要保證傳遞給const_func()函數(shù)的是指向一個由int類型值組成的數(shù)組的指針。const修飾符的作用是防止const_func()函數(shù)意外地修改初始數(shù)組中的某一個元素。
地址傳遞方式唯一的不足之處是必須由程序本身來保證將一個數(shù)組傳遞給函數(shù)作為參數(shù),例如,在函數(shù)const—rune()的原型和定義中,都沒有明確指示該函數(shù)的參數(shù)是指向一個由int類型值組成的數(shù)組的指針。然而,地址傳遞方式速度快,效率高,因此,在對運行速度要求比較高時,應(yīng)該采用這種方式。
請參見:
8.8用PASCAL修飾符說明的函數(shù)與普通C函數(shù)有什么不同?
8.7 在程序退出main()函數(shù)之后,還有可能執(zhí)行一部分代碼嗎?
可以,但這要借助C庫函數(shù)atexit()。利用atexit()函數(shù)可以在程序終止前完成一些“清理”工作——如果將指向一組函數(shù)的指針傳遞給atexit()函數(shù),那么在程序退出main()函數(shù)后(此時程序還未終止)就能自動調(diào)用這組函數(shù)。下例的程序中就使用了atexit()函數(shù):
# include <stdio.h>
# include <atdlib. h>
void close_files(void);
void print_regiatration_message(void);
int main(int, char ** );
int main (int argc, char** argv)
{
atcxitCprint_regiatration_message);
atexit(cloae_files) ;
while (rec_count <max_recorda)
{
process_one_record ( );
}
exit (0);
}
在上例中,通過atexit()函數(shù)指示程序在退出main()函數(shù)后自動調(diào)用函數(shù)close_files()
和print_registration_message(),分別完成關(guān)閉文件和打印登記消息這兩項工作。
在使用atexit()函數(shù)時你要注意這樣兩點:第一,由atexit()函數(shù)指定的要在程序終止前
執(zhí)行的函數(shù)要用關(guān)鍵字void說明,并且不能帶參數(shù);第二,由atexit()函數(shù)指定的函數(shù)在入棧
時的順序和調(diào)用atexit()函數(shù)的順序相同,即它們在執(zhí)行時遵循后進先出(LIFO)的原則。例
如,在上例中,由atexit()函數(shù)指定的函數(shù)在入棧時的順序如下所示:
atexit(print_registration_message);
atexit(close_files);
根據(jù)LIFO原則,程序在退出main()函數(shù)后將先調(diào)用close_files()函數(shù),然后調(diào)用print_
registration_message()函數(shù)。
利用atexit()函數(shù),你可以很方便地在退出main()函數(shù)后調(diào)用一些特定的函數(shù),以完成一
些善后工作(例如關(guān)閉程序中用到的數(shù)據(jù)文件)。
請參見:
8.9 exit()和return有什么不同?
8.8 用PASCAL修飾符說明的函數(shù)與普通C函數(shù)有什么不同?
用PASCAL修飾符說明的函數(shù)的調(diào)用約定與普通函數(shù)有所不同。對于普通的C函數(shù),參數(shù)是自右至左傳遞的,而根據(jù)PASCAL調(diào)用約定,參數(shù)是自左至右傳遞的。下例是一個普通的C函數(shù):
int regular_func(int,char*,long);
根據(jù)普通C函數(shù)的調(diào)用約定,函數(shù)參數(shù)入棧時的順序為自右至左,因此,在調(diào)用regular()函數(shù)時,其參數(shù)的入棧順序如下所示:
long
char·
int
當(dāng)regular_func()函數(shù)返回時,調(diào)用regular_func()函數(shù)的函數(shù)負責(zé)恢復(fù)棧。
下例是一個用PASCAL修飾符說明的函數(shù):
int PASCAL pascal_func(int,char *,long);
根據(jù)PASCAL調(diào)用約定,函數(shù)參數(shù)入棧時的順序為自左至右,因此,在調(diào)用‘pascal—func()函數(shù)時,其參數(shù)的入棧順序如下所示:
int
char *
long
當(dāng)pascal_func()函數(shù)返回時,調(diào)用pascal_func()函數(shù)的函數(shù)負責(zé)恢復(fù)棧指針。
采用PASCAL調(diào)用約定的函數(shù)比普通C函數(shù)的效率要高一些——前者的函數(shù)調(diào)用要稍快一些。MicrosoftWindows就是一個采用PASCAL調(diào)用約定的操作環(huán)境的例子,WindowsSDK中有數(shù)百個用PASCAL修飾符說明的函數(shù)。
當(dāng)Windows的第一個版本于80年代末期編寫成功時,使用PASCAL修飾符能明顯提高程序的執(zhí)行速度。現(xiàn)在,計算機的運行速度已經(jīng)相當(dāng)快,PASCAL修飾符對程序運行速度的作用已經(jīng)很小了。事實上,Microsoft在其WindowsNT操作系統(tǒng)中已經(jīng)放棄了PASCAL調(diào)用約定。
在大多數(shù)情況下,采用PASCAL調(diào)用約定對程序的運行速度幾乎沒有明顯的作用,因此,采用普通C函數(shù)的調(diào)用約定完全能滿足編程要求。但是,當(dāng)幾個毫秒的運行時間對你的程序也很重要時,你就應(yīng)該用PASCAL修飾符來說明你的函數(shù)。
請參見:
8.6怎樣把數(shù)組作為參數(shù)傳遞給函數(shù)?
8.9 exit()和return有什么不同?
用exit()函數(shù)可以退出程序并將控制權(quán)返回給操作系統(tǒng),而用return語句可以從一個函數(shù)中返回并將控制權(quán)返回給調(diào)用該函數(shù)的函數(shù)。如果在main()函數(shù)中加入return語句,那么在執(zhí)行這條語句后將退出main()函數(shù)并將控制權(quán)返回給操作系統(tǒng),這樣的一條return語句和exit()函數(shù)的作用是相同的。下例是一個使用了exit()函數(shù)和return語句的程序:
#include <stdio.h>
#include <stdlib.h>
int main (int, char** );
int do_processing (void);
int do_something_daring();
int main (int argc, char** argv)
{
int ret_code;
if (argc <3)
{
printf ("Wrong number of arguments used ! \n");
/* return 1 to the operating system * /
exit(1);
}
ret_code = do_processing ();
......
/* return 0 to the operating system * /
exit(0);
}
int do_processing(void)
{
int rc;
rc = do_aomcthing_daring();
if (rc == ERROR)
{
printf ("Something fiahy ia going on around here... *\n);
/* return rc to the operating syatem * /
exit (re);
}
/* return 0 to the calling function * /
return 0;
}
在上例的main()函數(shù)中,如果argc小于3,程序就會退出。語句“exit(1)”指示程序在退出時將數(shù)字1返回給操作系統(tǒng)。操作系統(tǒng)有時會根據(jù)程序的返回值進行一些相關(guān)的操作,例如許多DOS批處理文件會通過一個名為ERRORLEVEL的全局變量來檢查可執(zhí)行程序的返回值。
請參見:
8.5如果一個函數(shù)沒有返回值,是否需要加入return語句?
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -