您的位置:首页 > 编程语言 > C语言/C++

C语言函数

2017-01-24 02:44 295 查看
关于形参与实参的一些说明:

#include <stdio.h>
int main ()
{
int max (int x, int y);//对max函数的声明
int a, b, c;
scanf("%d%d",&a, &b);
c=max(a, b);//实参
printf("Max is %d", c);
}
int max (int x, int y)//形参
{
int z;
z=x>y?x:y;
return z;  //如果定义在主函数前面,可以不用声明
}


1、在定义函数中指定的形参,在未出现函数调用时,它们并不占据内存中的存储单元。只有在发生函数调用时,函数max中的形参才被分配内存单元。在调用结束后,形参所占的内存单元也被释放。

2、实参可以是常量、变量或表达式,如:

      max(3,a+b);

      但要求它们有确定的值。在调用时将实参的赋值给形参。

3、在被定义的函数中,必须指定形参的类型。

4、实参与形参的类型应相同或兼容。

5、实参对形参的数据传递是“值传递”(相当于copy),单向传递,只由实参传给形参,而不能由形参传回来给实参。在内存中,实参单元与形参单元是不同的单元。

函数的返回值:

      通常希望通过函数调用使主函数能得到一个确定的值,就是函数的返回值。

关于函数返回值的一些说明:

1、函数的返回值是通过函数中的return语句获得的,return语句将被调用函数中的一个确定值带回主函数中去。如果需要从被调用函数带回一个函数值供主函数使用,被调用函数中必须包含return语句。如果不需要从被调用函数带回函数值可以不要return语句。

2、一个函数中可以有一个以上的return语句,执行到哪一个语句,哪一个语句起作用。

3、return后面的值可以是一个表达式。如:

int max (int x, int y):
{
return( x > y ? x : y ):
}

4、对于不带返回值的函数,应当用void定义为无类型(或称空类型)。此时在函数体中不得出现return语句。

函数的调用:

1、一般形式:函数名(实参表列)

                          如果是调用无参函数,括弧不能省略。

                          如果实参表列包含多个实参,则各参数间用逗号隔开。实参与形参的个数应相等,类型应匹配。实参与形参按顺序对应,一一传递数据。

               如果实参列表包括多个实参,对实参求值得要求并不是确定的,有的系统按自左向右的顺序求实参的值,有的系统则按自右向左的顺序。

               这个代码可以测试系统调用顺序:

#include <stdio.h>
int main ()
{
int f(int a, int b);
int i = 2, p;
p = f(i, ++i);
printf("%d\n", p);
}
int f (int a,int b)
{
int c;
if(a > b)
c = 1;
else if(a==b)
c = 0;
else
c = -1;
return (c);
}

        我用Code::Block编译,结果为0,说明编译器自右向左调用。

函数调用的方式:

1、把函数调用作为一个语句。这时不要求函数带返回值,只要求函数完成一定的操作。

2、函数出现在一个表达式中,这种表达式成为函数表达式。如:

         c=2*max(a,b);

3、 在函数的调用中,可以将函数的返回值当做参数。如:

        m=max(a,max(b,c));

声明与定义的区别:

     “声明”一词的原文是delaration,过去在许多书中把它译为“说明”。声明的作用是把函数名、函数参数的个数和参数类型等信息通知编译系统,以便在遇到函数调用时,编译系统能正确识别函数并检查调用是否合法。

     定义是指对函数功能的确立,包括指定函数名、函数值类型、形参及其类型、函数体等,它是一个完整的独立的函数单位(占内存)。

     而函数的声明的作用则是把函数的名字、函数的类型以及形参的类型、个数和顺序通知编译系统,以便在调用该函数时系统按此进行对照检查(不占内存)。

数组作为函数参数:

      数组可以作为函数的参数使用,进行数据传送。数组用作函数参数有两种形式。一种是把元素(下标变量)作为实参使用;另一种是把数组名作为函数的形参和实参使用。

      数组名做函数参数与数组元素做实参有几点不同:

       1、用数组元素做实参时,只要数组类型和函数的形参变量类型一致,那么作为下标变量的数组元素类型也和函数形参变量的类型是一致的。因此并不要求函数的形参也是                下标变量。换句话说,对数组元素的处理是按普通变量对待的。然而,用数组名作函数参数时,则要求形参和相对应的实参都必须是类型相同的数组,都必须有明确的                数组说明。当形参和实参二者不一致时,即会发生错误。

       2、在普通变量或下标变量作函数参数时,形参变量和实参变量是由编译系统分配的两个不同的内存单元。在函数调用时发生的值传送是把实参变量的值赋予形参变量。然                而在用数组名作函数参数时,不是进行值的传递,而是地址的传递,数组名就是数组的首地址也就是说把实参数组的首地址赋予形参数组名,形参数组取得该首地址                    后,也就等于有了实在的数组。实际上是形参数组和实参数组为同一数组,共同拥有一段内存空间。

      下面给出三个例题:

      例题一:

      判别一个整数数组a[10]={1,2,3,4,-1,-2,-3,-4,2,3}中各元素的值,若大于0,则输出该值,若小于等于0则输出0。

#include<stdio.h>
void test(int v);
int main()
{
int a[10]={1,2,3,4,-1,-2,-3,-4,2,3};
int i;
for(i=0;i<10;i++)
{
test(a[i]);
}
printf("\n");
}
void test(int v)
{
if(v>0)
{
printf("%d",v);
}
else
{
printf("%d",0);
}
}
      例题二:

      给定数组a[10]={2,4,6,8,10,12,14,16,18,20},输出前5个数。
#include<stdio.h>
void test(int b[10]);
int main()
{
int a[10]={2,4,6,8,10,12,14,16,18,20};
test(a);
putchar('\n');
}
void test(int b[10])
{
int i=0;
for( ;i<5;i++)
{
printf("%d",b[i]);
}
}
      例题三:
      有一个一维数组score,内放10个学生成绩,求平均成绩。

#include<stdio.h>
double average(double array[10]);//这里数组的值随意,不写也可以
int main()
{
double score[10]={82,100,87.5,89,78,85,67.5,92.5,93,94},result;
result=average(score);
printf("average score is %5.2lf\n",result);
putchar('\n');
}
double average(double array[10])
{
double result=0;
int i=0;
for(i=0;i<10;i++)
{
result+=array[i];
}
result/=10;
return result;
}
局部变量:只能在本函数内使用的变量。
      1、主函数定义的变量也只在主函数中有效,而不因为在主函数中定义而在整个文件或程序中有效。主函数也不能使用其他函数中定义的变量。

      2、不同函数中可以使用相同名字的变量。在内存中占用不用的单元,互不混淆。

      3、形式参数也是局部变量。

      4、在一个函数内部,可以在复合语句中定义变量,这些变量只在本复合语句中有效,这种复合语句也称为“分程序”或“程序块”。

全局变量:在函数外部定义的变量,也称全程变量。可以为本文件中其他函数所共用。它的有效范围从定义变量的位置开始到本源文件结束。

建议不要使用全局变量,原因如下:

      1、全局变量在程序的全部执行过程中都占用存储单元,而不是仅在需要时才开辟单元。

      2、使用全局变量过多,会降低程序的清晰性,人们往往难以清楚的判断出每个瞬时各个外部变量的值。在各个函数执行时都有可能改变外部变量的值,程序容易出错。因此要限制使用全局变量。

      3、它使函数的通用性降低了。

储存类别:

auto变量(自动变量):

      函数中的局部变量,如不专门声明为static存储类别,都是动态地分配存储空间的(栈),数据存储在动态存储区中。

      函数中定义的形参和在函数中定义的变量(包括在复合语句中定义的变量),都属此类,在调用函数时系统会给它们分配存储空间,在函数调用结束时会自动释放这些空间。关键字auto可以省略。

static变量(静态局部变量):

      有时希望函数中的局部变量的值在函数调用结束后不消失而保留原值,即占用的储存单元不释放,下一次该函数调用时,该变量已有值,就是上一次函数调用结束的值。

x下面这个小程序可以考察静态局部变量的值:

#include<stdio.h>
int f(int a)
{
auto int b=0;
static int c=3;
b=b+1;
c=c+1;
return (a+b+c);
}
int main()
{
int a=2,i;
for(i=0;i<3;i++)
{
printf("%d\n",f(a));
}
} 在定义局部变量时不赋初值的话,则对静态局部变量来说,编译时会自动赋初值0(对数值型变量)或空字符(对字符变量)。对自动变量来说,如果不赋初值则它的值是一个不确定的值。这是由于每次函数调用结束后存储单元已释放,下次调用时又重新另分配存储单元,而所分配的单元中的值是不确定的。
register变量(寄存器变量):

      

如果有一些变量使用频繁(例如在一个函数中执行10000次循环,每次循环中都要引用某局部变量),则为存取变量的值要花费不少时间。为了提高运行效率,C语言允许将局部变量的值放在CPU的寄存器中,需要时直接从寄存器取出参加运算,不必再到内存中去存取。

extern变量(外部变量):

      外部变量即全局变量,它的作用域是从变量的定义处开始,到本程序文件的末尾。在此作用域内,全局变量可以为程序中各个函数所引用。编译时将外部变量分配在静态存储区。有时需要用extern来声明外部变量,以扩展外部变量的作用域。

作用域角度分,有局部变量和全局变量。

局部变量:1、自动变量,即动态局部变量(离开函数值就消失);

                    2、静态局部变量(离开函数值仍保留);

                    3、寄存器变量(离开函数值就消失)。

                           (形式参数可以定义为自动变量或寄存器变量,不可以定义为静态变量,会报错)

全局变量:1、静态外部变量(只限本文件引用);

                    2、外部变量(即非静态的外部变量,允许其他文件引用)。extern

变量存在的时间(生存期)来区分,有动态存储和静态存储两种类型。静态存储是程序整个运行时间都存在,而动态存储测试在调用函数时临时分配单元。

动态存储:1、自动变量(本函数内有效);

                    2、寄存器变量(本函数内有效);

                    3、形式参数(本函数内有效)。

静态存储:1、静态局部变量(函数内有效);

                    2、静态外部变量(本文件内有效);

                    3、外部变量(其他文件可引用)。

变量值存放的位置来区分,可分为:

内存中静态存储区:1、静态局部变量;

                                    2、静态外部变量(函数外部静态变量);

                                    3、外部变量(可为其他文件引用)。

内存中动态存储区:自动变量和形式参数。

CPU中的寄存器:寄存器变量。

关于作用域和生存期的概念:

       从前面的叙述可
9ccd
以知道,对一个变量的性质可以从两个方面分析,一是变量的作用域,即变量作用的范围,一是变量值存在的时间长短,即生存期。

static对局部变量和全局变量的作用不同:

      对局部变量来说,它使变量由动态存储方式改变为静态存储方式。而对全局变量来说,它使变量局部化(局限于本文件),但仍为静态储存方式。

      从作用域角度来看,凡有static声明的,其作用域都是局限的,或者是局限于本文件内(静态局部变量,或者是局限于本文件内(静态外部变量)。

我们根据函数能不能被其他文件调用,将函数区分为内部函数和外部函数。

      如果一个函数只能被本文件中其他函数所调用,它称为内部函数。如static int fun(int a,int b)

      在定义函数时,如果在函数首部的最左端加关键字extern,则表示此函数是外部函数,可供其他文件调用。如函数首部可写为extern int fun(int a,int b)。这样函数fun就可以为其它文件调用。C语言规定,如果在定义函数时省略extern,则隐含为外部函数。

      
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: