函数:function,功能模块
在C语言中,函数是完成某个特定功能的指定序列的封装。(在C语言中,指令只能在函数内部)
函数可以实现代码的复用,以及模块化的设计
结构化设计主张把大任务,分成多个小任务(多个函数)来完成
函数就是实现某个功能的指令序列
设计一个函数,需要考虑哪些问题?
(1)这个函数的功能是什么?
目的
(2)完成这个功能,需要什么资源?输入参数
需求分析
(3)怎么完成?
算法思路
(4)完成情况,结果?
返回值
输出
功能:求一个数组的最大值
(1)目的:求一个数组的最大值
(2)需要的资源
整个数组
(3)算法思路
遍历
(4)返回值
1.c函数实现
在C语言定义一个函数
返回值类型 函数名(输入参数列表)
{
声明部分
语句部分 =》指令序列
}
“返回值类型” :函数返回值的类型
“函数返回值” :语句return 后面的那个表达式的值
函数也可以没有返回值,即返回值类型为void
return ; =>仅仅结束该函数
return 值 ; =>该函数有返回值
“函数名”:要符合C语言的标识符的规定
“输入参数列表” :功能模块的输入
格式如下:
(参数类型1 参数名1,参数类型2 参数名2,......)
参数就是函数的局部变量,只不过他的初始值有调用者给定
函数也可以没有参数,即输入参数列表为空或void
{} :花括号里面就是完成这个函数的功能的代码的实现
函数头+函数体
/*
求一个数组的最大值
*/
int find_max(int a[],int n)
{
int max = a[0];
int i;
for(i = 0;i < n;i++)
{
if(a[i] > max)
{
max = a[i];
}
}
return max;
}
这个函数里面的指令会不会自动执行?
2.函数调用:
调用函数 :执行某个函数
调用函数:
要调用的函数名(传递个这个函数的实际参数);
函数调用语句:要调用的函数名(传递个这个函数的实际参数);
要调用的函数名(传递个这个函数的实际参数) =》函数调用表达式
函数调用表达式的值,就是这个函数的返回值
函数的调用过程: “传值调用”
把实际参数的值赋值给对应的形式参数,然后跳到被调用的函数中去执行
,被调用函数return语句表名被执行完毕,并且整个函数调用表达式的值
就是return后面的表达式的值
实际参数:函数调用表达式里面的参数。实际参数不需要写类型
所有有值的表达式都可以当做实际参数
fun(3,4+5);//3,4+5.0称为实参
int a = 3,b = 7;
fun(a,a+b);
形式参数:函数定义时的参数
int fun(int a,int b) //a,b就是形参
{
}
练习:
(1)写一个函数,判断一个数组是否为递增数组
是 返回1
不是 返回0
/*
判断一个数组是否为递增数组
@a:数组名
@n:数组元素的个数
返回值:
1 =》递增
0 =》非递增
*/
int is_inc(int a[],int n)
{
int i;
for(i = 0;i < n-1;i++)
{
if(a[i] >= a[i+1])
{
return 0;
}
}
return 1;
}
函数调用过程:
传值调用,把实参的值拷贝一份赋值给相应的形参
主调函数: 调用别人的函数
被调函数: 被别人调用的函数
数据传递
主调函数 -》被调函数 参数
被调函数 -》主调函数 返回值
主调函数 《-》被调函数 全局变量
3.递归函数
我们在定义一个函数表达式的时候,有直接或间接的调用了该函数表达式本身
这种函数称为递归函数
假设f(n)为n的阶乘
f(4) =>4!
f(5) =>5!
...
f(n) =>n!
when n = 0 or n = 1 f(n) == 1
when n >= 2 f(n) = f(n-1)*n
=>f(n) 为递归函数
C语言直接支持函数的递归调用(不能是无限递归)
当递归到某个程度是,其结果显而易见
int f(int n)
{
if(n < 0)
{
}
if(n == 0 || n == 1)
{
return 1;
}
else
{
return n*f(n-1);
}
}
int main()
{
int n = 3;
}
====
设计递归
(1)在解决问题的时候,遇到了该问题同样的问题
(2)不能是无限递归
练习:
(1)写一个函数,求斐波那契数列的第n项
1 1 2 3 5 8 13 .....
n = 1 F(1) == 1
n = 2 F(2) == 1
n = 3 F(3) == F(2) +F(1)
int F(n)
{
if(n <= 0 )
{
return 0;
}
if(n == 1 || n == 2)
{
return 1;
}
else
{
return F(n-1)+F(n-2);
}
}
(2)hanoi塔问题
写一个函数,实现Hanoi塔的搬运步骤
功能:把n个盘子从A移动到C,中间利用B
输入参数:
n :多少个盘子
A :起点
B :中转点
C :终点
Hanoi(1,A,B,C) ?
直接从A移动到C
Hanoi(2,A,B,C)
A->B
A->C
B->C
//Hanoi(3,A,B,C)
Hanoi(n,A,B,C)
n > 1
(1) Hanoi(n-1,A,C,B)
(2)A->C
(3)Hanoi(n-1,B,A,C)
void Hanoi(int n,char A,char B,char C)
{
if(n == 1)
{
printf("%c->%c\n",A,C);
return ;
}
Hanoi(n-1,A,C,B);
printf("%c->%c\n",A,C);
Hanoi(n-1,B,A,C);
}
作业:
(1)能不能计算移动n个盘子,所需要的步数
(2)“鞍点”:行中最大,列中最小
a[4][4]
#include <stdio.h>
int main()
{
int a[4][4],i,j,k,max;
for(i = 0;i < 4;i++)
{
for(j = 0;j < 4;j++)
{
scanf("%d",&a[i][j]);
}
}
for(i= 0;i<4;i++)//行
{
max = a[i][0];
for(j = 0;j < 4;j++)//找到一行中最大的那个值
{
if(max < a[i][j])
{
max = a[i][j];
}
}
for(j = 0;j < 4;j++)//找最大的值的位置
{
if(max == a[i][j])
{
for(k = 0;k < 4;k++)
{
if(a[k][j] < a[i][j])
{
goto loop;
}
}
printf("鞍点:a[%d][%d] = %d\n",i,j,a[i][j]);
}
loop:
;
}
}
}
=======================
C语言对象的作用域和生存期
1.作用域
what?
起作用的一个区域
变量和函数的作用域
变量从作用域来分,分两种
(1)全局变量:定义在函数外面的变量
整个工程都起作用的全局变量
一个有多个源文件(1.c,2.c,3.c....)
在这些文件中都可以访问的全局变量
eg:
1.c
int a = 5;(函数外部定义)
作用域:整个工程文件
2.c需要用到1.c的a
extern int a;//这个变量a是在外面的文件定义的,但是当前文件需要用到
仅在当前文件内起作用的全局变量
1.c
static int a = 5;(函数外部定义)
=>声明a仅在本文件(1.c)中有效,其他文件不能用1.c的a
(2)局部变量
定义在{}(函数内部或代码块)里面的变量,局部变量
作用域:仅在{}(函数内部或代码块)内起作用
eg:1.c
int a = 250;
int main()
{
int a = 5;
if(1)
{
int a = 6;
printf("A = %d\n",a);
}
printf("a = %d\n",a);
}
A = 6
a = 5
只要作用域不一样就可以定义同名的变量
====
函数的作用域
(1)全局作用域
对整个工程都有效
1.c
int sum(int a,int b)
{
return a+b;
}
2.c
声明:sum是一个外部定义的函数
extern int sum(int a,int b);
fun()
{
sum(2,3);
}
(2)仅在文件中有效
1.c
static int sum(int a,int b)
{
return a+b;
}
=>sum仅在当前文件有效
=》static的两个作用
(1)static修饰全局变量和函数时,使得全局变量和函数的作用域只在当前文件有效
(2)static修饰局部变量,使得局部变量的生存期变为随着进程的持续性,并且static修饰的变量,只被初始值赋值一次,之后不会再被循环中比如while(1){
Static int x = 2,
X++;}此时只会赋值一次,第二次进循环将不再被赋值为2,而是直接处理下面的内容
2.生存期
what?
从生到死的期间
随文件系统的持续性:
随内核持续性:
操作系统一启动他就存在,并且存在到操作系统关闭
随进程的持续性(随程序的持续性):
程序一运行他就存在,并且存在到程序的退出
int a = 5;
void fun()
{
int c;
static int b = 6;
b++;
printf("b = %d\n",b);
}
int main()
{
fun();
fun();
}