函数
函数的学习不得不说还是挺好用的,使代码的编写更加清晰。不管别人如何,还是得做好自己的学习总结。
什么是函数,为什么要使用函数?
- 函数是完成特定任务的独立代码单元;
- 降低复杂性,避免重复代码段,限制了改动带来的影响,隐含顺序,改进性能,
- 进行集中控制,隐含数据结构,隐含指针操作,隐含全局变量。
我们可以对函数进行调用,这样避免了我们一大串代码写在一个main函数中。
C语言中对函数的分类,下面来简单总结一下。
有无返回值参数就不多说了。void main 无返回值,不过老师不建议使用无返回值的函数,具体原因自己也不太清楚,待会可以百度一下;int main 有返回值。
形式参数和实际参数
- 形参出现在函数定义中,在整个函数体内都可以使用,离开该函数则不能使用(如31行中的,a、b);
- 实参出现在主调函数中,进入被调函数中也不能使用(如43行的m、n),实参可以是常量、变量、表达式、函数等,
- 在进行函数调用时,都必须具有确定的值,以便把值传给形参;
- 实参和形参在数量上、类型上、顺序上应严格一致,否则会报错(类型不匹配)
- 函数调用中发生的数据传送是单向的,只能把实参的值传送给形参,在函数调用过程中,形参的值发生改变,实参的值不改变。
函数的返回值
函数的返回值只能通过return语句返回主调函数
return 语句的一般形式为:
return 表达式;或 return (表达式);
函数的调用
在程序中是通过对函数的调用来执行函数体的
C语言中函数调用的一般形式
函数名 (实际参数表) //无参函数则无实际参数,如果有多个参数则用逗号隔开。
int sum(int *a,int n)
{
int sum=0;
int i;
for (i = 0; i < n; ++i)
{
sum+=a[i];
}
return sum;
}
int main(int argc, char const *argv[])
{
int a[10]={1,2,3,4,5,6,7,8,9,10};
int s=0;
s=sum(a,10);
printf("累加结果为:%d\n",s );
return 0;
}
函数的调用还是挺好用的,使函数的结构更加清晰,避免出错。
被调函数的声明和函数原型:
- 在主调函数中调用某函数之前应对该被调函数进行声明,这于使用变量之前对变量进行变量说明是一样的。目的是使辨析系统知道 被调函数的返回值类型。
- 其一般形式为
类型说明符 被调函数名(类型 形参,类型 形参,......);
或者
类型说明符 被调函数名(类型,类型.........);
C语言中规定以下几种情况可以省去声明;
1:被调函数的返回值是整型或字符型,可以不对被调函数声明;
2:被调函数声明在主调函数之前
3:在所有函数之前预先说明了各个函数的类型
4:对库函数的调用不需要再做说明,但是必须把该函数的头文件用include命令包含。
函数的嵌套调用:
- C语言不允许嵌套定义函数,但是允许在一个函数的定义中出现另一个函数。这样就出现了函数函数嵌套调用。
计算 s=(22)!+(33)!
函数的递归调用:
- 一个函数在它的主体中调用他的自身称为递归调用。这种函数称为递归函数。
执行的过程中将反复调用自身,每调用一次都进入新的一层。
long jiecheng(int n)
{
long ret = -1;
if(n<0)
printf("n<0,input error\n");
else if(n==0||n==1)
ret = 1;
else
ret = jiecheng(n-1)*n;
}
int main()
{
int n;
long y;
printf("input a intrager number:\n");
scanf("%d",&n);
y=jicheng(n);
printf("%d!=%ld\n",n,y);
return 0;
}
这是一个求阶层的问题,其中使用到了函数的递归调用。其中的ret=jieceng(n-1)*n这里。
数组作为函数的参数
数组可以作为函数的参数使用,进行数据传送。数组作为函数参数有两种形式,一种是把数组元素作为实参使用;另一种是把数组名作为函数的形参和实参使用。
数组作为函数的参数
- 数组可以作为函数的参数使用,进行数据传送。数组作为函数参数有两种形式,一种是把数组元素作为实参使用;另一种是把数组名作为函数的形参和实参使用。
判断一个整型数组中个元素的值,如果大于0,则输出该值,否则输出0,
1:数组元素作为实际参数时,数组元素的类型和函数形参的类型保持一致,这时数组元素是一个普通变量。
数组名作为函数参数时,要求形参和实参都必须是类型相同的。
2:数组元素做函数参数时,形参和实参是由编译器分配的两个不同的内存单元,在函数调用时发生的值传递是把实参变量赋予形参变量。
在用数组名做函数参数时,不是进行值传送,即不是把参数组的每一个元素的值都赋予形参组的各个元素。因为实际形参数组并不存在,编译数组并不为形参数组分配内存。数组名就是数组的首地址,。数组做函数参数时说进行的传送只是地址的传送,也就是说把实参数组的首地址赋给形参数组名,形参数组名取得改首地址后,也就等于有了实在的数组。实际上是形参数组和实参数组为同一数组,共同拥有一段空间。
局部变量和全局变量
-
局部变量也称为内部变量,局部变量是在函数内定义的,其作用域仅限于函数内,离开该函数后再使用这种变量是非法的。
注意:
1:主函数中定义的变量也只能在主函数中使用
2:形参变量是属于被调函数的局部变量,实参变量属于主调函数
3:允许在不同的函数中使用相同的变量名;
4:在复合语句中定义的变量,作用域仅限于复合语句中。 -
全局变量也称为外部变量,它是在函数外部定义的;他不从属于哪个函数,他属于一个程序源文件。其作用域是整个源程序。
*局部变量会屏蔽全局变量。
变量的存储类别:
- 动态存储方式与静态存储方式
从变量值的生存期来划分可分为,静态存储方式和动态存储方式。
静态存储方式是指在程序运行期间分配固定的存储空间的方式。
动态存储方式是在程序运行期间根据需要进行动态分配存储空间的方式。
用户存储空间可以分为三部分:
(1)程序区
(2)静态数据区
(3)动态数据区
全局变量存储在静态数据区,程序开始时分配,结束时释放,占据固定单元。 - 动态存储区存放以下数据:
函数形参,
自动变量(未加static修饰的局部变量),
函数调用的现场保护和返回地址。
static声明局部变量
-
有时希望函数中的局部变量的值在函数调用后不消失而保留原值,这使就指定局部变量为“静态局部变量”,用关键字static声明。
-
对静态局部变量的说明:
局部变量属于静态存储类别,在静态存储区内分配单元,整个程序运行期间都不释放。
静态局部变量在编译时赋值,只赋值一次;
不赋初值的话,编译器默认符0;