副标题#e#
1、什么是函数
在C语言中,完成一个特定任务的措施段、子措施称作函数,在一个完整的C措施中,凡是是由许多个函数构成的,每一个函数完成其指定的任务。
2、什么是函数原型
一个函数有函数名、函数的返回值及返回值的范例、函数的参数及参数的范例。对函数的所有这些特征予以描写称作函数的原型。函数原型一般放在整个措施文件的开始部门(内部函数)。对付可在当前源文件以外利用的函数,应该在一个头文件中说明,要利用这些函数的源文件必需包括这个头文件。
3、什么是函数的返回值
当一个函数执行完之后通报给挪用函数一个值,称为返回值。是否需要返回一个值给挪用函数,详细环境视措施中的需要而定,有时基础就不需要返回一个值给挪用函数。
4、为什么要说明函数的原型
函数原型能汇报编译措施一个函数接管什么样的参数,将返回什么样的返回值,这样编译措施就能检点对函数的挪用是否正确,是否存在错误的范例转换。例:
int some_func(int,char *,long);
编译措施应会查抄所有对该函数的挪用(包罗该函数的界说)是否利用了三个参数而且返回一个int范例的值。假如编译措施发明函数的挪用或界说与函数原型不匹配,编译措施应会陈诉堕落或告诫信息。譬喻对上述函数原型来说,当编译措施查抄以下语句时,就会陈诉堕落或告诫动静:
x=some_func(1); /*参数个数少*/
x=some_func("HELLO!",1,"DUDE!"); /*参数范例错误*/
x=some_func(1,str,2879,"T"); /*参数太多*/
下面的函数挪用同样是不正确的,因为函数some_func()的返回值不是一个long *范例的值。
lValue=some_func(1,str,2879); /*函数返回值应该是int而不是long型。*/
同样编译措施还能查抄函数的界说(或函数体)是否与函数原型匹配。譬喻当编译措施查抄以下函数界说时,应会陈诉堕落或告诫信息:
int some_func(char * string,,long lValue,int iValue) /*参数的位置差池*/
总之,在源文件中说明函数原型提供了一种查抄函数是否被正确引用的机制。今朝很多风行的编译措施城市查抄被引用的函数的原型是否已在源文件中说明过,假如没有,就会发出告诫信息。
#p#副标题#e#
5、一个函数可以有几多个参数
一个函数的参数的数目没有明晰的限制,可是参数过多(譬喻高出8个)显然是一种不行取的编程气势气魄。参数的数目直接影响到挪用函数的速度,参数越多,函数挪用越慢。另一方面,函数的参数少,措施就显得简练、简便,这有助于查抄和发明措施中的错误,因此凡是应该只管淘汰参数的数目,假如一个函数的参数高出4 个,就应该思量一下函数是否编写恰当。假如一个函数不得不利用许多参数,可以界说一个布局来容纳这些参数,这是一种很是好的办理步伐。
在下例中,函数print_report()需要利用10个参数,然而在它的参数说明中并没有列出这些参数,而是通过一个RPT_PARMS的布局获得这些参数。
#include<stdio.h>
typedef struct
{
int orientation;
char rpt_name[25];
char rpt_path[40];
int destination;
char output_file[25];
int starting_page;
char ending_page;
char db_name[25];
char db_path[40];
int draft_quality;
}RPT_PARMS;
int print_report(RPT_PARMS *);
void main(void)
{
RPT_PARMS rpt_parm;
...
...
rpt_parm.orientation=ORIENT_LANDSCAPE;
rpt_parm.rpt_name="QSALES.RPT";
rpt_parm.rpt_path="C:\REPORTS";
rpt_parm.destingation=DEST_FILE;
rpt_parm.output_file="QSALES.TXT";
rpt_parm.starting_page=1;
rpt_parm.ending_page=RPT_END;
rpt_parm.db_name="SALES.DB";
rpt_parm.db_path="C:\DATA";
rpt_parm.draft_quality=TRUE;
ret_code=print_report(&rpt_parm);
....
....
}
int print_report(RPT_PARMS *p)
{
int rc;
....
....
orient_printer(p->orientation);
set_printer_quality(p->draft_quality==TRUE)?DRAFT:NORMAL);
....
....
return rc;
}
上例独一不敷的是编译措施无法查抄引用print_report()函数时RPT_PARMS布局的10个成员是否切合要求。
6、什么是内部函数
#p#分页标题#e#
内部函数用static来说明,是浸染域只限于说明它的源文件的函数。浸染域指的是函数或变量的可见性。假如一个函数或变量在说明它的源文件以外也是可见的,那么就称它有全局或外部浸染域果一个函数或变量在说明它的源文件中是可见的,那么就称它具有局部或内部浸染域。
内部函数只能在说明它的源文件中利用。假如你呈但愿一个函数不会在说明它的源文件以外被利用,就应该将它说明为内部函数,这样做是一个好的编程习惯,因为这样可以制止与其它源文件中的同名函数产生斗嘴。
例:
#include<stdio.h>
int open_customer_table(void);
static int open_customer_indexes(void);
int open_customer_table(void)
{
int ret_code;
....
....
if(ret_code==OK)
{
ret_code=open_customer_indexes();
}
return ret_code;
}
static int open_customer_indexes(void)
{
int ret_code;
....
....
return ret_code;
}
在上例中,函数open_customer_table()是一个外部函数,它可以被任何模块挪用,而函数open_customer_indexes()是一个内部函数,它永远不会被其它模块挪用。之所以这样说明这二个函数,是因为函数open_customer_indexes()只需被函数open_customer_table()挪用,即只需在上例的源文件中利用。
7、假如一个函数没有返回值,是否需要插手return语句
在C语言中,用void要害字说明的函数是没有返回值的,而且也没有须要插手return语句。在有些环境下,一个函数大概会引起严重的错误,而且要当即退出该函数,这时就应该插手return语句,以跳过函数体内还未执行到的代码。可是在void函数中随意插手return语句是一个欠好的编程习惯,困此,在void函数中退出函数的操纵应该只管会合和简捷。
8、奈何把数组作为参数传给函数
在把数组作为参数传给函数时,有值通报(传值 by value)和地点通报(传址 by reference)二种方法。在值通报方法中,在说明和界说函数时,要在数组参数尾部加上一对方括号,挪用函数时只需要将数组的地点(即数组名)通报给数组。
例:在下例中数组x[]是通过值通报方法通报给byval_func()函数的。
#include<stdio,h>
void byval_func(int[]); /*这个函数的参数是一个int型数组*/
void main(void)
{
int x[10];
int y;
for(y=0;y<10;y++) /*初始化整型数组*/
x[y]=y;
byval_func(x); /*把数组名放在参数里,留意是值通报*/
}
void byval_func(int i[])
{
int y;
for(y=1;y<11;y++)
{
i[y]=y;
printf("%d"\n",i[y]);
}
}
在上例中,界说了一个名为x的数组,并对它的10个元素赋了初值,函数byval_func()的说明如下所示:
int byval_func(int[]);
参数int[]汇报编译措施byval_func()只有一个参数,即一个int范例值构成的数组,在挪用byval_func()函数时,只需将数组的地点通报给该函数,即:
byval_func(x);
在值通报方法中,数组x将被复制一份,复制所得的数组将被存放在栈中,然后由byval_func()函数吸收并打印出来。由于通报给byval_func()函数的是初始数组的一份考贝,因此在byval_func()函数内部修改通报过来的数组对初始数组没有任何影响。
值通报方法的开销长短常大的,其原因有这样几点:第一,需要完整地复制初始数组并将这份考贝存放到栈中,这将淹灭相当长的时间,因而值通报方法的效率较量低二,初始数组的考贝需要占用特另外内存空间(栈中的内存)三,编译措施需要专门发生一部门用来复制初始数组的代码,这将使措施变大。
地点通报方法降服了值通报方法的缺点,是一种更好的方法。在地点通报方法中,通报给函数的是指向初始数组的指针,不消复制初始数组,因此措施变得简练和高效,而且也节减了内存和栈空间。在地点通报方法 中,只需在函数原型中将函数的参数说明为指向数组元素数据范例 的一个指针。
例:
#p#分页标题#e#
#include<stdio.h>
void const_func(const int *);
void main(void)
{
itn x[10];
int y;
for(y=0;y<10;y++)
x[y]=y;
const_func(x);
}
void const_func(const int *i)
{
int y;
for(y=1;y<11;y++)
{
i[y]=y;
printf("%d\n",*(i+y));
}
}
在上例中,同样界说了一个名为x的数组,并对它的10个元素赋了初值。函数const_func()的说明如下所示:
int const_func(const int *);
参数const int *汇报编译措施const_func()函数只有一个参数,即指向一个int范例常量的指针。在挪用const_func()函数时,同样只需将数组的地点通报给该函数,即:
const_func(x);
在地点通报方法中,没有复制初始数组并将其考贝存放在栈中,const_func()函数只吸收到指向一个int 范例常量的指针,因此在编写措施时要担保通报给const_func()函数的是一个由int范例值构成的数组的指针。const修饰符的浸染是防备const_func()函数意外地修改初始数组中的某一个元素。
地点通报方法独一不敷的是必需由措施自己来担保将一个数组通报给函数作为参数,譬喻在函数const_func()的原型和界说中,都没有明晰指示该函数的参数是指向一个由int范例值构成的数组的指针。可是,地点通报方法速度快,效率高,因此在对运行速度要求比效高时,应访回收这种方法。