函数
引例:
#include<stdio.h>
int main()
{
int a,b,c,d,e,f;
a=1,b=2,c=3,d=9,e=-5,f=100;
if(a>b)
printf("%d\n",a);
else
printf("%d\n",b);
if(c>d)
printf("%d\n",c);
else
printf("%d\n",d);
if(e>f)
printf("%d\n",e);
else
printf("%d\n",f);
return 0;
}
输出结果:
2
9
100
*以上代码有重复现象,过程繁琐,可以优化算法
#include<stdio.h>
void max(int i,int j) //void说明函数无返回值,max是函数名字,i,j是形式参数,简称形参
{
if(i>j)
printf("%d\n",i);
else
printf("%d\n",j);
}
int main()
{
int a,b,c,d,e,f;
a=1,b=2,c=3,d=9,e=-5,f=100;
max(a,b);
max(c,d);
max(e,f);
return 0;
}
【注】
系统先执行 main()函数,当执行到 max(a,b)时,a返回给i,b返回给j,此时程序跳到if...else...中执行。
执行完毕后,开始执行 max(c,d),第二次使用前,会将第一次的使用空间释放。
虽然被释放,但第一次和第二次分配的空间不一定为同一块空间。
循环完毕后,从 main()函数中退出。
为什么需要函数(重要)
避免了重复性操作
有利于程序的模块化
什么是函数(重要)
逻辑上:能够完成特定功能的独立的代码块
物理上:能够接收数据(也可不接受)
能够对接收的数据进行处理
能够将数据处理的结果返回(也可不返回,void表示无返回值)
总结:函数是个工具,是为了解决大量类似问题设计的
函数可当作一个黑匣子
#include<stdio.h>
int f(void) //void表示函数不能接受数据,int表示函数返回值为int型
{
return 10; //向主调函数返回10
}
void g(void) //函数名前面void表示该函数没返回值
{
return 10 //错,与void g(void)行首void矛盾
}
int main(void)
{
int j=89;
j=f();
printf("%d\n",j);
j=g(); //错,因为g()函数无返回值
return 0;
}
如何定义函数
函数的返回值 函数的名字(函数的形参列表)
{
函数的执行体
}
1.函数定义的本质:详细描述函数之所以能够实现某个特定功能的具体方法
2.return表达式;的含义:
- 终止被调函数,向主调函数返回表达式的值
- 如果表达式为空,只终止函数,不向被调函数返回任何值
- break是用来终止循环和switch的,return是用来终止函数的
举例
void f()
{
return; //return只用来终止函数,不向被调函数返回任何值
}
void f()
{
return 10; //第一,终止函数;第二,向被调函数返回10
}
#include<stdio.h>
void f(void)
{
int i;
for(i=0;i<5;i++)
{
printf("大家辛苦了\n");
break;
}
printf("同志们好\n");
}
int main()
{
f();
return 0;
}
输出:
大家辛苦了
同志们好
#include<stdio.h>
void f(void)
{
int i;
for(i=0;i<5;i++)
{
printf("大家辛苦了\n");
break;
}
printf("同志们好\n");
}
int main()
{
f();
return 0;
}
输出:
大家辛苦了
3.函数返回值的类型也称为函数的类型,因为如果 函数名前的返回值类型 和 函数执行体中的return表达式;中表达式类型不同时,则最终函数返回值的类型 以函数名前的返回值类型为主
#include <stdio.h>
int f()
{
return 10.5; //因为函数的返回值类型为int 所以最终f返回值为10而不是10.5
}
int main()
{
int i=99;
double x=6.6;
x=f();
printf("%lf\n",x);
return 0;
}
输出:x=10.000000
函数分类
有参函数 和 无参函数
又返回值函数 和 无返回值函数
库函数 和 用户自定函数
值传递函数 和 地址传递函数
普通函数 和 主函数
- 一个程序必须有且只有一个主函数
- 主函数可以调用普通函数,普通函数不能调用主函数
- 普通函数可以相互调用
- 主函数是程序的入口,也是程序的出口
#include<stdio.h>
void max1(int i,int j) //找最大值,对最大值处理
{
if(i>j)
printf("%d\n",i);
else
printf("%d\n",j);
}
int max2(int i,int j) //找最大值,处理交给main
{
if(i>j)
return i;
else
return j;
}
int main()
{
int a,b,c,d,e,f;
a=1,b=2,c=3,d=9,e=-5,f=100;
printf("%d\n",max2(a,b));
printf("%d\n",max2(c,d));
printf("%d\n",max2(e,f));
return 0;
}
判断是否为素数
#include<stdio.h>
int main()
{
int val;
int i;
scanf("%d",&val);
for(i=2;i<val;++i)
{
if(val%i==0)
break;
}
if(i==val)
printf("yes\n");
else
printf("no\n");
return 0;
}
输入:13
输出:yes
优化算法:
#include<stdio.h>
bool IsPrine(int val) //素数 bool只有真假
{
int i;
for(i=2;i<val;++i)
{
if(val%i==0)
break;
}
if(i==val)
return ture;
else
return false;
}
int main()
{
int m;
int i;
scanf("%d",&m);
if(IsPrine(m))
printf("yes\n");
else
printf("no\n");
return 0;
}
复习例子
#include<stdio.h>
int f(int i)
{
return 10.8;
}
int main()
{
float i=99.9;
printf("%f\n",i);
i=f(5);
printf("%f\n",i);
return 0;
}
输出:99.900002 10.000000
注意的问题
函数调用和函数定义的顺序
*如果函数调用写在了函数定义之前,必须加函数前置声明
*函数前置声明:
- 告诉编译器即将可能出现的若干字母代表的是一个函数
- 告诉编译器即将可能出现的若干字母代表的函数的形参和返回值的具体情况
- 函数声明是一个语句,末尾必须加分号
- 对库函数的声明是通过
#include<库函数所在的文件名字.h>
来实现的
#include <stdio.h>
void f(void)
{
printf("哈哈!\n");
}
int main()
{
f();
return 0;
}
//若调用放在定义之前,如下:
(一定要明白程序为何出错)
#include <stdio. h>
void f(void); //函数的声明,分号不能丢
int main() //调用函数
{
f();
return 0;
}
void f(void) //定义函数
{
printf("哈哈!\n");
}
#include <stdio.h>
void f(void); //改正:前面加一行声明
void g(void)
{
f(); //函数f()的定义放在了函数调用之后,语法出错
}
void f(void)
{
printf("哈哈!\n");
}
int main()
{
f();
return 0;
}
形参和实参
- 个数相同
- 位置一一对应
- 数据类型相互兼容
#include<stdio.h>
void f(int i,float x)
{
printf("%d\n",i);
}
int main(void)
{
f(5,6.6);
return 0;
}
如何在软件开发中合理的设计函数解决问题(理解)
判断一个数是否为素数
#include<stdio.h>
int main()
{
int val;
int i;
scanf("%d",&val);
for(i=2;i<val;++i)
{
if(val%i==0)
break;
}
if(i==val)
printf("yes\n");
else
printf("no\n");
return 0;
}
// 只用一个函数实现不好,代码利用率不高
#include<stdio.h>
bool IsPrine(int val) //素数 bool只有真假
{
int i;
for(i=2;i<val;++i)
{
if(val%i==0)
break;
}
if(i==val)
return ture;
else
return false;
}
int main()
{
int val;
int i;
scanf("%d",&val);
if(IsPrine(val))
printf("yes\n");
else
printf("no\n");
return 0;
}
// 用单独的函数实现,代码的可重性提高
求1到100间所有素数
#include<stdio.h>
int main()
{
int val;
int i;
int j;
scanf("%d",&val);
for(i=2;i<=val;++i)
{
//判断i是否为素数,是输出,不是不输出
for(j=2;j<i;++j)
{
if(0==i%j)
break;
}
if(j==i)
printf("%d\n",i);
}
return 0;
}
/*
只用main函数实现,有局限性:
1.代码重用性不高
2.代码不易理解
*/
#include<stdio.h>
//判断i是否为素数,是输出,不是不输出
bool IsPrime(int m)
{
int i;
for(i=2;i<m;++i)
{
if(0==m%i)
break;
}
if(i==m)
return ture;
else
return false;
}
int main()
{
int val;
int i;
scanf("%d",&val);
for(i=2;i<=val;++i)
{
if(IsPrime(i))
printf("%d\n",i);
}
return 0;
}
/*用一个函数判断一个数自是否为素数
优点:代码比之前的更易理解,代码的可重用性高
缺点:代码可重用性仍不是非常高,如求1-1000的素数,则
for(i=2;i<val;++i)
{
if(IsPrime(i))
printf("%d\n",i);
}
要写1000次
*/
#include<stdio.h>
//本函数的功能是:判断m是否为素数,是返回ture,不是返回false
bool IsPrine(int m)
{
int i;
for(i=2;i<m;++i)
{
if(m%i==0)
break;
}
if(i==m)
return ture;
else
return false;
}
//本函数功能是输出1到n所有素数
void TraverseVal(int n)
{
int i;
for(i=2;i<=n;++i)
{
if(IsPrime(i))
printf("%d\n",i);
}
}
int main()
{
int val;
scanf("%d",&val);
TraverseVal(val);
return 0;
}
/*
用两个函数实现求1到某个数字之间的所有素数
与上面比较代码量更少,可重用性更高
*/
一个函数的功能尽量独立、单一
多学习,模仿牛人代码
函数是C语言的基本单位,类是 Java, C#, C++ 的基本单位
常用的系统函数(了解)
double sqrt(double x); //求x的平方根
int abs(int x); //求x绝对值
double fabs(double x) //求x绝对值
机械工业:《turboc 2.0实用大全》 C语言书
专题:递归(详见数据结构)
栈
像杯子,只能从一个口进出
先进后出
A调用B A调用A
压栈:放入 出栈:抛出
变量的作用域和存储方式
按作用域分
全局变量
在所有函数外部定义的变量
使用氛围:从定义位置开始到程序结束
#include<stdio.h>
int k=1000; //1
void g()
{
printf("k=%d\n",k);
} //2
void f(void)
{
g();
printf("k=%d\n",k);
}
int main()
{
f(88);
return 0;
}
//一定要明白程序为什么若1,2互换,错误,也要明白为什么此程序对
局部变量
在一个函数内部定义的变量或者函数的形参
使用范围:只在本函数内部使用
void f(int i)
{
int j=20;
}
//i和j都是局部变量
全局变量和局部变量命名冲突问题
在一个函数内部如果定义的局部变量名字和全局变量名字一样时,局部变量会屏蔽全局变量
#include<stdio.h>
int i=99;
void f(int i)
{
printf("i=%d\n",i);
}
int main()
{
f(8);
return 0;
}
输出结果:i=8