?? 第8章 函 數.txt
字號:
C語言編程常見問題解答
發表日期:2003年10月2日 已經有2085位讀者讀過此文
第8章 函 數
函數是C語言的基本構件,要成為一個優秀的程序員,必須很好地掌握函數的編寫方法和使用方法。本章將集中討論與函數有關的問題,例如什么時候說明函數,怎樣說明函數,使用函數的種種技巧,等等。
在閱讀本章時,請回憶你曾編寫過的函數,看看你是否已盡可能提高了這些函數的效率;如果沒有,請應用本章所介紹的一些技術,以提高你的程序的速度和效率。此外,請注意本章所介紹的一些實用編程技巧,其中的一些例子能有效地幫助你提高編寫函數的技能。
8. 1 什么時候說明函數?
只在當前源文件中使用的函數應該說明為內部函數(static),內部函數應該在當前源文件中說明和定義。對于可在當前源文件以外使用的函數,應該在一個頭文件中說明,要使用這些函數的源文件要包含這個頭文件。例如,如果函數stat_func()只在源文件stat.c中使用,應該這樣說明:
/* stat.c */
# include <atdio.h>
atatic int atat_func(int,int); /* atatic declaration of atat-funcO */
void main (void);
viod main (void)
{
......
rc=stat_func(1,2);
......
}
/* definition (body) of stat-funcO */
static int stat-funcdnt argl,int arg2)
{
return rc;
}
在上例中,函數stat_func()只在源文件stat.c中使用,因此它的原型(或說明)在源文件stat.c以外是不可見的,為了避免與其它源文件中可能出現的同名函數發生沖突,應該將其說明為內部函數。
在下例中,函數glob_func()在源文件global.c中定義和使用,并且還要在源文件extern,c中使用,因此應該在一個頭文件(本例中為proto.h)中說明,而源文件global.c和extern.c
中都應包含這個頭文件。
File: proto.h
/* proto.h */
int glob_func(int,int); /* declaration of the glob-funcO function * /
File: global. c
/* global. c */
# include <stdio.h>
# include "proto. h" /*include this file for the declaration of
glob_func() */
viod main(void);
viod main (void)
{
rc_glob_func(l,2);
}
/* deHnition (body) of the glob-funcO function */
int glob_func(int argl,int arg2)
{
return rc;
}
File extern. c
/* extin.c */
# include <atdio.h>
# include "proto. h" /*include thia file for the declaration of
glob_func() */
void ext_func(void);
void ext_func(void)
{
/* call glob_func(), which ia deHncd in the global, c source file * /
rc=glob_func(10,20);
}
在上例中,在頭文件proto.h中說明了函數glob_func(),因此,只要任意一個源文件包含了該頭文件,該源文件就包含了對函數glob_func()的說明,這樣編譯程序就能檢查在該源文件中glob_func()函數的參數和返回值是否符合要求。請注意,包含頭文件的語句總是出現在源文件中第一條說明函數的語句之前。
請參見;
8.2 為什么要說明函數原型?
8.3 一個函數可以有多少個參數?
8.4 什么是內部函數?
8.2 為什么要說明函數原型?
函數原型能告訴編譯程序一個函數將接受什么樣的參數,將返回什么樣的返回值,這樣編譯程序就能檢查對函數的調用是否正確,是否存在錯誤的類型轉換。例如,現有以下函數原型;
int some_func(int,char·,long);
編譯程序就會檢查所有對該函數的引用(包括該函數的定義)是否使用了三個參數并且返回一個int類型的值。如果編譯程序發現函數的調用或定義與函數原型不匹配,編譯程序就會報告出錯或警告消息。例如,對上述函數原型來說,當編譯程序檢查以下語句時,就會報告出錯或警告消息:
x = some_func(l); /* not enough arguments passed */
x = somc_funcC*HELLOl", 1, "DUDE:"); /* wrong type of arguments used */
x = aome_funcd, sir, 2879, "T"); /* too many arguments passed */
下例中的函數調用同樣是不正確的,因為函數some_func()的返回值不是一個long*類型的值。
lValue=some_func(1,str,2879); /*some_rune()returns anint,not a long* */
同樣,編譯程序還能檢查函數的定義(或函數體)是否與函數原型匹配。例如,當編譯程序檢查以下函數定義時,就會報告出錯或警告消息:
int some_func(char *string,longlValue,int iValue) /* wrong order Of
{ parameters */
......
}
總之,在源文件中說明函數原型提供了一種檢查函數是否被正確引用的機制。目前許多流行的編譯程序都會檢查被引用的函數的原型是否已在源文件中說明過,如果沒有,就會發出警告消息。
請參見:
8.1什么時候說明函數?
8.3一個函數可以有多少個參數?
8.4什么是內部函數?
8.3 一個函數可以有多少個參數?
一個函數的參數的數目沒有明確的限制,但是參數過多(例如超過8個)顯然是一種不可取的編程風格。參數的數目直接影響調用函數的速度,參數越多,調用函數就越慢。另一方面,參數的數目少,程序就顯得精練、簡潔,這有助于檢查和發現程序中的錯誤。因此,通常應該盡可能減少參數的數目,如果一個函數的參數超過4個,你就應該考慮一下函數是否編寫得當。
如果一個函數不得不使用很多參數,你可以定義一個結構來容納這些參數,這是一種非常好的解決方法。在下例中,函數print_report()需要使用10個參數,然而在它的說明中并沒有列出這些參數,而是通過一個RPT_PARMS結構得到這些參數。
# include <atdio. h>
typedef struct
(
int orientation ;
char rpt_name[25];
char rpt_path[40];
int destination;
char output_file[25];
int starting_page;
int ending_page;
char db_name[25];
char db_path[40];
int draft_quality;
)RPT_PARMS;
void main (void);
int print_report (RPT_PARMS* );
void main (void)
{
RPT_PARMS rpt_parm; /*define the report parameter
structure variable * /
/* set up the report parameter structure variable to pass to the
print_report 0 function */
rpt_parm. orientation = ORIENT_LANDSCAPE;
rpt_parm.rpt_name = "QSALES.RPT";
rpt_parm. rpt_path = "Ci\REPORTS"
rpt_parm. destination == DEST_FILE;
rpt_parm. output_file = "QSALES. TXT" ;
rpt_parm. starting_page = 1;
rpt_pann. ending_page = RPT_END;
rpt_pann.db_name = "SALES. DB";
rpt_parm.db_path = "Ci\DATA";
rpt_pann. draft_quality = TRUE;
/*call the print_report 0 function; paaaing it a pointer to the
parameteM inatead of paMing it a long liat of 10 aeparate
parameteM. * /
ret_code = print_report(cu*pt_parm);
}
int print_report(RPT_PARMS*p)
{
int rc;
/*acccM the report parametcra paaaed to the print_report()
function */
oricnt_printcr(p->orientation);
Kt_printer_quality((p->draft_quality == TRUE) ? DRAFT ; NORMAL);
return rc;
}
上例唯一的不足是編譯程序無法檢查引用print_report()函數時RPT_PARMS結構的10個成員是否符合要求。
請參見:
8.1 什么時候說明函數?
8.2 為什么要說明函數原型?
8.3 什么是內部函數?
8.4 什么是內部函數?
內部函數(用static關鍵字說明)是作用域只限于說明它的源文件的函數。作用域指的是函數或變量的可見性。如果一個函數或變量在說明它的源文件以外也是可見的,那么就稱它具有全局或外部作用域;如果一個函數或變量只在說明它的源文件中是可見的,那么就稱它具有局部或內部作用域。
內部函數只能在說明它的源文件中使用。如果你知道或希望一個函數不會在說明它的源文件以外被使用,你就應該將它說明為內部函數,這是一種好的編程習慣,因為這樣可以避免與其它源文件中可能出現的同名函數發生沖突。
請看下例:
#include <stdio.h>
int open_customer_table(void); /*global function, callable from
any module * /
static int open_customer_indexes(void); /*local function, used only in
this module * /
int open_customer_table(void)
{
int ret_code;
/* open the customer table * /
......
if (ret_code == OK)
{
ret_code = opcn_customer_indexes();
}
return ret_code;
}
static int open_customer_indexes(void)
{
int ret_code;
/* open the index files used for this table * /
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -