函数
函数的作用
什么是函数
用来完成一定的功能。函数名即给对应功能起一个名字
为什么要使用函数?
事先编好一批常用的函数来实现各种不同的功能,把它们保存在函数库中。需要用时,直接可以调用,可以实现模块化程序设计。大大减少重复编写代码的工作量,提高程序可读性
graph TB 程序软件 --> 功能1 程序软件 --> 功能2 程序软件 --> 功能3 程序软件 --> 功能4 程序软件 --> 功能5说明:
- 一个C程序由一个或多个程序模块组成,每一个程序模块作为一个源程序文件。对于较大的程序,一般不希望把所有内容全放在一个文件中,而是把它们分别放在若干个源文件中,由若干个源程序文件组成一个C程序。这样便于分别编写和编译,提高调试效率。一个源程序文件可以为多个C程序公用
- C程序的执行是从main函数开始的,如果在main函数中调用其他函数,在调用后流程返回到main函数,在main函数中结束整个程序的运行
函数的定义
定义函数的方法
定义无参函数
无参数函数:函数名后面的括号中是空的,没有任何参数
类型名 函数名()
{
函数体
}
//或
类型名 函数名(void)
{
函数体
}
函数名后面括号内的void表示空,即函数没有参数
定义有参函数
类型名 函数名(形式参数列表)
{
函数体
}
定义空函数
类型名 函数名()
{
}
调用函数
调用函数的方法
C语言要求,在程序中用到的所有函数,必须先定义,后使用。为了使用函数时,可以调用到对应的函数
调用函数的形式:
函数名(实参列表)
如果实参列表没有参数,对应的括号也不能省去,如果有多个实参,使用逗号隔开
调用函数的3中形式
- 函数调用语句:把函数调用单独作为一个语句
- 函数表达式:函数调用出现在另一个表达式中,如a=strcpy_new(a,b)
- 函数参数:作为另一个函数调用时的参数
数据如何传递
无参函数不需要进行数据传递。当函数为有参数函数时,要区别数据是如何传递的
定义有参函数:
类型名 函数名(形式参数列表)
函数名(实参列表)
{
函数体
}
#include <stdio.h>
...
代码1...
...
函数名(实参列表)
...
说明:
- 函数调用过程中,将实参传递给被调用的形参,使得形参对应变量的内容为实参传递的值。值只在调用期间有效
- 实参可以是常量、变量或表达式,但要求它们的值必须是确定的
- 实参和形参的数据类型需要是一致的。如果出现不同类型输出传递,会进行强制转换
返回值
如果需要函数返回一个确定的数值给调用函数,可以通过return语句来实现,也称为函数的返回值
示例;
#include "stdio.h"
int max(int a, int b)
{
return (a > b ? a : b);
}
int main()
{
int a, b;
scanf("%d,%d", &a, &b);
printf("%d\n", max(a, b));
return a;
}
结果:
3,5
5
Press any key to continue
说明:
- 函数的返回值是通过函数中的return语句获得的。如果不需要返回值可以不写return语句,一个函数也可以只有return语句
- 函数的返回值数据类型需要指定,并且返回给调用函数也需要相同
- 定义函数时指定的数据类型和return语句中的表达式结果的数据类型相同
- 无返回值的函数,一般定义为void类型的函数
函数声明
为什么要函数声明?
如果定义的函数位于调用函数之后,需要在主调函数中对别调用的函数作声明。使得在调用函数的时候,编译系统能够正确的识别函数
如何声明?
2种声明形式
- 函数类型 函数名(参数类型1 参数名1, 参数类型2 参数名2, …., 参数类型n 参数名n)
- 函数类型 函数名(参数类型1, 参数类型2 , …., 参数类型n)
最简单的做法:将函数定义的首行(函数原型)赋值过来,再加上一个分号,就成了函数的声明
也可以在文件的最开头对所有调用的函数进行声明,则在各个函数中,不必对所调用的函数再作声明。外部声明在整个文件范围内都是有效的
函数嵌套
函数内部不能再定义函数,但可以在函数内部调用另一个函数,称为函数嵌套
main()
...
调用 max
...
int max()
...
调用 max_2
...
return m
int max_2
...
return 最大值
调用 max --> int max();return m --> 调用 max
调用 max_2 --> int max_2;return 最大值 --> 调用 max_2
函数递归
直接或间接调用函数本身,称为函数的递归调用
无限循环
示例:
#include "stdio.h"
int fun(int i)
{
printf("%d\t", i);
return fun(i + 1);
}
void main()
{
int num;
scanf("%d", &num);
fun(num);
}
结果:
5
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 ...
Press any key to continue
求一个数的阶乘
示例:
#include "stdio.h"
int fact(int n)
{
int f;
if (n == 1)
f = 1;
else
f = fact(n - 1) * n;
return f;
}
void main()
{
int i;
scanf("%d", &i);
printf("%d\n", fact(i));
}
结果:
5
120
Press any key to continue
函数参数为数组
传递数组元素
一般来说,变量都可以使用数组元素替代。因此数组元素也可以作为函数实参进行传递
将数组的元素当作实参传递和变量的传递类似,实参使用数组名[下标];形参使用对应元素的类型即可
求5个数值中的最大值
示例:
#include "stdio.h"
int max(int x,int y)
{
return x>y?x:y;
}
void main()
{
int a[5],b,c,i;
for(i=0;i<5;++i)
scanf("%d",&a[i]);
for(i=1,b = a[0];i<10;++i)
{
c = max(b,a[i]);
if( c > b)
b = c;
}
printf("最大的数为:%d\n",b);
}
结果:
2
5
8
7
6
最大的数为:8
Press any key to continue
传递一维数组名
也可以使用数组名作为函数参数
注意:用数组元素作为实参传递时,是传递数组元素的值,但是用数组名作为实参传递时,传递的是数组元素的首元素地址
求5个数值的平均值
示例:
#include "stdio.h"
float ave(float a[]) //主调函数和被调函数都应该分别定义数组,且数组类型一致
{ //系统不检查形参数组的大小,a[]也可以的
int i; //将实参数组的首元素的地址传递给形参,因此a和num使用相同的内存地址
float b,sum = a[0];
for(i=1;i<5;++i)
sum =sum+a[i];
b = sum/5;
return b;
}
void main()
{
float num[5],average;
int i;
for(i=0;i<5;++i)
scanf("%f",&num[i]);
average = ave(num);
printf("平均值为:%f\n",average);
}
结果:
5
2
7
9
8
平均值为:6.200000
Press any key to continue
num和a使用同一个内存空间,一旦通过a[0]改变了值,对应的num[0]也改变值内容
传递多维数组名
多维数组元素也可以作函数参数使用
注:形参定义多维数组时,行数可以省略
示例:
#include "stdio.h"
int max(int a[][4]) //编译器不会检查第一维的大小
{
int i,j,max;
max = a[0][0];
for(i=0;i<3;++i)
for(j=0;j<4;++j)
if(a[i][j]>max) max = a[i][j];
return max;
}
void main()
{
int a[3][4] = {{3,2,7,4},{8,5,8,3},{2,5,3,8}};
printf("%d\n",max(a));
}
结果:
8
Press any key to continue
局部变量和全局变量
在一个函数中定义的变量能否在其他函数中使用?
示例:
#include "stdio.h"
void fun(int a)
{
int i,j,k ;
i = 10;
j = 12;
k = 3;
printf("fun函数输出:%d\t%d\t%d\t%d\n",i,j,k,a); //输出x,y,z,
}
void main()
{
int x,y,z ;
x = 10;
y = 1001;
z = 1003;
fun(x);
printf("主函数输出:%d\t%d\t%d\n",x,y,z); //输出i,j,k;
}
结果:
fun函数输出:10 12 3 10
主函数输出:10 1001 1003
Press any key to continue
通常变量在函数内部定义,只在本函数范围内有效。这就是变量的作用域
变量定义的范围:
- 局部变量
- 在函数的开头定义
- 在函数内的复合语句内定义
- 全局变量
- 在函数的外部定义
局部变量
注:
- 不同函数中可以使用相同的变量名,但代表的是对应函数内部的数据,互不干扰
- 形式参数也是局部变量
- 程序执行完复合语句或调用函数,系统会将对应占用的内存单元释放
全局变量
全局变量可以为本文件中所有的函数共用
在一个函数既可以使用本函数中的局部变量,又可以使用全局变量。全局变量可以实现各个函数之间数据的直接传递
当出现全局和局部定义了相同的变量名时,优先使用局部变量
示例:
int a = 10; // 各个函数对全局变量进行改变,会使得全局变量发生变化
#include "stdio.h"
void ff()
{
int a = 1000;
int c = 100000;
a++;
printf("%d\t%d\n", a, c);
}
// int b = 1;
void main()
{
int c = 100;
a++;
printf("%d\t%d\n", a, c);
ff();
}
结果:
11 100
1001 100000
Press any key to continue
存在的问题:
- 全局变量在程序的全部执行过程中都暂用存储单元,而不是在需要时才开辟空间
- 各模块之间的耦合性比较强,降低了程序的可靠性
全局变量可以实现各个函数之间数据的直接传递,减少return的传递
示例:
float max = 0, min = 0;
#include "stdio.h"
float ave(float a[])
{
int i;
float b, sum = a[0];
for (i = 1; i < 10; ++i)
{
if (a[i] > max)
max = a[i];
if (a[i] < min)
min = a[i];
sum = sum + a[i];
}
b = sum / 10;
return b;
}
void main()
{
float num[10], average;
int i;
for (i = 0; i < 10; ++i)
scanf("%f", &num[i]);
max = num[0];
min = num[0];
average = ave(num);
printf("平均值为:%f\t最大值为:%f\t最小值为:%f\t", average, max, min);
}
结果:
1
2
3
3
2
4
3
4
5
6
平均值为:3.300000 最大值为:6.000000 最小值为:1.000000
Press any key to continue
存储类别
变量的存储类别:
- 自动的
- 静态的
- 寄存器的
- 外部的
函数中的局部变量,如果没有特别声明static存储类型时,都是动态的分配存储空间
动态存储方式:在程序运行期间根据需要进行动态的分配存储空间
函数的形参、局部变量、复合语句中定义的局部变量都是动态存储方式。在使用时开辟空间,在调用结束时回收对应的空间
auto变量
为了区分变量的存储类别,一般在动态存储变量前面加一个auto(自动变量) 关键字
注:一般默认变量前面是auto类型的变量。可以省略不写
示例:
#include "stdio.h"
void fun(int a)
{
auto int x,y,z ;
x = 10;
y = 12;
z = 3;
printf("fun函数输出:%d\t%d\t%d\t%d\n",x,y,z,a);
}
void main()
{
int x,y,z ;
x = 10;
y = 1001;
z = 1003;
fun(x);
printf("主函数输出:%d\t%d\t%d\n",x,y,z);
}
static变量
static的作用:在定义变量的前面冠上static关键词,表示局部变量的值在函数调用结束后不消失而继续保留原值。在下一次调用该函数时,该变量的值是上一次的值。对应的变量为静态局部变量,属于静态存储方式
静态存储方式:在程序运行期间由系统分配固定的存储空间
示例:
#include "stdio.h"
void fc()
{
auto int a = 0; // 新赋值
static int b = 0; // 使用上一次函数结束后的值
a += 3;
b += 3;
printf("a=%d\tb=%d\n", a, b);
}
void main()
{
fc();
fc();
fc();
}
结果:
a=3 b=3
a=3 b=6
a=3 b=9
Press any key to continue
注:
- 静态局部变量在整个程序运行期间都不释放内存空间
- 在第一次赋值有效,以后不再重新赋值,而是使用上一次函数结束后的值
- 如果不赋初始值,静态局部变量数值类型默认为0,字符默认为\0;自动变量对应是不确定的值
- 不是必要,不要过多的使用静态变量,降低程序的可读性
register变量
寄存器的存取速度远远高于内存的读取速度,因此一般把需要反复读取的变量冠上register,代表寄存器变量
但现代计算机读取速度非常快,性能非常高,编译系统能够识别反复需要读取的变量,从而自动的将对应的变量存放在寄存器中。在实际编写代码中,无需再对变量进行register申明
extern变量
-
在一个文件内扩张外部变量的作用域
如果外部变量没有在文件开头定义,对应的作用域是在定义处到文件的最后。如果在定义点之前需要使用外部变量,可以通过关键字extern对该变量作外部变量声明
示例:
#include "stdio.h" void ff() { extern int a; int c = 100000; a++; printf("%d\t%d\n", a, c); } int a = 10; void main() { int c = 100; a++; printf("%d\t%d\n", a, c); ff(); }
结果:
11 100 12 100000 Press any key to continue
提示:
- 全局变量也是静态存储
- 外部变量的定义放在引用它的所有函数之前,可以避免额外的extern声明
-
当有多个文件时,将外部变量的作用扩张到其他文件
如果一个程序包含多个文件,假如a文件定义了外部变量,b文件要想使用a文件中的外部变量,需要用extern进行变量声明
-
不让别的文件使用本文件的外部变量
定义外部变量时加上static声明
内部函数和外部函数
如果一个函数只能被本文件中其他函数所调用,称为内部函数(静态函数)
在定义函数时,在函数类型的前面加上static声明
如果在定义函数的函数类型前面加上extern关键词,则表示函数是外部函数,可以被其他文件使用
定义函数时,默认都是外部函数,可以省略extern
扩展
设置密码
示例:
#include "stdio.h"
#include "windows.h"
int password;
void password_intput()
{
printf("请输入需要设置的密码:");
scanf("%d", &password);
printf("设置成功\n");
}
void password_validation()
{
int password_verify, i = 0;
while (1)
{
Sleep(10000);
printf("请验证您的密码:");
scanf("%d", &password_verify);
if (password_verify == password)
printf("输入的密码正确\n");
else
{
printf("输入的密码不正确\n");
i++;
}
if (i == 5)
{
printf("五次验证不通过,密码开始锁定\n");
printf("密码锁定中...\n");
break;
}
}
}
void main()
{
password_intput();
password_validation();
}
标签:函数,int,max,void,printf,变量
From: https://www.cnblogs.com/ruoxianshi/p/17004156.html