/*
* 为什么要用函数:
* 提前设计好函数用来实现不同的功能,编写程序过程中就可以直接调用这些函数,避免重复编写
* 函数就是功能,每一个函数用来实现一个特定的功能,函数的名字应该反应期望代表的功能
* 1、一个c程序由一个或者多个程序模块组成,每一个程序模块作为一个源程序文件,一个源程序文件可以为多个c程序公用
* 2、一个源程序文件是一个编译单位,程序编译时以一个源程序为编译单位,而不是一个函数为单位。
* 3、c程序的执行都是从main函数开始的,也从main函数结束
* 4、函数之间可以互相调用,但是不可以调用主函数,main函数是被操作系统调用的
* 5、从用户的角度看,函数一共由两种,库函数和自己定义的函数
* 库函数:系统提供,用户不必自己定义,可以直接使用他们,不同编译系统提供的库函数可能有所不同,但许多基本函数还是共同的
* 用户自己定义的函数,他用来解决用户需要的函数
* 6、从函数形式上看,函数一共分为两种无参函数和有参函数
* 无参函数:main函数不需要给调用函数传递参数数据,一般用来执行指定的一组操作
* 有参函数:调用函数时,向调用函数传递数据,一般执行点用函数后会得到一个函数值返回到主函数中使用,此时有参函数应该定义为与返回值同一个类型
* 怎样定义函数:
* 1、指定函数的名字,便于调用
* 2、指定函数的类型,即函数返回值的类型
* 3、指定函数的参数的名字和类型,调用函数时方便向他们传递数据,无参函数不需要
* 4、指定函数应该完成什么操作,也就是函数的功能,这是最重要的
* 定义函数的方法:
* 定义无参函数: 类型名 函数名()//或者 类型名 函数名(void)//void表示空
* {
* 函数体//包括声明部分和语句部分
* }
* 定义有参函数: 类型名 函数名(形式参数列表)
* {
* 函数体//包括声明部分和语句部分
* }
* 定义空函数: 类型名 函数名()
* {
* }
* 调用函数:
* 调用函数的形式:函数名(实参表列)
* 1、函数调用语句:
* 把调用函数单独作为一个语句,这时函数不要求带回值,只要求函数完成一定操作
* max(a,b);
* 2、函数表达式:
* 函数调用出现在另外一个表达式中,要求函数带回一个确定的值来参加表达式的运算
* c=2*max(a,b);
* 3、函数参数
* 函数调用,作为另一个函数的实参;
* m=max(a,max(b,c));
* 调用函数时的数据传递:
* 1、形式参数和实际参数(两者类型相同或者兼容)//单向传递
* 定义函数时()里的变量名称为形式参数;
* 调用函数时()里的是实际参数;可以是常量,变量,表达式,但是必须要有固定的值
* 2、形式参数和实际参数之间的数据传递
* 系统会自动把实际参数的值传递给形式参数,这个值在哈桑农户调用期间有效,并且参与运算;
* 调用函数的过程:
* 1、在定义哈桑农户中的形参时,在未出现函数调用时,他们并不占用内存中的储存单元,在函数发生调用时,才分配内存空间
* 2、将实参的值传递给对应形参;
* 3、执行调用函数时,形参已经有值,所以可以直接运算
* 4、通过return,把函数值带回主调函数,返回值类型因该与函数类型一致;如果函数不需要返回值,函数类型应该定义为void类型
* 5、调用结束形参单元被释放(实参仍然保持原值,形参的值改变不会影响到实参的值);
* 函数的返回值:
* 通常,希望通过一个函数调用使主函数得到一个确定的值,这就是函数返回值。
* 函数返回值通过return语句获取,不需要返回值可以没有return语句
* 可以有一个以上的return语句,执行到哪一个就返回哪一个函数值;
* 函数值的类型:(与调用函数的类型相同)
* int a(float a,float b)//返回值为整型
* char b(char a,char b)//返回值为字符型
* double a(int x,int y)//返回值为双进度型
* 定义函数时,return语句中表达式的类型应该和调用函数的类型相同
* 对于不带返回值的函数,定义为void类型
* 对被调用函数的声明和函数原型:
* 在一个函数中调用另一个函数需要具备以下条件:
* 1、函数必须是已经定义的函数;
* 2、库函数必须引用头文件
* 3、使用自己定义的函数,如果调用函数在主函数之后,在主函数中要进行声明
* (使用函数原型做声明是C语言的一个重要特点)形参名可写可不写,是什么都无所谓
* 在主函数之前做了声明,在各函数调用中不用重复声明
* 函数的镶套调用:
* 调用函数内不能定义另外一个函数但是可以引用
* 数组作为函数参数:
* 数组元素作为实参
* 一维数组名作为参数:除了数组元素外,还可以用数组名作为函数参数(包括实参和形参)
* 数组元素做实参传递的是数组元素的值,数组名做函数实参,传递的是数组首元素的地址
* 实参类型与形参类型应该保持一致
* 形参首元素地址和实参首元素地址具有同一地址,指同一个单元
* 形参数组可以不指定大小:int arr[];
* 因为实参和形参首地址相同,所以可以通过改变形参来改变实参;
* 多维数组名做函数参数:多维数组元素可以作为函数参数
* 在调用函数中,对形参定义时可以只定义一维的大小
* int brr[3][10];或int brr[][10];
* 局部变量和全局变量:
* 局部变量:一个在函数内部定义的变量只在函数范围内有效,只有能在函数内部才能引用他们,在此函数外不能使用这些变量;
* 在复合语句内定义的变量只能在复合语句中使用,在复合语句({多个语句})外不能使用这些变量;
* 定义变量的三种情况:
* 在函数开头定义;
* 在函数内的复合语句定义;
* 在函数外部定义;
* 主函数中定义的变量只在主函数中有效,不能因为是在主函数中定义就在整个文件中有效;
* 不同函数可以使用同名的变量,两者之间互不干扰;
* 形式参数也是局部变量;
* 在函数内部,复合语句中也可以定义变量,这些变量只在本复合语句中有效;
* 全局变量:在函数之外定义的变量是外部变量,是全局变量,全局变量,可以为本文件其他函数共用,有效范围是定义变量开始到本源文件结束;
* 在函数内定义的是局部变量,在函数外定义的是全局变量;
* 增加了函数之间的联系,相当于各个函数之间有了直接的传输通道,由于函数调用只能带回一个返回值,因此可以使用全局变量来增加函数之间的联系渠道
* 不建议使用
* 原因:1、全局变量在程序执行过程中都要占用存储单元,而不是在需要时开辟单元;
* 2、通用性降低,函数中如果引用了全局变量,那么执行情况会受到有关外部变量的影响,函数如果转移到另外一个文件中,有关全局变量也要转移
* 可能会出现与其他变量重名的情况,降低了程序的可靠性和通用性,通常要求模块功能要单一,与外界相互联系尽量少,通过实参,形参的形式和外界联系
* 这样的程序可读性强,移植性好。
* 3、全局变量过多会降低函数的清晰性,各个函数执行时都有可能改变全局变量的值,程序容易出错
* 全局变量和局部变量同名,在局部变量作用范围内,局部变量有效,全局变量被屏蔽,不起作用。
*变量的储存方式和生存周期:
* 动态存储方式和静态存储方式
* 静态:在程序运行期间由系统分配的固定的存储空间的方式
* 动态:在程序运行期间,根据需要进行动态的分配存储空间的方式
* 内存中供用户使用的存储空间的情况:
* 1、程序区
* 2、静态存储区
* 3、动态存储区
* 全局变量存放在静态存储区,在程序开始时分配,程序结束释放
* 动态存储区存放以下内容:
* 1、函数的形式参数:在调用函数时给形参分配存储空间
* 2、在函数定义中没有用到关键字static声明的变量,即自动变量
* 3、函数调用时现场保护和返回地址等
* 每一个变量和函数都有两个属性:数据 类型和数据的存储类别;
* C语言的数据存储类别:
* 自动的,静态的,寄存器的,外部的
* 根据变量的存储类别可以知道变量的作用域和生存周期;
* 局部变量的存储类别
* 1、自动变量(auto):动态存储区
* 函数中的局部变量如果不声明是static存储类别,都动态的分配存储空间,函数的形参和函数定义的局部变量都是,调用函数时分配空间,调用结束,释放空间,这一类局部变量称为自动变量
* 2、静态局部变量(static):静态存储区
* 函数调用结束后不消失,保留原值,占用的存储单元不释放,下一次调用时,变量已经有值,这时指定该局部变量为静态局部变量(static)
* 3、寄存器变量(rigister):cpu的寄存器
* 如果一些变量使用频繁,则允许将变量的值存放在寄存器中,可以提高执行效率
* 全局变量的存储类别:(静态存储区)
* 1、在文件内扩展外部变量的作用域
* exterm,将外部变量的作用域扩展到此位置
* 可以不指定类型,因为不是定义,是引用
* 2、将外部作用域扩张到其他文件
* extern 两个文件都要使用同一个外部变量时,在其中一个定义,另外一个用extern引用
* 3、将全局变量作用域限制在本文件中
* 用static定义外部变量,在另一个文件用extern中引用,不能成功,被限制在本文件中
* static 声明一个变量的作用:
* 1、对局部变量,把他分配在静态存储区域,在程序执行期间,分配空间不释放,始终存在。
* 2、对全局变量,该变量的作用域限制在本文件。
* 存储类别小结:
* 对一个数据的定义需要两方面:数据类型,存储类别
* 关于变量的声明和定义:
* 把建立存储空间的声明叫做定义,把不需要建立存储空间的叫做声明。
* 内部函数和外部函数:
* 函数的本质上是全局的,定义一个函数的目的就是为了方便调用,不添加声明,则表示函数可以被本文件的函数调用也可以被其他文件调用
* 根据函数是否能被其他源文件调用分为两个:外部函数和内部函数。
* 内部函数:函数只能被本文件中的函数调用。(静态函数)
* static 类型名 函数名
* 优点:使函数局部化,其他文件包含能引用,提高了可靠性。
* 外部函数:定义函数时在最左端加关键字extern,则是外部函数,可以供其他文件调用
* extern 类型名 函数名
*/
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<math.h>
#include<string.h>
//在主函数之前做了声明,在各函数调用中不用重复声明
int max1(int x, int y);
int max2(float x, float y);
void xingxing();
void aini();
float sum(float x, float y);
//int main()
//{
// char c[] = "asdfghjj";
// for (int i = 0; i < 4; i++)
// {
// scanf("%c", &c[i]);
//
// }
// printf("%s", c);
//}
//递归求n!
int jiecheng(int x)//三种情况,>0;<0;=0;
{
if (x < 0)
{
return 0;
}
else if (x == 0)
{
return 1;
}
else
{
return jiecheng(x - 1) * x;
}
}
//第一个学生10岁,每个比前一个大2岁,求第五个学生多大
int wu(int x)
{
return x += 2;
}
//输入两个小数比较较大者,输出整数;
int max2(float x, float y)
{
return x > y ? x : y;
}
//输出特定文字
void xingxing()
{
printf("************************\n");
}
void aini()
{
printf("i love you\n");
}
//输出两个整数,要求输出其中值较大者
int max1(int x, int y)
{
int z;
z = x > y ? x : y;
return z;
//return x > y ? x : y;
}
//找出两个数中最小的
int min(int x, int y)
{
return x < y ? x : y;
}
//有一个3*4的矩阵,求所有元素的最大值
int shuzuzuida(int a[][4])
{
int max = a[0][0];
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
if (max < a[i][j])
{
max = a[i][j];
}
}
}
return max;
}
//有一个一维数组,内存放10个学生的成绩,写一个函数,当主函数调用后能求出平均分,最高分,和最低分
//定义全局变量
float max=0;
float min1=0;
//有一维数组score内存放10个学生的成绩,求平均成绩
//两次调用数组长度不同
float pingjun(float arr[], int x)
{
float sum = 0;
float k;
max = arr[0];
min1 = arr[0];
for (int i = 0; i < x; i++)
{
sum += arr[i];
if (max < arr[i])
{
max = arr[i];
}
if (min1 > arr[i])
{
min1 = arr[i];
}
}
k = sum / x;
return k;
}
//考察静态局部变量的值
int f(int a)
{
int b = 0;
static int c = 3;//c的值不发生改变,存储单元不释放;
b = b + 1;
c = c + 1;
return (a + b + c);
}
//输出1-5的阶乘
int jie(int x)
{
static int n=1;//n不释放,避免调用重新赋值
n *= x;
return n;
}
int main()//主函数调用函数
{
//输出1-5的阶乘
for (int i = 1; i < 6; i++)
{
printf("%d ", jie(i));
}
//考察静态局部变量的值
int a = 2;
for (int i = 0; i < 3; i++)
{
printf("%d\n", f(a));
}
//有一个一维数组,内存放10个学生的成绩,写一个函数,当主函数调用后能求出平均分,最高分,和最低分,
float d[10];
for (int i = 0; i < 10; i++)
{
scanf("%f", &d[i]);
}
pingjun(d,10);
printf("%f %f %f", min1, max, pingjun(d, 10));
//有一个3*4的矩阵,求所有元素的最大值
int c[3][4] = { {1,2,3},{9,8,7},{6,7,5} };
printf("%d", shuzuzuida(c));
//输出两个整数,要求输出其中值较小者
int a, b;
scanf("%d %d", &a, &b);
printf("%d ", min(a, b));
//用选择法对数组中的十个整数按照由小到大进行排序
int brr[10];
for (int i = 0; i < 10; i++)
{
scanf("%d", &brr[i]);
}
for (int i = 0; i < 10; i++)
{
for (int j = i+1 ; j < 10; j++)
{
if (min(brr[i],brr[j])<brr[i])
{
int tmp;
tmp = brr[i];
brr[i] = brr[j];
brr[j] = tmp;
}
}
printf("%d ", brr[i]);
}
//有两个班级,分别有35 30个人,分别求平均成绩
float score1[35];
int n1 = 35;
int n2 = 30;
float score2[30];
printf("一班成绩");
for (int i = 0; i < n1; i++)
{
scanf("%f", &score1[i]);
}
printf("二班成绩");
for (int i = 0; i < n2; i++)
{
scanf("%f", &score2[i]);
}
printf("%5.2f\n", pingjun(score1, n1));
printf("%5.2f", pingjun(score2, n2));
//有一维数组score内存放10个学生的成绩,求平均成绩
float score[10];
for (int i = 0; i < 10; i++)
{
scanf("%f", &score[i]);
}
printf("%f", pingjun(score));
//输入10个数,要求输出其中最大值元素和在第几个
int a[10];
for (int i = 0; i < 10; i++)
{
scanf("%d", &a[i]);
}
printf("\n");
int m;
int k=a[0];
for (int i3 = 0; i3 < 10; i3++)
{
if (max1(a[i3], a[i3 + 1])>k )
{
k = max1(a[i3], a[i3 + 1]);
}
}
printf("%d\n", k);
//递归求n!
int n;
scanf("%d", &n);
printf("%d", jiecheng(n));
//第一个学生10岁,每个比前一个大2岁,求第五个学生多大
int i2=10;
for (int i1 = 1; i1 < 5; i1++)
{
i2=wu(i2);
}
printf("%d", wu(i2));
//输入四个整数,找出其中最大的数
int a1,a2,a3,a4;
scanf("%d %d %d %d", &a1, &a2,&a3,&a4);
printf("%d", max1(a1,max1(a2,max1(a3,a4)) ));
//输入两个小数比较较大者,输出整数;
float sum(float x, float y);//sum()函数在主函数后,要在主函数中进行声明
float sum(float , float );//声明中只写类型不写形参名也是正确的,写什么都可以
float c ,d;
scanf("%f %f", &c, &d);
printf("%d",max2(c,d));
// 输出两个实数之和
printf("%f", sum(c, d));
//输出两个整数,要求输出其中值较大者
int a, b;
scanf("%d %d", &a, &b);
printf("%d", max1(a, b));
//输出特定文字
xingxing();
aini();
xingxing();
return 0;
}
//输入两个实数,用函数求他们之和
float sum(float x, float y)
{
return x + y;
}