学会思想就够了!
理解获得意想不到的结果——新技术的诞生!
函数定义公式:
函数可以作为定义返回值,也可作为函数内部的应用函数。
注意:每个C程序的入口和出口都位于main函数之中。编写程序时,并不是将所有的内容都放在主函数main中。
函数调用的一般形式为:
functionName(param1, param2, param3 ...);
functionName 是函数名称,param1, param2, param3 ...是实参列表。实参可以是常数、变量、表达式等,多个实参用逗号,分隔。
先来看一个例子:
1、函数的声明
注意:这里的函数为新定义的函数,以下是声明函数之后,主函数调用其他函数。
#include<stdio.h>
int Function(); /*声明函数*/
int main()
{
printf("我在函数之前\n"); /*输出提示信息*/
Function(); /*调用函数*/
printf("函数的结尾\n"); /*输出提示信息*/
return 0;
}
int Function() /*定义函数*/
{
printf("我是函数\n"); /*输出提示信息*/
/*函数结束*/
}
执行结果:
当然我们可以把定义的函数和主函数程序块交换一个位置,结果仍然相同,因此主函数总是去调用定义的新函数内容。这主要看个人的书写习惯吧!我比较喜欢把定义的函数放在前面,主函数放在后面。即:
#include<stdio.h>
int Function(); /*声明函数*/
int Function() /*定义函数*/
{
printf("我是函数\n"); /*输出提示信息*/
/*函数结束*/
}
int main()
{
printf("我在函数之前\n"); /*输出提示信息*/
Function(); /*调用函数*/
printf("函数的结尾\n"); /*输出提示信息*/
return 0;
}
执行结果:
类似地,我们这里举出一个简单例子:
#include<stdio.h>
/*自定义一个函数*/
int fun2020(int x,int y)
{
if((x*x+y*y)%2==0)
{
return 0;
}
else
{
return 1;
}
}
/*定义一个主函数去调用上诉函数*/
int main()
{
int num1,num2,i,j;
printf("请输入两位数:\n");
scanf("%d%d",&num1,&num2);
/*声明调用的函数*/
i=fun2020(num1,num2);
j=num1*num1+num2*num2;
if(i==0)
{
printf("%d和%d的平方和%d是偶数\n",num1,num2,j);
}
else
{
printf("%d和%d的平方和%d是奇数\n",num1,num2,j);
}
}
执行结果:
请输入两位数:
66
88
66和88的平方和12100是偶数
2、函数的参数调用
递归:
#include<stdio.h>
/*自定义一个函数*/
int fun2020(int n)
{
int m;
if(n==0||n==1)
{
return m=1;
}
else
{
m=n*fun2020(n-1);
}
return m;
}
/*定义一个主函数去调用上诉函数*/
int main()
{
int i,j;
printf("请输入一个数:\n");
scanf("%d",&i);
if(i<0)
{
printf("输入错误 \n");
}
else
{
j=fun2020(i);
printf("%d的阶乘为%d",i,j);
}
}
受到以上方法的启发,这里来判断三角形
/*三角形*/
#include<stdio.h>
#include<stdlib.h>
/*自定义一个函数*/
int feimagougu(int a, int b,int c)
{
if(((a+b)>c&&abs(a-b)<c))
{
return 0;
}
else
{
return 1;
}
}
/*定义一个主函数去调用上诉函数*/
int main()
{
int x,y,z,i;
printf("请输入三个数:\n");
scanf("%d%d%d",&x,&y,&z);
/*一定别忘了要声明函数,不然不能调用*/
i=feimagougu(x,y,z);
if(i==0)
{
printf("是三角形 \n");
printf("这三边长分别为%d,%d和%d",x,y,z);
}
else
{
printf("不是三角形 \n");
}
}
执行结果:
同样的方法,可以获得如下:
3、输入任意三个数判断是否为勾股数
/*任意输入三个数,判断是否为勾股数*/
#include<stdio.h>
/*自定义一个函数*/
int feimagougu(int a, int b, int c)
{
if((a*a+b*b)==(c*c))
{
return 0;
}
else
{
return 1;
}
}
/*定义一个主函数去调用上诉函数*/
int main()
{
int x,y,z,i;
printf("请输入三个数:\n");
scanf("%d%d%d",&x,&y,&z);
/*一定别忘了要声明函数,不然不能调用*/
i=feimagougu(x,y,z);
if(i==0)
{
printf("这三个数为勾股数 \n");
printf("这三个数分别为%d,%d和%d",x,y,z);
}
else
{
printf("这三个数为非勾股数 \n");
}
}
执行结果:
4、调用其他函数
其实从上面的函数之间的调用分析,我们已经知道函数调用的初步过程了,为了更细说明其中的思想,那么如何在函数之间互相调用取值?这里再举例说明:
/*在主函数中调用其他函数*/
#include<stdio.h>
void Move(); /*声明搬运函数*/
void Build(); /*声明建造函数*/
void Paint(); /*声明粉刷函数*/
//使用主函数main调用其他函数
int main()
{
Move(); /*执行搬运函数*/
Build(); /*执行建造函数*/
Paint(); /*执行粉刷函数*/
return 0; /*程序结束*/
}
//构造各个函数的功能和方法
/*执行搬运功能 */
void Move()
{
printf("这个函数可以搬运货物\n");
}
/*执行建造功能 */
void Build()
{
printf("这个函数可以建造一栋高楼\n");
}
/* 执行粉刷功能 */
void Paint()
{
printf("这个函数可以粉刷墙面\n");
}
执行结果:
备注:
返回值类型为void的方法.
定义格式:
修饰符 void 方法名(参数列表){
方法体;
return; // 可以省略
}
void: 空的意思, 不能用来定义变量,只能用来作为返回值类型使用
注意点:
1. 不能定义变量来接收
2. 不能直接放在输出语句中
5、返回值的调用
以下是一输入任意两数求差的例子:
#include<stdio.h>
//先声明定义的函数
int Fun(int iNumber1,int iNumber2);
//定义一个函数Fun
int Fun(int iNumber1,int iNumber2)
{
int iResult; /*定义一个整型变量用来存储返回的结果*/
//以上定义的iResult也可定义多个
iResult=iNumber1-iNumber2; /*进行减法计算,得到计算结果*/
return iResult;
/*return语句返回计算结果,这里要注意的是,返回值给了函数,
一般只能返回一个值,因此其他函数调用它时调用的return返回的结果*/
}
//定义一个主函数main调用以上函数
int main()
{
int x,y,Result; /*定义3个整型变量*/
printf("请任意输入两个数:\n");
scanf("%d%d",&x,&y);
Result=Fun(x,y);/*进行x-y的减法计算,并将结果赋值给变量iResult*/
printf("Fun(%d,%d)=%d\n",x,y,Result);
return 0; /*程序结束*/
}
//切记,定义函数中的iResult和主函数中Result不能重名,否则报错或不能运行
//scanf()函数里的参数一定别忘了取地址符:&
执行结果:
6、使用数组元素作为函数参数
由于实参可以是表达式形式,数组元素可以是表达式的组成部分,因此数组元素可以作为函数的实参,与用变量作为函数实参一样,是单向传递。
#include<stdio.h>
void ShowMember(int iMember); /*声明函数*/
void ShowMember(int iMember) /*函数定义*/
{
printf("这名员工的编号为00%d\n",iMember);/*输出数据*/
}
int main()
{
int iCount[10]; /*定义一个整型的一维数组*/
int i; /*定义整型变量,用于循环*/
for(i=0;i<10;i++) /*进行赋值循环*/
{
iCount[i]=i; /*为数组中的元素进行赋值操作*/
}
for(i=0;i<10;i++) /*循环操作*/
{
ShowMember(iCount[i]);/*执行输出函数操作*/
}
return 0;
}
执行结果:
类似地,我们再举一个有难度的例子,计算一个函数列二维数组,生成10*10矩阵值:
#include<stdio.h>
#include <math.h>
#include <complex.h>
void ShowMember(int k,int l,int iMember); /*声明函数*/
void ShowMember(int k,int l,int iMember) /*函数定义*/
{
printf("a[%d][%d]=%4d ",k,l,iMember);/*输出数据*/
}
int main()
{
int iCount[10][10]; /*定义一个整型的数组*/
int i,j; /*定义整型变量,用于循环*/
for(i=0;i<10;i++) /*进行赋值循环*/
{
for(j=0;j<10;j++)
{
iCount[i][j]=cos(2*i)+sin(2*j)+exp(i-j)+pow(-1,i+j); /*为数组中的元素进行赋值操作*/
}
}
for(i=0;i<10;i++) /*循环操作*/
{
for(j=0;j<10;j++)
{
ShowMember(i,j,iCount[i][j]);/*执行输出函数操作*/
}
printf("\n");//生成10*10矩阵形式
}
return 0;
}
执行结果:
备注:还可以使用指针作为函数参数,也就是将函数参数声明为一个指针,例如:
#include<stdio.h>
void Evaluate(int* pPoint);/*声明函数,参数为可变长度数组*/
void Display(int* pPoint);/*声明函数,参数为可变长度数组*/
int main()
{
int iArray[10]; /*定义一个具有10个元素的整型数组*/
......
}
void Display(int* pPoint)/*定义函数,参数为可变长度数组*/
{
......
}
void Evaluate(int* pPoint) /*定义函数,参数为可变长度数组*/
{
......
}
7、主函数参数main()
运行程序时,有时需要将必要的参数传递给主函数。
主函数main的形式参数如下:
main (int argc, char * argv[] )
两个特殊的内部形参argc和argv是用来接收命令行实参的,这是只有主函数main才能具有的参数。
- argc参数: argc参数保存命令行的参数个数,是整型变量。这个参数的值至少是1,因为至少程序名就是第一个实参。
- argv参数: argv参数是一个指向字符指针数组的指针,这个数组里的每一个元素都指向命令行实参。所有命令行实参都是字符串,任何数字都必须由程序转变成为适当的格式。
argc、argv的具体含义
argc和argv参数在用命令行编译程序时有用:
main( int argc, char* argv[], char **env )
第一个参数,int型的argc,为整型,用来统计程序运行时发送给main函数的命令行参数的个数,在VS中默认值为1。
第二个参数,char*型的argv[],为字符串数组,用来存放指向的字符串参数的指针数组,每一个元素指向一个参数。各成员含义如下:
- argv[0]指向程序运行的全路径名
- argv[1]指向在DOS命令行中执行程序名后的第一个字符串
- argv[2]指向执行程序名后的第二个字符串
- argv[3]指向执行程序名后的第三个字符串
- argv[argc]为NULL
第三个参数,char**型的env,为字符串数组。env[]的每一个元素都包含ENVVAR=value形式的字符串,其中ENVVAR为环境变量,value为其对应的值。平时使用到的比较少。
下面给出例子说明:
8、指针作为函数参数
指针变量作参数后就很容易解决上面的问题:
#include <stdio.h>
void swap(int *p1, int *p2){
int temp; //临时变量
temp = *p1;
*p1 = *p2;
*p2 = temp;
}
int main(){
int a = 2019, b = 2020;
swap(&a, &b);
printf("a = %d, b = %d\n", a, b);
return 0;
}
运行结果:
a = 2020, b = 2019
调用 swap() 函数时,将变量 a、b 的地址分别赋值给 p1、p2,这样 p1、p2 代表的就是变量 a、b 本身,交换 p1、p2 的值也就是交换 a、b 的值。函数运行结束后虽然会将 p1、p2 销毁,但它对外部 a、b 造成的影响是“持久化”的,不会随着函数的结束而“恢复原样”。
需要注意的是临时变量 temp,它的作用特别重要,因为执行*p1 = *p2;语句后 a 的值会被 b 的值覆盖,如果不先将 a 的值保存起来以后就找不到了。