首页 > 编程知识 正文

函数的声明定义和调用方法,声明函数和调用函数

时间:2023-05-03 19:59:20 阅读:279542 作者:2441

1 函数的声明与定义 1.1 声明的概念

    声明:一般位于头文件,告知编译器这里有一个叫xxx(函数名)的函数,作用是让编译器知道这个函数的存在。总而言之声明的功能就是告诉编译器有这么个函数,但并不实现。

1.2 定义的概念

    定义:用于实现这个函数,真正在内存(堆或栈中)为此函数分配空间。定义一般在源文件里,以函数体的形式展现函数的实现过程。

1.3 声明与定义

    “定义”是指对函数功能的确立,包括指定函数名,函数值类型、形参类型、函数体等,它是一个完整的、独立的函数单位。而“声明” 的作用则是把函数的名字、函数类型以及形参类型、个数和顺序通知编译系统,以便在调用该函数时系统按此进行对照检查(例如函数名是否正确,实参与形参的类型和个数是否一致)。
    从程序中可以看到对函数的声明与函数定义中的函数首部基本上是相同的。因此可以简单地照写已定义的函数的首部,再加一个分号,就成为了对函数的“声明”。在函数声明中也可以不写形参名,而只写形参的类型。
    在C语言中,使用函数原型是ANSI C的一个重要特点。它的作用主要是利用它在程序的编译阶段对调用函数的合法性进行全面检查。函数原型(function prototype)并不等于函数声明,只能说函数原型(function prototype)是函数声明的一种形式。
说明:

以前的C版本的函数声明方式不是采用函数原型,而只是声明函数名和函数类型。 如:float add(); 不包括参数类型和参数个数。系统不检查参数类型和参数个数。新版本也兼容这种用法,但不提倡这种用法,因为它未进行全面的检查。实际上,如果在函数调用前,没有对函数作声明,则编译系统会把第一次遇到的该函数形式(函数定义或函数调用)作为函数的声明,并将函数类型默认为int 型。如一个max函数,调用之前没有进行函数声明,编译时首先遇到的函数形式是函数调用”max(a, b)”,由于对原型的处理是不考虑参数名的,因此系统将max()加上int作为函数声明,即int max(); 因此不少教材说,如果函数类型为整型,可以在函数调用前不必作函数声明。但是使用这种方法时,系统无法对参数的类型做检查。或调用函数时参数使用不当,在编译时也不会报错。因此,为了程序清晰和安全,建议都加以声明为好。如果被调用函数的定义出现在主调函数之前,可以不必加以声明。因为编译系统已经先知道了已定义的函数类型,会根据函数首部提供的信息对函数的调用作正确性检查。所以可以说函数定义本身也是一种函数声明。如果已在所有函数定义之前,在函数的外部已做了函数声明,则在各个主调用函数中不必对所调用的函数再作声明。 2 函数的调用

    在C语言中有两种函数调用方式:传值调用和传地址调用。下面通过两个简单的程序介绍一下这两种函数调用方式。值得注意的是在C语言里并没有C++所谓的“按引用调用”的概念,这里的传地址调用与C++中引用调用实现的功能是一样的。

下面我们再强调一下两者的概念:
1. 传值:实际就是把实参的值赋值给形参,相当于copy。此时对形参的修改,不会影响实参的值 。
2. 传址:实际是传值的一种特殊方式,只是他传递的是地址,不是普通的赋值,传地址以后,实参和形参都指向同一个对象,因此对形参的修改会影响到实参。

2.1 传值调用 #include <stdio.h>void swap(int x,int y){ int temp; temp=x; x=y; y=temp; printf("x=%d,y=%dn",x,y);}void main(){ int a=6; int b=8; swap(a,b); printf("a=%d,b=%dn",a,b);}

运行结果如下图所示:

    从运行结果上可以看出实参a和b并没有实现数值交换,实现交换的只有被调函数里的形参x和y。
    造成这样结果的原因是我们虽然通过调用函数将a和b的值传递给了被调函数的形参x和y,即在调用函数时隐含地把实参a、b 的值分别赋值给了x、y,x、y也完成了它们之间数值的交换。但是由于函数体内并没有对、,b进行任何的操作,所以交换的只是x、y变量,并不是a、b。这其实是一次单向的传递过程,a、b能传给x、y,x、y能成功互换其数值。但x、y是定义在函数swap中的局部变量,当swap()函数执行完毕,其中swap()函数占用的内存资源会被释放(在main函数中调用swap时会给swap开辟一个函数栈,函数返回时就会被释放),因此被调函数没有渠道把交换的值传回给a、b。结果当然是a、b的值就不会发生改变!函数只是把a、b的值通过赋值传递给了x、y,函数里头操作的只是x、y的值并不是a、b的值。这就是所谓的参数的值传递了。

2.2 传地址调用 #include <stdio.h>void swap(int *x,int *y){ int temp; temp=*x; *x=*y; *y=temp; printf("*x=%d,*y=%dn",*x,*y);}void main(){ int a=6; int b=8; swap(&a,&b); printf("a=%d,b=%dn",a,b);}


    从函数的接口部分:swap(int *x,int *y),可以看出此时参数x、y都是指针。再看函数调用处:swap(&a, &b);,它是将a的地址(&a)代入到x,b的地址(&b)代入到y。同上面的值传递一样,函数调用时作了两个隐含的操作:将&a,&b的值赋值给了x,y,即x=&a;y=&b;。所以传递的实参是a和b在内存中的地址,那么在swap中的x就指向main中a的地址,y就指向main中b的地址,此时指针x、y的值已经分别是a、b变量的地址值了,那么当*p1、*p2被修改时,a、b也会跟着发生变化,因为此时二者占用了同一块空间,当任意一者使空间里的内容发生变化时,二者都会做相同变化。

赛车每天赚1000的方法数定义本身也是一种函数声明。如果已在所有函数定义之前,在函数的外部已做了函数声明,则在各个主调用函数中不必对所调用的函数再作声明。 2 函数的调用

    在C语言中有两种函数调用方式:传值调用和传地址调用。下面通过两个简单的程序介绍一下这两种函数调用方式。值得注意的是在C语言里并没有C++所谓的“按引用调用”的概念,这里的传地址调用与C++中引用调用实现的功能是一样的。

下面我们再强调一下两者的概念:
1. 传值:实际就是把实参的值赋值给形参,相当于copy。此时对形参的修改,不会影响实参的值 。
2. 传址:实际是传值的一种特殊方式,只是他传递的是地址,不是普通的赋值,传地址以后,实参和形参都指向同一个对象,因此对形参的修改会影响到实参。

2.1 传值调用 #include <stdio.h>void swap(int x,int y){ int temp; temp=x; x=y; y=temp; printf("x=%d,y=%dn",x,y);}void main(){ int a=6; int b=8; swap(a,b); printf("a=%d,b=%dn",a,b);}

运行结果如下图所示:

    从运行结果上可以看出实参a和b并没有实现数值交换,实现交换的只有被调函数里的形参x和y。
    造成这样结果的原因是我们虽然通过调用函数将a和b的值传递给了被调函数的形参x和y,即在调用函数时隐含地把实参a、b 的值分别赋值给了x、y,x、y也完成了它们之间数值的交换。但是由于函数体内并没有对、,b进行任何的操作,所以交换的只是x、y变量,并不是a、b。这其实是一次单向的传递过程,a、b能传给x、y,x、y能成功互换其数值。但x、y是定义在函数swap中的局部变量,当swap()函数执行完毕,其中swap()函数占用的内存资源会被释放(在main函数中调用swap时会给swap开辟一个函数栈,函数返回时就会被释放),因此被调函数没有渠道把交换的值传回给a、b。结果当然是a、b的值就不会发生改变!函数只是把a、b的值通过赋值传递给了x、y,函数里头操作的只是x、y的值并不是a、b的值。这就是所谓的参数的值传递了。

2.2 传地址调用 #include <stdio.h>void swap(int *x,int *y){ int temp; temp=*x; *x=*y; *y=temp; printf("*x=%d,*y=%dn",*x,*y);}void main(){ int a=6; int b=8; swap(&a,&b); printf("a=%d,b=%dn",a,b);}


    从函数的接口部分:swap(int *x,int *y),可以看出此时参数x、y都是指针。再看函数调用处:swap(&a, &b);,它是将a的地址(&a)代入到x,b的地址(&b)代入到y。同上面的值传递一样,函数调用时作了两个隐含的操作:将&a,&b的值赋值给了x,y,即x=&a;y=&b;。所以传递的实参是a和b在内存中的地址,那么在swap中的x就指向main中a的地址,y就指向main中b的地址,此时指针x、y的值已经分别是a、b变量的地址值了,那么当*p1、*p2被修改时,a、b也会跟着发生变化,因为此时二者占用了同一块空间,当任意一者使空间里的内容发生变化时,二者都会做相同变化。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。