目录
函数引入:
函数要先定义再使用,和变量一个道理。
函数的三要素:
- 函数名(体现功能);
- 参数列表(比如y=f(x)中, x就是参数;y=f(x,y), x,y就是参数;参数的个数可以根据用户需求定义);
- 返回值(比如y=f(x)中y就是函数根据x的值和f的功能执行后的结果)。
函数体:执行什么样的功能,涉及的处理代码叫函数体。
定义无参数函数:
编程练习:
#include <stdio.h>
void PrintWelcome()
{
printf("=============\n");
printf("欢迎来C的世界\n");
printf("=============\n");
}
int main()
{
PrintWelcome();
return 0;
}
定义有参数有返回值的函数:
编程练习:
#include <stdio.h>
//函数三要素:返回值、参数列表、功能
int Add(int data1,int data2) //函数类型
{
int result ;
result = data1 + data2;
return result;
}
int main()
{
int x;
int y;
int result;
int result1;
printf("请输入两个整数\n");
scanf("%d%d",&x,&y);
result = Add(x,y);
result1 = Add(x,y)+100;
printf("两个数的和为:%d\n",result);
printf("函数当作表达式:%d\n",result1);
printf("函数当作被调用的函数:%d\n",Add(x,y)+100);
return 0;
}
函数调用注意事项:
- 定义空函数:程序设计,模块设计(先定义空函数然后封装);
- 带返回值类型:例如 int add(2,3);
- 形参带类型:add(int a,int b);
- 函数见怪不怪的表达方法:① 函数可以当作表达式:result1 = Add(x,y)+100; ② 函数调用当做其他函数调用的参数 : printf("函数当作被调用的函数:%d\n",Add(x,y)+100)。
形式参数和实际参数:
传递参数,传递的是值,形参和实参值相同,但是地址空间不同
代码验证:
#include <stdio.h>
int PrintResult(int data1,int data2)
{
int result;
result = data1 + data2;
printf("形参data1=%d,地址为%p\n",data1,&data1);
printf("形参data2=%d,地址为%p\n",data2,&data2);
return result;
}
int main()
{
int data1 = 10;
int data2 = 20;
int result;
result = PrintResult(data1,data2);
printf("实参data1=%d,地址为%p\n",data1,&data1);
printf("实参data2=%d,地址为%p\n",data2,&data2);
printf("result = %d\n",result);
return 0;
}
局部变量:
顾名思义,变量作用的范围有限。
编程练习:
①:输入两个整数,要求输出其较大值,用函数实现
/*
输入两个整数,要求输出其较大值,用函数实现
*/
#include <stdio.h>
int GetBigOneFrom(int data1,int data2)
{
int max;
max = data1>data2 ? data1:data2; //作用和下边一样
/*if(data1>data2)
{
max = data1;
}
else
{
max = data2;
}*/
return max;
}
int main()
{
int data1;
int data2;
int max;
printf("请输入两个整数\n");
scanf("%d%d",&data1,&data2);
max = GetBigOneFrom(data1,data2);
printf("两个数中较大值为:max = %d\n",max);
return 0;
}
②:输入两个小数,要求输出其较大值,用函数实现
/*
输入两个小数,要求输出其较大值,用函数实现
*/
#include <stdio.h>
float GetBigOneFrom(float data1,float data2)
{
float max;
max = data1>data2 ? data1:data2; //作用和下边一样
/*if(data1>data2)
{
max = data1;
}
else
{
max = data2;
}*/
return max;
}
int main()
{
float data1;
float data2;
float max;
printf("请输入两个小数\n");
scanf("%f%f",&data1,&data2);
max = GetBigOneFrom(data1,data2);
printf("两个小数中较大值为:max = %.4f\n",max);
return 0;
}
③:输入两个字符,要求输出其较大字符,用函数实现
/*
输入两个字符,要求输出其较大字符,用函数实现
*/
#include <stdio.h>
char GetBigOneFrom(char data1,char data2)
{
char bigger;
bigger = data1>data2 ? data1:data2; //作用和下边一样
/*if(data1>data2)
{
bigger = data1;
}
else
{
bigger = data2;
}*/
return bigger;
}
int main()
{
char data1;
char data2;
char bigger;
printf("请输入两个字符\n");
scanf("%c%c",&data1,&data2); //输入的时候不要敲空格或者回车等字符!!!
bigger = GetBigOneFrom(data1,data2);
printf("两个小数中较大值为:bigger = %c\n",bigger);
return 0;
}
函数的调用过程:
- 在定义函数中指定的形参,在未出现函数调用时,它们并不占内存中的存储单元。在发生函数调用时,函数max的形参被临时分配内存单元。
- 将实参对应的值传递给形参。如图73所示,实参的值为2把2传递给相应的形参x,这时形参x就得到值2,同理,形参y得到值3。
- 如果函数返回类型是void,函数体可以不用加return,返回值要注意类型,如果类型不同,可能会发生强制转换影响结果或编译警告。
- 通过return语句将函数值带回到主调函数。例72中在return语句中指定的返回值是z这个z就是函数max的值(又称返回值)。执行return语句就把这个函数返回值带
回主调函数main。应当注意返回值的类型与函数类型一致。如max函数为int型,返回值
是变量z,也是int型。二者一致。 - 调用结束,形参单元被释放。注意:实参单元仍保留并维持原
值,没有改变。如果在执行一个被调用函数时,形参的值发生改变,不会改变主调函数的实参的值。例如,若在执行max函数过程中x和y的值变为10和15,但a和b仍为2和3,见图74。这是因为实参与形参是两个不同的存储单元。
函数调用的条件:
- 函数已被定义
- 调用库函数(比如#include<stdio.h> #include<math.h>)
- 函数的声明:如果使用用户自己定义的函数,而该函数的位置在调用它的函数(即主调函数)的后面(在同一个文件中),应该在主调函数中对被调用的函数作声明(declaration)。声明的作用是把函数名、函数参数的个数和参数类型等信息通知编译系统,以便在遇到函数调用时,编译系统能正确识别函数并检查调用是否合法。
函数的嵌套:
编程练习:输入四个数,函数方式找出最大值
/*
输入四个数,函数方式找出最大值
*/
#include <stdio.h>
int GetDataFromTwo(int a,int b)
{
int bigger;
bigger = a>b ? a:b;
return bigger;
}
int GetDataFromFour(int a,int b,int c,int d)
{
int biggest;
biggest = GetDataFromTwo(a,b);
biggest = GetDataFromTwo(biggest,c);
biggest = GetDataFromTwo(biggest,d);
return biggest;
}
int main()
{
int data1;
int data2;
int data3;
int data4;
int max;
printf("请输入四个整数\n");
scanf("%d%d%d%d",&data1,&data2,&data3,&data4);
max = GetDataFromFour(data1,data2,data3,data4);
printf("四个数中的最大值是:%d\n",max);
return 0;
}
函数的递归:
编程练习:
#include <stdio.h>
int GetageFrom(int num)
{
int age;
if(num==1)
{
age = 10;
}
else
{
age = GetageFrom(num-1)+2; //如果num不为1,一直递减到为1,把age的数取回来后再进行运
// 算,返回age给main函数
}
return age;
}
int main()
{
int num;
int age;
printf("请问你想知道第几个人的年龄?\n");
scanf("%d",&num);
age = GetageFrom(num);
printf("第%d个人的年龄是:%d",num,age);
return 0;
}
/*
n的阶乘
*/
#include <stdio.h>
#include <stdlib.h>
int GetFactorialFrom(int num)
{
int result = 0;
if(num>=17)
{
puts("越界");
exit(-1);
}
if(num==1)
{
result = 1;
}
else
{
result = GetFactorialFrom(num-1) * num;
}
return result;
}
int main()
{
int num;
int result;
puts("请问您想知道几的阶乘?");
scanf("%d",&num);
result = GetFactorialFrom(num);
printf("%d的阶乘是%d\n",num,result);
return 0;
}
数组名当做函数实际参数:当数组名作为函数实际参数的时候,也是值传递,但数组名传递的是数组的首地址。
#include <stdio.h>
void PrintArray(int a[],int len)//形参中不存在数组的概念,即便中括号约定了数组的大小,但无效
//传递的是一个地址,是数组的首地址
{
int i;
//printf("形参:%d\n",sizeof(a)); //在操作系统中用8byte表示一个地址
for(i=0;i<len;i++)
{
printf("%d ",a[i]);
}
}
int main()
{
int a[] = {21,54,34,97,64};
int len = sizeof(a)/sizeof(a[0]);
printf("实参:%d\n",sizeof(a)); //求实参所占内存空间大小
//PrintArray(a,len); //传递数组名就是传递数组的首地址
PrintArray(&a[0],len); //第一个元素的地址就是数组的首地址
return 0;
}
有趣的案例①:
#include <stdio.h>
void GetChange(int data)
{
data = data + 100;
printf("GetChange函数中的data = %d\nGetChange函数中的data地址是%p\n",data,&data);
}
int main()
{
int data = 10;
GetChange(data);
printf("main函数中的data = %d\nGetChange函数中的data地址是%p\n",data,&data);
return 0;
}
有趣的案例②:
#include <stdio.h>
void GetChange(int data[])
{
data[0] = data[0] + 100;
printf("GetChange中的data = %d\nGetchange函数中data的地址是:%p\n",data[0],&data[0]);
}
int main()
{
int data[] = {12,24};
GetChange(data);
printf("main函数中data = %d\nmain函数中data的地址是:%p\n",data[0],&data[0]);
return 0;
}
编程练习:有两个班的同学,分别是10个人和5个人,分别求这两个班的平均分 。
#include <stdio.h>
void InitArray(int array[],int len)
{
int i;
for(i=0;i<len;i++)
{
printf("请输入第%d个学生的成绩:\n",i+1);
scanf("%d",&array[i]);
}
puts("输入完毕");
}
void PrintArray(int array[],int len)
{
int i;
printf("总人数为:%d\n",len);
for(i=0;i<len;i++)
{
printf("%d ",array[i]);
}
puts("\n打印完毕\n");
}
float GetAverage(int array[],int len)
{
int i;
int sum = 0;
float average;
for(i=0;i<len;i++)
{
sum += array[i];
}
average = (float)sum/len;
return average;
}
int main()
{
int ClassOne[5];
int ClassTwo[10];
int len1 = sizeof(ClassOne)/sizeof(ClassOne[0]);
int len2 = sizeof(ClassTwo)/sizeof(ClassTwo[0]);
float average1;
float average2;
InitArray(ClassOne,len1);
InitArray(ClassTwo,len2);
PrintArray(ClassOne,len1);
PrintArray(ClassTwo,len2);
average1 = GetAverage(ClassOne,len1);
average2 = GetAverage(ClassTwo,len2);
printf("一班的平均成绩是:%.2f\n",average1);
printf("二班的平均成绩是:%.2f\n",average2);
return 0;
}
二维数组作为函数的参数:
正确写法:int a[2][3]或int a[][3];
错误写法:int a[][] 或 int a[2][];
关键两点:数组的数据类型、二维数组中一维数组的个数
编程练习:有3x4矩阵,初始化它并输出,然后求最大值并输出
#include <stdio.h>
void InitArray(int array[][4],int line,int list)
{
int i;
int j;
for(i=0;i<3;i++)
{
for(j=0;j<4;j++)
{
printf("请输入第%d行第%d列的数值:\n",i+1,j+1);
scanf("%d",&array[i][j]);
}
}
puts("输入完毕");
}
void PrintArray(int array[][4],int line,int list)
{
int i;
int j;
for(i=0;i<3;i++)
{
for(j=0;j<4;j++)
{
printf("%d\t",array[i][j]);
}
putchar('\n');
}
puts("\n打印完毕\n");
}
int GetMaxDataFrom(int array[][4],int line,int list)
{
int i;
int j;
int max;
max = array[0][0];
for(i=0;i<3;i++)
{
for(j=0;j<4;j++)
{
if(max<array[i][j])
{
max = array[i][j];
}
}
}
return max;
}
int main()
{
int max;
int array[3][4];
InitArray(array,3,4);
PrintArray(array,3,4);
max = GetMaxDataFrom(array,3,4);
printf("数据中的最大值为:%d\n",max);
return 0;
}
全局变量:
全局变量我们也任何的地方都是可以使用的,但是全局变量也存在着不少的缺点,很多有经验的程序员都会避免使用全局变量,这主要是是因为在使用全局变量的时候,可能会引起来一系列的问题,像是干扰了模块化,无意间的修改,并发的问题等等。 无意间的修改的意思是说,在使用全局变量的时候,我们并不知道在什么时候就被修改了,这样产生的后果会有很多,这将会造成测试困难,产生歧义。
编程练习:班上10 个学生,封装一个函数,调用该函数后获得班上的平均分,最高分,最低分
#include <stdio.h>
int max;
int min;
void InitArray(int array[],int len)
{
int i;
for(i=0;i<len;i++)
{
printf("请输入第%d个学生的成绩:\n",i+1);
scanf("%d",&array[i]);
}
puts("输入完毕");
}
float GetAverage(int array[],int len)
{
int i;
int sum = 0;
max = min = array[0];
float average;
for(i=0;i<len;i++)
{
if(max<array[i])
{
max = array[i];
}
if(min>array[i])
{
min = array[i];
}
sum +=array[i];
}
average = (float)sum/len;
return average;
}
int main()
{
float average;
int array[10];
int len = sizeof(array)/sizeof(array[0]);
InitArray(array,len);
average = GetAverage(array,len);
printf("最高分是:%d,最低分是:%d,平均分是:%.2f\n",max,min,average);
return 0;
}
作业 :
- 要求输入10个数,找出最大数以及最大数的下标
- 封装冒泡排序的函数
- 封装选择排序的函数
编程练习
① 要求输入10个数,找出最大数以及最大数的下标
#include <stdio.h>
int subscript;
void InitArray(int a[],int len)
{
int i;
for(i=0;i<len;i++)
{
printf("请输入第%d个数据:\n",i+1);
scanf("%d",&a[i]);
}
}
int PrintArray(int a[],int len)
{
int i;
int max;
max = a[0];
for(i=0;i<len;i++)
{
if(max<a[i])
{
max = a[i];
subscript = i;
}
}
return max;
}
int main()
{
int a[10];
int max;
int len = sizeof(a)/sizeof(a[0]);
InitArray(a,len);
max = PrintArray(a,len);
printf("最大值是%d,最大值的下标是%d\n",max,subscript+1);
return 0;
}
② 封装冒泡排序的函数
#include <stdio.h>
void InitArray(int a[],int len)
{
int i;
for(i=0;i<len;i++)
{
printf("请您输入第%d个数据\n",i+1);
scanf("%d",&a[i]);
}
}
void PrintfArray(int a[],int len)
{
int i;
int j;
int temp;
for(i=0;i<len-1;i++)
for(j=0;j<len-1-i;j++)
{
if(a[j]>a[j+1])
{
temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
}
int main()
{
int i;
int a[5];
int len = sizeof(a)/sizeof(a[0]);
InitArray(a,len);
puts("原样输出");
for(i=0;i<len;i++)
{
printf("%d ",a[i]);
}
PrintfArray(a,len);
putchar('\n');
puts("排序后输出");
for(i=0;i<len;i++)
{
printf("%d ",a[i]);
}
return 0;
}
③ 封装选择排序的函数
#include <stdio.h>
void InitArray(int a[],int len)
{
int i;
for(i=0;i<len;i++)
{
printf("请输入您的第%d个数据\n",i+1);
scanf("%d",&a[i]);
}
}
void PrintArray(int a[],int len)
{
int i;
int j;
int temp;
for(i=0;i<len-1;i++)
{
for(j=i+1;j<len;j++)
{
if(a[i]>a[j])
{
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
}
int main()
{
int i;
int a[5];
int len = sizeof(a)/sizeof(a[0]);
InitArray(a,len);
puts("原样输出");
for(i=0;i<len;i++)
{
printf("%d ",a[i]);
}
PrintArray(a,len);
putchar('\n');
puts("排序后输出");
for(i=0;i<len;i++)
{
printf("%d ",a[i]);
}
return 0;
}