一、一个简单的函数
函数在先前已经用到过,这里就一个程序对于函数进行说明:
#include<stdio.h>
int a=0; //全局变量
int main()
{
void function1(); //函数1
int fuction2(int temp); //函数2
int b=0; //变量
printf("%d\n",fuction2(5));
return 0;
}
void function1()
{
int c=0; //局部变量
}
int fuction2(int temp)
{
temp+=2;
return temp;
}
1、 首先我们看到了注释中的全局变量这个词,在程序中有整个程序都有效的变量,我们可以认定为全局变量;而在函数中定义的变量我们认为只有在这个函数中才会有效,我们叫做是局部变量,而在循环体或者更小的结构中定义的变量,那么出了这个结构,这个变量将不再有效。
2、 然后我们看整个程序的构架,函数在主函数中被声明,那么在主函数中就可以被调用,或者说这个函数的定义在主函数的前面,那么无需声明,主函数在执行的时候也可以被调用,但是在主函数中声明是一种比较好的方法,这就好像是头文件的声明一样,只是两者声明的地方不同,其实都是相同的,想要在什么有效的生命周期内使用,就在恰当的位置声明。
3、 然后就是函数的格式:函数类型 函数名(参数类型 参数1,参数类型 参数2…)
函数类型是指这个函数在执行完毕的时候需要返回给调用者的数值,如果是void则不用返回,假如是int,则在调用函数内的return后面必须是int的数据类型。至于参数,在函数调用的时候程序放进去的参数我们叫做实参,而在声明或者定义函数的地方的参数我们又叫做形参。
二、函数参数问题
2.1 值传递和地址传递
程序中数据的储存可以这么理解,每个数值存放在对应的地址中,那么在函数的参数传递中,加入传入的参数是一个数值,那么在函数内部对数值进行任何修改都不会影响到在调用这个函数的地方的实参的数值。而地址传递则相当于把这个数值的地址当作参数传入,那么在函数内部对存放在这个地址的数值的修改将会有效,在学习C++的过程中我们还可以知道在用引用这个功能的时候也可以实现影响原先数值的作用。这里我们就知道要让函数内部影响外部的某个值,方式有:
1、 地址传递;
2、 引用;
3、 不用参数的方式,用全局变量的方式;
4、 用到了容器;
2.2 函数的嵌套调用和递归调用
函数的嵌套调用和循环中的循环可以等同考虑,比较简单,可以直观地代入了解。而递归调用则不一定,递归就是一个栈,先进后出的原理,是动态规划的灵魂,这里用递归实现一个字符串正向输入,逆向输出的功能,代码如下:
#include<stdio.h>
int main()
{
void recursion(); //函数声明
recursion(); //函数调用
return 0;
}
void recursion()
{
char c;
scanf("%c",&c); //输入字符
if(c!=10) //一直输入当输入的是回车为止
{
recursion();
}
printf("%c",c); //输出
}
大概的思路就是一个字符一个字符输入,当输入停止(这里判断为回车)时候,就开始输出当前字符,然后结束当前函数,跳回到上一个函数,输出上一个函数的输入的字符,一直到程序运行结束,就实现了输入的字符串逆向输出的功能。
三、变量的作用域和储存方式
作用域就是局部变量和全局变量的使用中涉及到的问题,在先前的说明中提到过,这里讲讲储存方式。
3.1 动态储存和静态储存
动态储存是指在程序执行过程中,使用到变量时才分配储存单元,使用完毕立刻释放。例如函数的形参就是属于这种方式。
静态储存是指在变量定义时就分配储存单元并一直保持,直至整个程序结束。例如,全局变量就属于这种方式。
这种由于储存方式不同而产生的特性称为变量的生存期。生存期和作用域是从时间和空间这两个不同的概念来描述变量的特性,两者既有关联,又有区别。一个变量究竟属于那种储存方式,作用域之外还有储存类型。
3.2 储存类型
关键字 | 类型名 | 说明 | 备注 |
auto | 自动类型 | 默认类型 | 没有赋初值,初值是随机的 |
register | 寄存器类型 | 动态储存,在CPU中的通用寄存器中 | 一般只能是int、char和指针 |
static | 静态类型 | 有外部和内部静态变量之分 | 都局限于某个某个范围 |
extern | 外部类型 | 定义在所有函数之外的全局变量 | 用于直接共享数据 |