nbhkdz.com冰点文库

第八讲 C语言函数_图文

时间:2016-03-07

一、函数概述
首先,什么是函数?函数(function)是用于完成特定任务的程序代码的自包 含单元。尽管C中的函数和其他语言中的函数、子程序或子过程等扮演着相同的角 色,但是在细节上会有所不同。某些函数会导致执行某些动作,比如printf()可使 数据呈现在屏幕上;还有一些函数能返回一个值以供程序使用,如strlen ()将指 定字符串的长度传递给程序。一般来讲,一个函数可同时具备以上两种功能。

为什么使用函数?第一,函数的使用可以省去重复代码的编写。如果程序中需 要多次使用某种特定的功能,那么只需要编写一个合适的函数即可。程序可以在任 何需要的地方调用该函数,并且同一个函数可以在不同的程序中调用,就像在许多 程序中需要使用putchar()一样。第二,即使某种功能在程序中只使用一次,将其 以函数的形式实现也是有必要的,因为函数使得程序更加模块化,从而有利于程序 的阅读,修改和完善。

示例程序
我们需要掌握如何正确定义函数、如何调用函数和如何建立函数间的通信。为 了让您对这些有一个清晰的思路,我们首先来看一个非常简单的例子:
#include<stdio.h> #define NAME "No.83 Middle School" #define ADDRESS "151 Xianning zhonglu" #define PLACE "Xi'an Shannxi" #define WIDTH 50 void starbar(void); int main(void) { starbar(); printf("%s\n",NAME); printf("%s\n",ADDRESS); printf("%s\n",PLACE); starbar(); return 0; }

程序输出如下:

void starbar(void) { int i;
for(i=1;i<=WIDTH;i++) putchar('*'); putchar('\n'); }

************************************************** No.83 Middle School 151 Xianning zhonglu Xi'an Shannxi **************************************************

程序分析
? Starbar标识符在不同位置被使用了3次:①函数原型(function prototype)告知 编译器starbar()的函数类型,②函数调用(function call)导致该函数的执行, ③函数定义(function definition)则确切指定了该函数的具体功能。 ? 函数同变量一样具有多种类型。任何程序在使用函数之前都需要声明该函数的类 型。因此,在main()函数的定义之前出现了如下的函数原型
void starbar(void); 圆括号表明starbar是一个函数名。第一个void指的是函数类型;它的意思是该函 数没有返回值。第二个void(位于圆括号内)表明该函数不接受任何参数。分号 的作用是表示该语句是进行函数的声明而不是函数定义。也就是说,这一行声明 了程序将使用一个名为starbar()且函数类型为void的函数,同事通知编译器需 要在其他位置找到该函数的定义。 ? 程序把starbar()原型置于main()之前;也可以将其置于main()之内,可 以放置在变量声明的任何位置。这两种方法都正确。 ? 程序在 main ()中通过使用函数名后跟圆括号和分号的格式调用函数 starbar (),语句如下: starbar();

程序分析
? 这是void类型函数的一般调用形式。当计算机执行到starbar();语句时,它找 到 starbar ()函数并执行其中的指令。执行完 starbar ()中的代码后,计算机 返回到调用函数(calling function)的下一行继续执行。在本例中,调用函数式 main()。如下图所示。 ? 程序中 starbar ()和 main ()具有相同的定义格式,即首先以类型、名称和圆 括号开始,接着是开始花括号、变量声明、函数语句定义以及结束花括号。注意 此处的 starbar ()后没有分号,这告诉编译器是在定义函数 starbar (),而不 是调用它或声明它的原型。 ? starbar()中的变量i是一个局部(Local)变量。这意味着该变量只是在starbar ()中可用。即使你在其他函数(包括main()函数)中使用名称i,也不会出 现任何冲突,你将得到具有统一名称的多个单独的、互不相关的变量。

二、函数参数
在上例中,如果文字居中显示,那么信头就会更漂亮。可以通过在打印文字之 前打印一定数目的空格来达到此目的。这和starbar()函数类似。在starbar()中 打印的是一定数量的星号,而现在要打印的是一定数目的空格。我们应不应该为这 个任务单独编写一个函数呢?答案是否定的,我们应该编写一个可以同时胜任这两 个任务的更为通用的函数。新函数将命名为 show_n_char ()(意思是显示 n 个某 种字符)。唯一的改变是要显示的字符和要现实的次数将被作为参数传递给函数 show_n_char(),而不是把它们置于函数内部。 具体一点儿说,假如一行是 50 个字符宽。 50 个星号恰好填满一行,调用函数 show_n_char(’*’,50)可以同starbar()函数一样实现该功能。而将No.83 Middle School.居中需要多少个空格?因为No.83 Middle School.是20个字符宽,为使其居 中,必须先输出 15 个空格,这样该短语两边就会分别有 15个空格。所以可以调用 show_n_char(’ ’,15)输出15个空格。 除了使用参数外,在其他方面show_n_char()和函数starbar()非常相似。 两者的一个不同之处是show_n_char()不像starbar()那样输出换行符,因为在 同一行中可能还需要输出其他字符。程序清单如下:

#include<stdio.h> #include<string.h> #define NAME "No.83 Middle School" #define ADDRESS "151 Xianning zhonglu" #define PLACE "Xi'an Shannxi" #define WIDTH 50 #define SPACE ' '

void show_n_char(char ch,int num) { int i; for(i=1;i<=num;i++) putchar(ch); }

void show_n_char(char ch,int num); int main(void) { int spaces; show_n_char('*',WIDTH); putchar('\n'); show_n_char(SPACE,15); printf("%s\n",NAME); spaces=(WIDTH-strlen(ADDRESS))/2; show_n_char(SPACE,spaces); printf("%s\n",ADDRESS); show_n_char(SPACE, (WIDTH-strlen(PLACE))/2);

printf("%s\n",PLACE); show_n_char('*',WIDTH); putchar('\n');
return 0;

}

三、定义带有参数的函数:形式参量
函数定义一下面的函数头开始: void show_n_char(char ch,int num) 这行代码通知编译器show_n_char()使用名为ch和num的两个参数,并且这 两 个 参 数 的 类 型 分 别 是 char 和 int 。 变 量 ch 和 num 被 称 为 形 式 参 量 ( formal parameter)。形式参量是局部变量,它们是定义它们的函数所私有的。这意味着 可以在其他函数中使用相同的变量名。每当调用函数时,这些变量就会被赋值。 注意:不能像通常的变量声明那样使用变量列表来声明同一类型的变量,如下 所示: void a(int x,y,z) /*不正确*/ void a(int x,int y,int z) /*正确*/ 另外,如果表示一个函数确实不使用参数,需要在括号内加入void关键字。

六、带参函数的原型声明
使用函数之前需要用原型声明该函数 void show_n_char(char ch,int num); 当函数接受参数时,函数原型通过使用一个逗号分隔的类型列表指明参数的个 数和类型。在函数原型中可以根据自己的喜好省略变量名: void show_n_char(char,int); 因为在原型中并没有实际的创建变量。这只是说明char代表一个char类型的变 量,num代表了一个int类型的变量。

四、调用带有参数的函数:实际参量
函数调用中,通过使用实际参数(actual argument)对ch和num赋值。例如上 例中show_n_char()的第一次使用: show_n_char(SPACE,12); 实际参数是空格字符和12。这两个数值被赋给show_n_char()中相应的形式 参量:变量ch和num。换句话说,形式参灵是被调函数中的变量,而实际参数是调 用函数分配给被调用函数变量的特定数值。如上例中所示,实际参数可以是①常量、 ②变量或③一个复杂的表达式。但是无论何种形式的实际参数,执行时首先要计算 其值,然后将该值赋值给被调用函数中相应的形式参量。以上例中最后一次使用 show_n_char()的语句为例: show_n_char(SPACE, (WIDTH-strlen(PLACE))/2); 求得构成第二个实际参数的表达式的值为18。然后把数值18赋给变量num。被 调函数不知道也不必知道这个数值来自与常量、变量或是更一般地表达式。再次, 实际参数是赋给被称为形式参量的函数变量的具体值。因为被调函数使用的值是从 调用函数中复制而来的,所以不管在被调函数中对复制数值进行什么操作,调用函 数中的原数值不会受到任何影响。

五、使用return从函数中返回一个值
前面讨论了从调用函数到被调函数的通信方法。需要沿相反方向传递信息时, 可以使用函数返回值。为了进一步说明,我们将构建一个比较两个参数大小并将较 小数值返回的函数。
#include<stdio.h> int imin(int,int); int main(void) { int a,b; printf("Enter a pair of integers(q to quit): \n"); while(scanf("%d%d",&a,&b)==2) { printf("The lesser of %d and %d is %d\n",a,b,imin(a,b)); printf("Enter a pair of integers(q to quit): \n"); } printf("Bye!"); return 0; } int imin(int m,int n) { int min; if(n<m) min=n;

else
min=m; return min; }

程序分析
关键字return指明了其后的表达式的数值即是该函数的返回值。在本例中,函 数返回变量min的值。因为min的类型是int,所以函数imin()的类型也是int。 变量min是imin()私有的,但是return语句把min的数值返回给了调用函数。 下面这个语句的作用相当于把min的值赋给lesser: lesser=imin(a,b); 但是不能用下面这个语句代替上句。 imin(a,b); lesser=min; 因为调用函数并不知道 min的存在。imin()中的变量是该函数的局部变量。 函数调用imin(a,b)只是复制了两个变量的数值。 返回值不仅可以被赋给一个变量,也可以被用作表达式的一部分。例如,可以 使用下列语句: answer=2*imin(a,b)+25; printf(”%d\n”,imin(a,b));

程序分析
返回值可以由任何表达式计算得出,而不仅仅来自于变量。例如可以使用以下 代码来简化示例程序: int imin(int n,int m) { return (n<m)? n:m; } 该条件表达式的值是n和m中的较小者,并且该数值被返回给调用函数。 return语句的另一个作用是终止执行函数,并把控制返回给调用函数的下一个 语句。即使return语句不是函数的最后一个语句,其执行结果也是如此。因此可以 用下面的方式编写imin()函数: int imin(int n,int m) { if(n<m) return n; else return m; } 大多数C程序员还是更倾向于只在函数结尾使用一次return语句,因为这样做更 有利于阅读程序的人明白函数的执行流程。但是,以上这种小函数中多次使用 return语句并没有问题。

六、函数类型
函数应该进行类型声明。同时其类型应和返回值类型形同。而无返回值的函数 应被声明为void类型。在早期C语言中,如果函数没有进行类型声明,则该函数具 有默认的函数类型int。使用这种默认类型的原因是早期大多数 C语言函数都是int类 型的。但是新的标准不再支持函数的int类型的默认设置。 类型声明是函数定义的一部分。但需要注意的是该类型指的是返回值类型,而 不是函数参数类型。例如,以下函数头表示函数使用两个int类型的参数而返回值的 类型是double。 double aaa(int a,int b) 为正确使用函数,程序在首次调用之前需要知道该函数的类型。途径之一是在 第一次调用之前进行完整的函数定义。但是,这种方式会使得程序难于阅读。而且, 需要的函数可能在C库中或其他文件中。因此,通常的做法是预先对函数进行声明, 以便将函数的信息通知给编译器。 在C标准库中,函数被分为几个系列每个系列都有各自的头文件。这些头文件 包含了本系列函数的声明部分。例如:头文件stdio.h包含了标准I/O库函数的声明, 像printf()、scanf()。而头文件 math.h是对各种数学函数进行声明。例如它使 用以下代码通知编译器函数sqrt()返回double类型的数值: doubel sqrt(double); 但是不要把函数声明和函数定义混淆。函数声明只是将函数类型告诉编译器, 而函数定义部分则是函数的实际实现代码。引用 math.h 头文件只向编译器说明了 sqrt()的返回值类型为double,但是sqrt()的实现代码则位于另一个库函数文件 中。

七、改变调用函数中的变量
有时我们需要用一个函数改变另一个函数中的变量。例如,排序问题中的一个 常见任务是交换两个变量的数值。假设要交换两个变量x和y的数值: temp=x; a=y; y=temp; 现在这段代码可以实现数值交换的功能,可以将其编写成函数。
#include<stdio.h> void interchange(int,int); int main(void) { int x=5,y=10; printf("Originally x=%d and y=%d.\n",x,y); interchange(x,y); printf("Now x=%d and y=%d.\n",x,y); return 0; } void interchange(int a,int b) { int temp; temp=a; a=b; b=temp; }

七、改变调用函数中的变量
运行程序之后我们发现数值并没有发生交换。我们在interchange()中加入一 些打印语句来检查错误
#include<stdio.h> void interchange(int,int); int main(void) { int x=5,y=10; printf("Originally x=%d and y=%d.\n",x,y); interchange(x,y); printf("Now x=%d and y=%d.\n",x,y); return 0; } void interchange(int a,int b) { int temp; printf("Originally x=%d and y=%d.\n",a,b); temp=a; a=b; b=temp; printf("Now x=%d and y=%d.\n",a,b); }

七、改变调用函数中的变量
我们发现函数interchange()并没有错误,a和b的值确实得到了交换。问题出 现在把执行结果传递给main()的时候,正如我们之前强调过的那样,interchange ()使用的变量独立于函数main(),因此交换a和b的数值对x和y的数值没有任何 影响!有人可能要说,使用return语句可以吗?不要忘了,return语句只能把一个数
值传递给调用函数,但是现在我们需要传递两个数值。这时我们就需要用到指针 了。

八、指针简介
究竟什么叫做指针?一般来讲,指针是一个其数值为地址的变量。就好比char 类型的变量用字符作为其数值,而int类型变量的数值是整数,指针变量的数值表示 的是地址。指针在C中有很多用途,这里我们暂时只研究他作为函数参数的方法和 理由。 如果将某个指针变量命名为ptr,就可以使用如下语句: ptr=&a; //把a的地址赋给ptr 对于这个语句,我们称ptr“指向”a。这里需要注意的一点是,ptr和&a的区别 在于前者是一个变量,而后者是一个常量。当然,ptr也可以指向其他任何地方: ptr=&sum; //令ptr指向sum而不是a 这时ptr的值是sum的地址。 要创建一个指针变量,首先要声明其类型。假设您想把ptr声明为可以存放一个 int数值的地址,就需要使用下面的新运算符。 假定ptr指向sum,如下所示: ptr=&sum; 这时就可以使用间接( indirection)运算符 * (也称作取值( dereferecing )运 算符)来取sum中存放的数值(不要把这种一元运算符和表示乘法的二元运算符相 混淆)。 val=*ptr; //得到ptr指向的值 语句ptr=&sum;以及语句val=*ptr;放在一起等同于下面的语句: val=sum; 由此看出,使用地址运算符和间接运算符可以间接完成上述语句的功能,这也 正是“间接运算符”名称的由来。

八、指针简介
那我们究竟要如何来声明指针变量呢?可能有人会猜是不是这样定义: pointer ptr; 这是不对的,为什么不能这样声明呢?因为这对于生命一个变量为指针是不够 的,还需要说明指针所指向变量的类型。因为不同类型的变量占用的存储空间的大 小不同,而有些指针操作需要知道变量类型所占用的存储空间。同时,程序也需要 了解地址中存储的是何种数据。例如,long和float两种类型的数值可能使用相同大 小的存储空间,但是它们的数据存储方式完全不同。所以,指针的声明形式如下: int *ptr1; //ptr1是指向一个整数变量的指针 char *ptr2; //ptr2是指向一个字符变量的指针 float *ptr3,ptr4; //ptr3和ptr4是指向浮点变量的指针 类型标识符表明了被指向变量的类型,而星号(*)表示该变量为一指针。声明 int *ptr1;的意思是ptr1是一个指针,而且*ptr1是int类型的。ptr2所指向的值(*ptr2) 是char类型的。而ptr2本身又是什么类型?我们称它为“指向char的指针”类型。 C专门为指针提供了%p输出格式。

八、指针简介
在下面的程序清单中,函数interchange()使用了指针参数:
#include<stdio.h> void interchange(int *,int *); int main(void) { int x=5,y=10; printf("Originally x=%d and y=%d.\n",x,y); interchange(&x,&y); printf("Now x=%d and y=%d.\n",x,y); return 0; } void interchange(int *a,int *b) { int temp; temp=*a; *a=*b; *b=temp; }

八、指针简介
这一次程序能否正常运行?答案是肯定的。 下面我们来详细分析一下程序的运行情况。首先函数调用语句如下: interchange(&x,&y); 可以看出,函数传递的是x和y的地址而不是它们的值。这就意味着interchange ()函数原型声明和定义中的形式参量a和b将使用地址作为它们的值,因此,它们 应该声明为指针。由于x和y都是整数,所以a和b是指向整数的指针。其声明如下: void interchange(int *a,int *b) 接下来,函数体进行如下声明: int temp; 从而提供了所需的临时变量。为了把x的值存在temp中,就需要使用以下语句: temp=*a; 注意,因为a的值是&x,所以a指向x的地址。这就意味着*a代表了x的值,而这 正是我们需要的数值。不要写成如下这样。 temp=a; 上面的语句中,因为赋给变量temp的只是x的地址而不是x的值,所以不能实现 数值的交换。 同样,把y的值赋给x,需使用下面的语句: *a=*b; 其执行结果相当于: x=y;

八、指针简介
在示例程序中,我们用一个函数实现x和y的数值交换。首先函数使用x和y的地 址作为参数,这使它可以访问x和y变量。通过使用指针和间接运算符*,函数可以获 得相应存储地址里面的数据,从而就可以改变这些数据。 通常情况下,可以把关于变量的两类信息传递给一个函数。如果函数调用形式 为: function(x); 这是传递的是x的值。但是如果使用的是下面这种函数调用形式: function(&x); 那么会把x的地址传递给函数。第一种调用形式要求函数定义部分必须包含一 个和x具有相同数据类型的形式参量。如下所示: int function(int num) 而第二种形式要求函数定义部分的形式参量必须是指向相应数据类型的指针: int function(int *ptr) 使用函数进行数据计算等操作时,可以使用第一种调用形式。但是,如果需要 要改变调用函数中的多个变量的值时,就需要使用第二种调用形式。其实我们已经 非常熟悉的scanf()函数在使用时就采用了第二种形式。例如,当需要为变量num 读取一个数值时,可以调用函数scanf(”%d”,&num)。该函数调用的意思是先读取一 个数值,然后将它存储到通过参数获得的地址中。 尽管 interchange ()只是用局部变量,但是通过使用指针,该函数可以操作 main()中的变量的值。


第八讲 C语言函数_图文.ppt

第八讲 C语言函数_学科竞赛_高中教育_教育专区。适用于想要参加NOIP的中学阶段学生,主要内容为C语言函数使用。NOIP,C语言,函数 一、函数概述首先,什么是函数?函数...

08_第八讲_C语言函数与预处理--力天手把手教你学单片机....ppt

08_第八讲_C语言函数与预处理--力天手把手教你学单片机之基础篇 - 手把手教

c语言课件第八讲_图文.ppt

c语言课件第八讲 - c语言课件,帮您轻松学c++!... c语言课件第八讲_IT/计算机_专业资料。c语言课件,帮...函数gets()和puts()是对字符串整体输入 输 函数 和 ...

第八讲 函数与程序结构_图文.ppt

第八讲 函数与程序结构_IT/计算机_专业资料。c语言ppt 阅读程序 void

《C语言与程序设计》第八讲_图文.ppt

C语言与程序设计》第八讲 - C语言程序设计基础 2010.9 课程大纲 第1

C语言程序设计第八讲_图文.ppt

C语言程序设计第八讲 - C语言程序设计 第八讲 主讲:厉福生 上讲回顾 ? ? ? ? ? 函数的分类 常用的数学函数 自定义函数的定义 函数的返回值 函数的调用 ...

C语言第八讲_指针_图文.ppt

C语言第八讲_指针 - 第八章 指针 西安电子科技大学模式识别与智能控制研究所 第一讲 指针基础 ? 指针的基本概念 ? 指针的定义和使用 ? 指针作函数的参数 ? ...

《c语言与程序设计》第八讲-清华李宛洲_图文.ppt

c语言与程序设计》第八讲-清华李宛洲 - C语言程序设计基础 2005.9 第八讲 函数(二) 教学内容 ? 函数基本概念回顾 ? 实参是变量与实参是地址的区别 ? 通过...

08 第08章 C语言函数_图文.ppt

08 第08章 C语言函数 - 第八章 ? 本章要点 ? ? ? ? ? 函数的

第八讲_函数(二)_图文.ppt

第八讲_函数(二) - 《C++语言及编程技巧》 主讲:匡纲要 国防科技大学电子科学与工程学院 湖南长沙 -1 第8讲 函数(二) ? 4.5通过函数参数传递数据 ? ...

C语言基础_图文.ppt

char str[13]; scanf("%s",str); scanf("%s",&str); /* 此语句是错误的 */ C程序设计第八讲 字符串处理函数C语言提供了丰富的字符串处理函数, 它们可...

C语言进阶-第八讲编写安全无错的代码_图文.pdf

C语言进阶-第八讲编写安全无错的代码 - 第八讲 代码的调试 凌明 黄少珉 hs

C语言函数_图文.ppt

C语言函数 - 第九章 (Pointer) 内容提要: ★指针的概念 ★指针与数

08 第八讲 C语言函数与预处理--力天手把手教你学单片机....ppt

08 第八讲 C语言函数与预处理--力天手把手教你学单片机之基础篇 LT_sup

C语言程序设计第八章课件_图文.ppt

C语言程序设计第八章课件 - C语言程序设计 第八讲:函数 主讲: 主讲:龚文引 提纲 函数的概念 函数的定义与调用 函数的递归调用 变量的作用域 问题 求200个同样...

08 第八讲 C语言函数与预处理--力天手把手教你学单片机....ppt

08 第八讲 C语言函数与预处理--力天手把手教你学单片机之基础篇四 讲解了C语言函数与预处理,学习如何将代码编写的更加清晰讲解了C语言函数与预处理,学习如何将...

第八讲 文件_图文.ppt

第八讲 文件_IT/计算机_专业资料。第八讲 文件 8.1 文件及格式化输入输出...C语言规定了标准输入输出函数库,用fopen()函数 打开一个文件,用fclose()函数...

第八讲 第九讲 第6章 函数、存储类和预处理程序_图文.ppt

第八讲 第九讲 第6章 函数、存储类和预处理程序_理学_高等教育_教育专区。...概述 *引例 *函数的定义 *函数使用说明 C语言中有标准库函数和自定义函数。 ...

C语言第八讲.ppt

掌握函数使用的常用方法难点: 难点: 函数的参数传递和返回值 第四章 模块化程序设计 C语言它提供如下一些支持模块化软件开发 语言它提供如下一些支持模块化软件...

第八讲第九讲第6章函数、存储类和预处理程序-精选文档_....ppt

第八讲第九讲第6章函数、存储类和预处理程序-精选文档_数学_自然科学_专业...概述 *引例 *函数的定义 *函数使用说明 C语言中有标准库函数和自定义函数。 ...