为什么要使用函数:
避免多次重复编写相同的程序代码,使程序冗长不精炼,便于进行模块化的程序设计
理解
函数就是功能,每一个函数都用于实现一个特定的功能,
函数声明的作用
作用是把有关函数的信息(函数名,函数类型,函数参数的个数和类型)告知编译系统,以便在编译系统对程序进行编译时知道他们是函数而不是变量或者其他对象
注意事项
1)C程序的执行是从main函数开始的,同时在main函数中结束整个函数的运行;
2)所有函数都是平行的,即定义函数是分别进行的,互相独立的,一个函数并不从属于另一个函数,即函数时不能嵌套定义的,函数间可以互相调用(但是不能调用main函数);
3)从用户使用的角度,函数有两种:
a:库函数:系统自己定义的,用户不必自己定义,不同的编译系统提供的库函数是有差别的,
b:用户自定义函数:用以解决用户专门需要的函数,
4)从函数形式上来分,函数有两种:
a:无参函数:主调函数不用向被调用函数传递数据,无参函数可以带回或者不带回函数值,但一般不带回函数值的居多。
b:有参函数:主调函数在调用被调函数时,通过参数向被调函数传递数据,被调函数一般也会返回一个函数值,供主调函数使用
示例一:函数的调用
#include<stdio.h>
int main()
{
void print_star();//声明1函数
void print_message();//声明2函数
print_star();//调用1函数
print_message();//调用2函数
print_star();//调用1函数
putchar('\n');
system("pause");
return 0;
}
void print_star()//定义1函数
{
printf("*******************\n");
}
void print_message()//定义2函数
{
printf("How do you do ?\n");
}
函数的定义;
原因:
C语言中要求,所有用到的函数,必须先定义后使用,如果事先不定义,编译系统怎么会知道这个东西是干什么的,实现的是什么功能呢
定义函数包括:
1)指明函数名,以便以后调用;
2) 指明函数的类型,即函数返回值的类型,这个很关键!也很好理解
3)指明函数的参数名字与类型,以便在调用函数时向他们传递数据,而对于无参函数就不要这一项;
4)指明函数的实现的功能;
注意:对于C编译系统提供的库函数,是由编译系统事先定义好的,程序设计者不需要自己定义,只需要用#include指令把有关的头文件包含到本文件模块中即可;
定义函数的方法:
1.定义无参函数:
类型名 函数名()
{
函数体
}
2.定义有参函数:
类型名 函数名(形式参数表列)
{
函数体
}
函数的调用:
*****函数调用时的数据传递
1.形式参数与实际参数
在调用有参函数时,主调函数与被调函数之间存在数据传递关系:
在定义函数时函数名后面括号中的变量名称为形式参数(或者称为虚拟参数);
在主调函数中调用一个函数时,函数名称后面的参数称为实际参数(或者称之为实参)
2.实参和形参之间的数据传递
在调用函数的过程中,系统会把实参的值传递给形参,或者说形参从实参那里得到一个值,该值在函数调用期间有效,数据传递又被称为虚实结合
示例一 输入两个函数,输出其中的较大者:
#include<stdio.h>
int main()
{
int max(int x, int y);//函数定义的时候,x,y对应的是两个形参
int a, b, c;
printf("please enter two integer numbers:\n");
scanf_s("%d,%d", &a, &b);//此处a,b是两个实参
c = max(a, b);
printf("max is %d:", c);
putchar('\n');
system("pause");
return 0;
}
int max(int a, int b)//到这个地方的时候,a,b又称为两个形参了
{
int z;
if (a >= b)
z = a;
else
z = b;
return(z);//可以加括号,也可以不加括号,不影响结果
}
注意两个int max()的定义,括号内的都是形参,形参是无所谓的,可以看到,代码中两次出现的形参不同,但其实是无所谓的
函数调用的过程
1)在定义函数时的形参,在无函数调用的时候,它们并不占内存的存贮单元,在发生函数调用的时候,函数的形参才会被分配内存单元,这个内存单元还是临时的;
2)将实参对应的值传递给形参
3)通过return语句将函数值带回到主调函数;
4)调用结束之后,形参单元被释放,实参单元仍保留原值没有发生改变;
注意:
实参向形参的数据传递是值传递,是单向传递,只能由实参传递给形参,而不能由形参传递给实参
关于函数的返回值
1)函数的返回值是通过函数的return语句而得到的,,如果需要返回函数值则必须要有return语句,
2)函数值的类型: 既然有返回值,则一定有对应的类型,函数的类型就是返回值的类型,因而
在定义函数时指定的函数类型应该要与return语句的表达式类型一致,函数值的类型决定返回值的类型
3)对于不带回值的函数,应当定义函数类型为void型
被调用函数的声明
在一个函数中调用另一个函数,具备以下条件:
1)首先被调用函数必须是库函数或者用户自己已经定义过的函数;
2)如果使用库函数,必须在文件的开头用#include<stdio.h>
3)如果要使用用户自己定义的函数,必须要先做声明,因为程序是从main函数开始运行的,在被调函数调用之前,对它进行声明,编译系统就对此有了记忆,可以检测出一些语法错误
实际上;函数声明时形参名可以不写,只写形参类型
函数的嵌套调用
注意:C语言中的函数是互相平行的,相互独立的,一个函数内不能在定义另一个函数,函数不能嵌套定义,但是可以嵌套调用
示例二:输入四个整数,找出其中的最大值
#include<stdio.h>
int main()
{
int max4(int a, int b,int c,int d);
int a,b,c,d,max;
printf(“please enter 4 integer numbers:\n”);
scanf_s("%d %d &d %d",&a,&b,&c,&d);
max = max4(a, b, c, d);
printf(“max=%d”, max);
putchar(’\n’);
system(“pause”);
return 0;
}
int max4(int a, int b,int c,int d)
{
int max2(int x,int y);
int m=0;
m = max2(a, b);
m = max2(m, c);
m = max2(m, d);
return(m);
}
int max2(int a, int b)
{
if (a >= b)
return(a);
else
return(b);
}
数组作为函数参数
1)数组元素可以作为函数实参;
2)数组名可以作为实参和形参,传递的是数组第一个元素的地址;
数组元素作为函数实参
数组元素可以用作函数实参,但不能用作函数实参
原因:因为形参在函数被调用时临时分配储存单元,不可能为一个数组元素单独分配存储单元,(数组是一个整体,在内存中占的是一段连续的存储单元)
示例三:输入10个数,要求输出其中最大的数,并且要指明是第几个;
#include<stdio.h>
int main()
{
int max(int x, int y);
int a[50], m, n, i;
printf("please enter 10 integer numbers:\n");
for (i = 0; i < 10; i++)
scanf_s("%d", &a[i]);
printf('\n');
for (i = 1, m = a[0], n = 0; i < 10; i++)
{
if (max(m, a[i])> m)
{
m = max(m, a[i]);
n = i;
}
}
printf("the biggest number is %d\nthe location is %d\n", m, n+1);
putchar('\n');
system("pause");
return 0;
}
int max(int x, int y)
{
if (x >= y)
return(x);
else
return(y);
}
上面这段代码我在VS2017中运行时会报一种很奇怪的错误,难以解决,无奈之下转移到了VC++6.0里面,稍加更改,即可运行,如下所示:
#include<stdio.h>
int main()
{
int max(int x, int y);
int a[50], m, n, i;
printf("please enter 10 integer numbers:\n");
for (i = 0; i < 10; i++)
scanf("%d", &a[i]);
printf("\n");
for (i = 1, m = a[0], n = 0; i < 10; i++)
{
if (max(m, a[i])> m)
{
m = max(m, a[i]);
n = i;
}
}
printf("the biggest number is %d\nthe location is %d\n", m, n+1);
putchar('\n');
return 0;
}
int max(int x, int y)
{
if (x >= y)
return(x);
else
return(y);
}
数组名做函数参数
1)数组元素做实参时,像形参变量传递的是数组元素的值;
2)数组名做实参时,向形参传递的是数据首元素的地址;
示例四:有一个一维数组score,内放10个学生成绩,求其平均成绩
#include<stdio.h>
int main()
{
float average(float array[10]);
float score[50], aver;
int i;
printf("please input 10 scores:\n");
for (i = 0; i < 10; i++)
scanf_s("%f", &score[i]);
printf("\n");
aver = average(score);
printf("the average score is %5.2f:\n",aver);
putchar('\n');
system("pause");
return 0;
}
float average(float array[10])
{
int i;
float aver, sum = array[0];
for (i = 1; i < 10; i++)
sum = sum + array[i];
aver = sum / 10;
return(aver);
}
注意:
1)用数组名作为函数参数,应该在主调函数和被调函数中都分别定义数组;在上个例子中,array是形参数组名,score是实参数组名,
2)实参数组与形参数组类型应该一致;
3)形参数组可以不指定大小,因为C语言编译系统并不会检查形参数组的大小,只是将实参数组的首元素的地址传给形参数组名,形参数组获得了实参数组首元素的地址
示例五:有两班级,分别有35名和30名学生,分别求这两个班学生的平均成绩:
#include<stdio.h>
int main()
{
float average(float array[],int n);
float score1[5]={98.5,97,91.5,60,55};
float score2[10]={67.5,89.5,99,69.5,77,89.5,76.5,54,60,99.5};
printf("the average of classs A is%6.2f\n",average(score1,5));//用数组名score1和5作为实参
printf("the average of class B is%6.2f\n",average(score2,10));//用数组名score2和10作为实参
putchar('\n');
return 0;
}
float average(float array[],int n)//定义average函数,但未指明形参数组的长度
{
int i;
float aver,sum=array[0];
for(i=1;i<n;i++)//累加n个学生的成绩
sum=sum+array[i];
aver=sum/n;
return(aver);
}
用同一个函数巧妙求出来了两个不同长度的数组的平均值问题
我们在定义自定义函数时,不必指明数组的长度,让数组的长度作为函数的一个形参(也就是体现到for循环中的循环次数)
用选择法进行排序
思路:每比较一轮,找出一个未经排序的数中最小的一个
示例六:任意输入10个数,构成一个一维数组,并将其从小到大排列
#include<stdio.h>
int main()
{
void sort(int array[],int n);
int a[10],i;
printf("please input the array:\n");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
printf("\n");
sort(a,10);
printf("the sorted array is as follows:\n");
for(i=0;i<10;i++)
printf("%d ",a[i]);
putchar('\n');
return 0;
}
void sort(int array[],int n)
{
int i,j,k,t;
for(i=0;i<n-1;i++)
{
k=i;
for(j=i+1;j<n;j++)
{
if(array[j]>array[k])
k=j;
t=array[k];
array[k]=array[i];
array[i]=t;
}
}
}
多维数组名用作函数参数
注意细节:可以用多维数组名作为函数的实参和形参,在被调用函数中对形参进行定义时可以指定每一维的的大小,也可以省略第一维的大小,C语言的编译系统并不检查第一维的大小
打擂算法找最值
示例七:有一个3*4的矩阵,求出所有元素中的最大值
#include<stdio.h>
int main()
{
int max_value(int array[3][4]);
int a[3][4]={{1,3,5,7,},{2,4,6,8},{15,17,34,12}};
printf("the MAX value is %d\n",max_value(a));
putchar('\n');
return 0;
}
int max_value(int array[3][4])
{
int i,j,max;
max=array[0][0];
for(i=0;i<3;i++)
{
for(j=0;j<4;j++)
{
if(array[i][j]>max)
max=array[i][j];
}
}
return(max);
}
直插法排序
思路:插入排序是把一个数插入到一个已排序的有序序列之中,使整个序列在插入数据之后仍然有序
示例八:键盘任意输入10个数,直插法按从小到大排序:
#include<stdio.h>
int main()
{
void insort(int s[],int n);
int a[11],i;
printf("please input the array:\n");
for(i=0;i<=10;i++)
scanf("%d ",&a[i]);//接受从键盘输入的10个数据到数组a
printf("the original order is as follows:\n");
for(i=1;i<11;i++)
printf("%5d",a[i]);//将未排序的数值顺序输出
insort(a,10);
printf("\nthe sorted array is as follows:\n");//输出排序后的数组
for(i=1;i<11;i++)
printf("%5d",a[i]);
putchar('\n');
return 0;
}
void insort(int s[],int n)//右端插入,向左移动的直插函数
{
int i,j;
for(i=2;i<=n;i++)//数组下标从2开始,因为一个数据无可比性,0标永远做监视哨
{
s[0]=s[i];//给监视哨赋初值
j=i-1;
while(s[0]<s[j])
{
s[j+1]=s[j];//插入的数据向左移动,其他数据向右移动
j--;
}
s[j+1]=s[0];
}
}
#include <stdio.h>
void insort(int s[], int n) /*自定义函数isort*/
{
int i, j;
for (i = 2; i <= n; i++) /*数组下标从2开始,0做监视哨,1一个数据无可比性*/
{
s[0] = s[i]; /*给监视哨赋值*/
j = i - 1; /*确定要进行比较的元素的最右边位置*/
while (s[0] < s[j])
{
s[j + 1] = s[j]; /*数据右移*/
j--; /*移向左边一个未比较的数*/
}
s[j + 1] = s[0]; /*在确定的位置插入s[i]*/
}
}
main()
{
int a[11], i; /*定义数组及变量为基本整型*/
printf("please input number:\n");
for (i = 1; i <= 10; i++)
scanf("%d", &a[i]); /*接收从键盘中输入的10个数据到数组a中*/
printf("the original order:\n");
for (i = 1; i < 11; i++)
printf("%5d", a[i]); /*将为排序前的顺序输出*/
insort(a, 10); /*调用自定义函数isort()*/
printf("\nthe sorted numbers:\n");
for (i = 1; i < 11; i++)
printf("%5d", a[i]); /*将排序后的数组输出*/
printf("\n");
}
示例九:统计字符串中大写字母的个数:
int cap(char c)//自定义cap函数,用以判断字母是不是大写字母
{
if (c>='A'&&c<='Z')
return 1;//如果是大写字母,就返回1;
else
return 0;//若不是大写字母,就返回0;
}
main()
{
int i,num=0;
char str[100];//自定义字符型数组
printf("Input a string: ");
gets(str);//获取输入的字符串
for(i=0;str[i]!='\0';i++)//这个意思就是遍历字符串
if (cap(str[i]))//调用函数判断字母是不是大写字母
num++;
puts("the string is:");
puts(str);输出字符串
printf("num=%d\n",num);
}
示例10:计算学生的平均身高
#include<stdio.h>
main()
{
float average(float array[],int n);
float height[100],aver;
int i,n;
printf("please input the number of students:\n");
scanf("%d",&n); /*输入学生数量*/
printf("please input student`s height:\n");
for(i=0;i<n;i++)
scanf("%f",&height[i]); /*逐个输入学生的身高*/
printf("\n");
aver=average(height,n); /*调用average函数求出平均身高*/
printf("average height is %6.2f",aver); /*将平均身高输出*/
}
float average(float array[],int n) /*自定义求平均身高函数*/
{
int i;
float aver,sum=0;
for(i=0;i<n;i++)
sum+=array[i]; /*用for语句实现sum累加求和*/
aver=sum/n; /*总和除以人数求出平均值*/
return(aver); /*返回平均值*/
}
示例11:计算两个数加减乘除后的结果
#include<stdio.h>
float add(float x,float y);//相应函数的声明
float sub(float x,float y);
float mul(float x,float y);
float div(float x,float y);
main()
{
float x,y;
printf("please input x and y:\n");
scanf("%f %f",&x,&y);//输入方式最重要,一定要注意,是空格,还是逗号
printf("addition:%f\n",add(x,y));
printf("subtration:%f\n",sub(x,y));
printf("multiplication:%f\n",mul(x,y));
printf("division:%f\n",div(x,y));
}
float add(float x,float y)
{
float z;
z=x+y;
return z;
}
float sub(float x,float y)
{
float z;
if(x>y)
z=x-y;
else
z=y-x;
return z;
}
float mul(float x,float y)
{
float z;
z=x*y;
return z;
}
float div(float x,float y)
{
float z;
z=x/y;
return z;
}