第五部分
注:除了有输出结果的代码,其余均无实际意义
函数 c语言的第二个重点
#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>
//max是函数的名字,i和j是形式参数,简称形参
//void表示函数没有返回值
void max(int i,int j)
{
if(i>j)
printf("%d\n",i);
else
printf("%d\n",j);
}
int main() //main也是一个函数,但系统规定,先执行内函数,所以先执行main
{
int a,b,c,d,e,f;
a=1,b=2,c=3,d=9,e=-5,f=100;
max(a,b); //找到max函数,a值发送给i,b值发送给j 然后进行比较,输出
max(c,d);
max(e,f);
return 0;
}
/*----输出结果-----------
2
9
100
-------------------------*/
//数组中的变量叫做元素
//函数中的变量叫做形参
为什么需要函数
避免了重复型操作
有利于程序的模块化(功能进行分类)
#include <stdio.h>
//括号中的void表示该函数不能接受数据
int f(void) //int表示函数返回值是int类型的数据
{
return 10; //向主调函数返回10
}
int main()//main为主调函数 上面的f为被调函数
{
int j=88;
j=f(); //本行括号内不能写入任何值,上面规定括号内为void
printf("%d\n",j); //j为10
return 0;
}
/*----输出结果-----------
10
-------------------------*/
//注,若第一个return 10; 改为return 10.5; 结果仍为10 ,因为类型为int ,会进行转换
若写为:
#include <stdio.h>
void g(void) //函数名前面的void表示该函数没有返回值
{
return 10; //error 与上面的void相矛盾
}
int main()
{
j=g(); //error,因为g函数没有返回值
return 0;
}
什么叫做函数
逻辑上:能够完成特定功能的独立的代码块
物理上:能够接受数据 [当然也可以不接受数据]
能够对接受的数据进行处理
能够将数据处理的结果返回 [当然也可以不返回任何值]
总结:函数是个工具,是为了解决大量的类似问题而设计的
函数可以当做一个黑匣子
如何定义函数
函数的返回值 函数的名字(函数的形参列表)
{
函数的 执行体
}
void的返回值为空
▶函数定义的本质是:详细描述,函数之所以能够实现某个特定功能的具体实现方法
▶return 表达式;的含义:
先回顾一下break的用法
#include <stdio.h>
void f(void)
{
int i;
for (i=0;i<5;++i) //只看本行共循环五次,第一次时执行完printf后,执行break,退出循环,故只循环一次
{
printf("大家辛苦了!\n");
break; //退出离它最近的循环
}
printf("加油\n");
}
int main()
{
f();
return 0;
}
/*----输出结果-----------
大家辛苦了!
加油
-------------------------*/
return
♦终止被调函数,向主调函数返回表达式的值
♦如果表达式为空,则只终止函数,不向主调函数返回任何值
#include <stdio.h>
void f(void)
{
int i;
for (i=0;i<5;++i)
{
printf("大家辛苦了!\n");
return; //终止函数不向主调函数返回任何值
//如果写return 1;会报错, 因为前面类型为void, 故不写值
}
printf("加油\n"); //本行与return是同一函数,故执行return退出后,无法执行本行
}
int main()
{
f();
return 0;
}
/*----输出结果-----------
大家辛苦了!
-------------------------*/
故:break是用来终止循环和switch的,return是用来终止函数的
类型一:
void f()
{
return; //终止函数不向主调函数返回任何值
}
类型二:
int f()
{
return 10;//第一终止函数,第二向主调函数返回10
}
▶函数返回值的类型也称为函数的类型
因为,如果函数名前的返回值类型和函数执行体中的return表达式; 中表达式类型不同的话,
则最终函数返回值的类型以函数名前的返回值类型为准
例子:
#include <stdio.h>
int f() //函数的类型以本行为主
{
return 10.5;//因为函数返回值类型为int,,所以返回10而不是10.5
}
int main()
{
int i=99;
double x=6.6;
x=f();
printf("%lf\n",x);
return 0;
}
/*----输出结果-----------
10.000000
-------------------------*/
函数的分类
有参函数和无参函数
有返回值和无返回值
库函数和用户自定义函数
值传递函数和地址传递函数()
普通函数和主函数(main函数)
一个程序必须有且只有一个主函数(程序是从主函数进去的,多了没有都不行)
主函数是程序的入口,也是程序的出口
主函数可以调用普通函数
普通函数不能调用主函数
普通函数可以相互调用
//找最大值
#include <stdio.h>
void max1(int i,int j) //直接输出,代码简单,但功能不如max2强
{
if(i>j)
printf("%d\n",i);
else
printf("%d\n",j);
}
int max2(int i,int j) //暂时不输出,在后面输出
{
if(i>j)
return i;
else
return j;
}
int main(void)
{
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;
}
/*----输出结果-----------
2
9
100
-------------------------*/
/判断一个函数是否是素数
#include <stdio.h>
bool IsPrime( int val) //bool分为true和false
{
int i;
for (i=2; i<val; ++i)
{
if(val%i == 0)
break;
}
if (i == val)
return true; //尽量不要输printf,将功能分开
else
return false;
}
int main()
{
int m;
scanf("%d " , &m);
if ( IsPrime(m) )
printf("Yes!\n");
else
printf("No!\n");
return 0;
}
/*--------------
先执行main函数,为m分配空间,从键盘给m赋了个值,继续向下执行
将m的值发送给形参val,进行判断
--------------*/
复习
#include <stdio.h>
void f(int i)
{
return;//void可搭配return;使用,不可搭配return 值;本行没错,但是执行到下面会出错
}
int main()
{
int i; //一个函数内部定义的变量只在本函数使用,所以两个函数定义的变量名字一样也不冲突
i=f(5);//本行会报错,上面的void说明f没有返回值,故不对
return 0;
}
-----------若将上述代码改为----------------
#include <stdio.h>
int f(int i)
{
//不对, int表示有返回值,但这里没有return,故不对
}
int main()
{
int i;
i=f(5);
return 0;
}
//执行顺序
#include <stdio.h>
int f(int i)
{
return 10; //若改为10.8,仍输出10,以f前的类型为准
}
int main()
{
int i=99;
printf("%d\n",i);
i=f(5);
printf("%d\n",i);
return 0;
}
/*----输出结果-----------
99
10
-------------------------
执行顺序
从main函数进去,执行下一行,i被赋值为99并输出
继续执行下一行,发现"字符()"这样的函数,一般为函数调用
找到字符相同的函数后(此处为f函数),核对格式是否正确,正确则进入函数
return,终止f函数,并向调用我的那个函数→主函数返回10,则i为10并输出。
-------------------------*/
//修改类型后的输出
#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
-------------------------*/
//99.900002 因为浮点数(float和double)都无法保证可以将所有实数精确存储
//函数的声明原代码
#include <stdio.h>
void f(void)
{
printf("哈哈!\n");
}
int main()
{
f();
return 0;
}
/*----输出结果-----------
哈哈!
-------------------------*/
将main函数放在上方,不做任何修改,会报错,可做下列修改
//函数的声明修改后代码,在main函数上面加上一行声明
#include <stdio.h>
void f(void);//函数的声明,分号不能丢掉
int main()
{
f();
return 0;
}
void f(void)
{
printf("哈哈!\n");
}
/*----输出结果-----------
哈哈!
-------------------------*/
函数声明的错误写法,一定要明白该程序为什么会出错
#include <stdio.h>
void f(int); //自上而下执行,已声明f为int型,在f()行就会报错
int main()
{
f();
return 0;
}
void f(void)
{
printf("哈哈!\n");
}
注意的问题
▶函数调用和函数定义的顺序
如果函数调用写在了函数定义的前面,则必须加函数前置声明
函数前置声明的作用:
告诉编译器即将可能出现的若干个字母代表的是一个函数
告诉编译器即将可能出现的若干个字母代表的函数的形参和返回值的具体情况
函数声明是一个语句,末尾必须加分号
对库函数的声明是通过#include<库函数所在的文件的名字.h>来实现的
系统函数(比如printf,scanf)不用声明,已经放在了头文件里
//错误代码
#include<stdio.h>
void g(void)//f的调用语句
{
f(); //因为函数f的定义语句放在了f调用语句后面,所以语法出错
}
void f(void) //f的定义语句
{
printf("哈哈!\n");
}
int main()
{
g();
return 0;
}
//正确代码
//调用的语句放在定义语句的前面,一定要加声明
#include<stdio.h>
void f(void); //一定要明白本行生效后为什么程序就正确了
void g(void)//f的调用语句
{
f(); //因为函数f的定义语句放在了f调用语句后面,所以语法出错
}
void f(void) //f的定义语句
{
printf("哈哈!\n");
}
int main()
{
g();
return 0;
}
/*----输出结果-----------
哈哈!
-------------------------*/
▶形参和实参
二者个数必须相同
//一个
#include<stdio.h>
void f(int i) //i为形参
{
printf("%d\n",i);
}
int main(void)
{
f(5); //5为实参
return 0;
}
/*----输出结果-----------
5
-------------------------*/
//两个
#include<stdio.h>
void f(int i,int j) //i,j为形参
{
printf("%d %d\n",i,j);
}
int main(void)
{
f(5,6); //5,6为实参
return 0;
}
/*----输出结果-----------
5 6
-------------------------*/
二者位置一一对应,数据类型必须相互兼容
#include<stdio.h>
void f(int i,float j) //i,j为形参
{
printf("%d %f\n",i,j);
}
int main(void)
{
f(5,6.1); //如果为f(6.1,5)或f("haha",6.1)都不对,但是f(5.1,6.1)是对的,结果不变
//但不同语言要求不同,数据类型一致是最好的
return 0;
}
/*----输出结果-----------
5 6.100000
-------------------------*/
如何在软件开发中合理的设计函数来解决实际问题
例一
原版
/*
判断一个数字是否是素数,
若只用一个函数实现,不好,程序的代码利用率不高
*/
#include <stdio.h>
int main()
{
int val;
int i;
scanf("%d",&val);
for(i=2;i<val;++i)
{
if(0 == val%i)
break;
}
if(i == val)
printf("Yes!\n");
else
printf("No!\n");
return 0;
}
一个函数不好的原因:上述函数是判断是否是素数,是则输出yes,不是则输出no
但若题目要求,是素数将这个值+2,不是素数变为负数,这种操作就无法使用
最好用一个函数判断是否为素数,是返回真,不是返回假(bool型)
再用另外一个函数单独设计下一步的处理
总之,函数的功能要单一
故将代码进行修改
修改版
/*
判断一个数字是否是素数,
用单独的函数来实现,代码的可重用性提高
*/
#include <stdio.h>
bool IsPrime(int val)
{
int i;
for(i=2;i<val;++i)
{
if(0 == val%i)
break;
}
if(i == val)
return true;
else
return false;
}
int main()
{
int val;
int i;
scanf("%d",&val);
if(IsPrime(val))
printf("Yes!\n");
else
printf("No!\n");
return 0;
}
例二
原版
/*
求1到某个数字之间所有的素数,并将其输出
只用main函数实现,有局限性
1.代码的重用性不高
2.代码不容易理解
*/
#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;
}
/*
100
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71
73
79
83
89
97
原本代码只判断一个val是否为素数
现在判断i,1到某个范围
i%j能整除则不是,不能整除则是
*/
shift+tab 整体前移
修改版一
/*
求1到某个数字之间(包含该数字)所有的素数,并将其输出
1个函数来判断一个数字是否是函数
优点:代码比原版更容易理解
代码的可重用性更高
缺点:
可重用性仍然不是非常高
比如求1000个数字,它们每个数字从1到它本身的素数
则
for(i=2;i<=val;++i)
{
if(IsPrime(i))
printf("%d\n",i);
}
这些代码要写1000次
*/
#include <stdio.h>
bool IsPrime(int m) //该函数的功能:用来判断是否为素数
{
int i;
for(i=2;i<=m;++i
{
if(0 == m%j)
break;
}
if(i== m)
return true;
else
return false;
}
int main()
{
int val;
int i;
scanf("%d",&val);
for(i=2;i<=val;++i)
{
if(IsPrime(i)) //条件为假,执行++i
printf("%d\n",i);
}
return 0;
}
//结果与原版一致
修改版二
总结:
一个函数的功能尽量独立,单一
多学习,多模仿牛人的代码
函数是c语言的基本单位
类是JAVA,C#,C++的基本单位
常用的系统函数
(了解)
double sqrt(double x); 求x的平方根
int abs(int x); 求x的绝对值
double fabs(double x); 求x的绝对值
推荐一本书 机械工业出版社 turboc 2.0实用大全
专题 :
递归(数据结构视频中有视频50-58)
学递归前要先了解栈 先进后出 压栈 出栈
函数复习
#include <iostream>
void f(void)
{
return;
printf("哈哈");
}
int main()
{
f();
return 0;
}
//运行结果为空
#include <iostream>
int f(void) //若写为void f(void) 会报错
{
return 1;
printf("哈哈");
}
int main()
{
printf("%d\n",f());
return 0;
}
//运行结果为1 无任何含义 语法上无任何错误
#include <iostream>
int f(int i) //把本行改为int f(int j),结果为99
{
int i=99;
printf("i=%d\n",i);
return 1;
}
int main()
{
int i=10;
f(i);
return 0;
}
//运行报错,f(int i)已经定义了i,f函数内不可再次定义i
变量的作用域和存储方式
按作用域分:
全局变量:在所有函数外部定义的变量
使用范围:从定义的位置开始到下面整个程序结束都可使用,在定义的上方不可使用
#include <iostream>
int k=1000;
void f(int i)
{
int j=20;
printf("k=%d\n",k);
}
int main()
{
int i=10;
f(88);
return 0;
}
//结果:k=1000
一定要搞清楚全局变量的位置问题
//本代码报错
#include <iostream>
void g()
{
printf("k=%d\n",k);
}
int k=1000; //全局变量范围:从定义的位置开始到下面整个程序结束
void f()
{
g();
printf("k=%d\n",k);
}
int main()
{
f();
return 0;
}
//结果:k=1000
局部变量:在一个函数内部定义的变量或者函数的形参 都统称为局部变量
使用范围:只能在本函数内部使用
int f(int i)
{
int j=20;
}
i和j都属于局部变量
注意:
全局变量和局部变量命名相冲突的问题
在一个函数内部如果定义idea局部变量的名字和全局变量名一样时,局部变量会屏蔽掉全局变量
#include <stdio.h>
int i=99;
void f(int i)
{
printf("i=%d\n",i);
}
int main()
{
f(8);
return 0;
}
//结果i=8
按变量的存储方式:
(此处不讲,后期看到会补充)
静态变量
自动变量
寄存器变量