C语言笔记: 3.函数
前言
1、函数是什么?
维基百科中对函数的定义:子程序
在计算机科学中,子程序(英语:Subroutine, procedure, function, routine, method,
subprogram, callable unit),是一个大型程序中的某部分代码, 由一个或多个语句块组
成。它负责完成某项特定任务,而且相较于其他代 码,具备相对的独立性。
一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软
件库。
2、函数的分类
- 库函数
- 自定义函数
2.1 库函数
简单来说就是C语言本身提供给用户的函数
主要有:
- IO函数 :输入输出函数
- 字符串操作函数
- 字符操作函数
- 内存操作函数
- 时间/日期函数
- 数学函数
- 其他库函数
2.2 自定义函数
就是用户自己设计出来的函数自己调用
例如:
ret_type fun_name(para1, * )
{
statement;//语句项
}
ret_type 返回类型
fun_name 函数名
para1 函数参数
如:
int get_max(int x,int y)
{
if(x>y)
return x;
else
return y;
}
int为返回类型
get_max为函数名
x和y为参数
3.void函数的理解
void函数即是没有类型,不需要返回值
比如一些比较大小的函数就不要用int定义函数,直接用void即可。
4.函数的参数
- 实参(实际参数)
- 形参(形式参数)
4.1 实参
真实传给函数的参数,可以是:常量、变量、表达式、函数等。
无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。
4.2 形参
形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单
元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有
效。
结论:
当实参传给形参的时候,形参其实是实参的一份临时拷贝
对形参的修改是不会影响实参的
5.函数的调用
5.1传值调用
函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参。
5.2 传址调用
传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。
这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操
作函数外部的变量。
例如:数组在传参过程中,仅仅传过去了首元素的地址
6.函数的嵌套调用和链式访问
6.1 函数的嵌套调用
就是一个A函数里面要调用B函数,B函数里面又得调用C函数这种,
6.2 函数的链式访问
把一个函数的返回值作为另外一个函数的参数。
例如:
int len;
len=length("abc");
printf("%d\n",len)
打印的是len的值,len的值又是length("abc")的值
7.函数的声明和定义
7.1 函数声明
- 函数的声明一般出现在函数的使用之前。要满足先声明后使用。
- 函数的声明一般要放在头文件中的。
7.2 函数定义
函数的定义是指函数的具体实现,交待函数的功能实现。
.c表示头文件 函数的声明放这里面
.h表示源文件 函数的定义放这里面
在一个源文件里面要引用自己定义的函数的格式 #include " .h"
例如:
定义一个add函数
add.h
#ifndef __TEST_H__
#define __TEST_H__
//函数的声明
int Add(int x, int y);
#endif //__TEST_H__
add.c
//函数的定义
int Add(int x, int y)
{
return x+y;
}
在test.c中引用add函数
#include <stdio.h>
#include "add.h"
int main()
{
int a=0;
int b=0;
int c=0;
scanf("%d%d",&a,&b);
c=add(a,b);//函数的调用
printf("%d\n",c);
return 0;
}
8.函数的递归和迭代
8.1 什么是递归?
程序调用自身的编程技巧称为递归( recursion)。
递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接
调用自身的
一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,
递归策略
只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
递归的主要思考方式在于:把大事化小
8.2 递归的两个必要条件
存在限制条件,当满足这个限制条件的时候,递归便不再继续。
每次递归调用之后越来越接近这个限制条件。
8.3函数的递归和迭代的应用
(1)接受一个整型值,控制顺序打印他的每一位
如:输入:1234 输出:1 2 3 4
void print(int a)
{
if (a > 9)
{
print(a / 10);
}
printf("%d", a%10);
printf(" ");
}
int main()
{
int a = 0;
scanf("%d", &a);
print(a);
return 0;
}
(2)求n的阶乘(不考虑溢出)
思路:
n=1时n!=1;
n>1时n!=n*(n-1)……1;
int Fac(int n)
{
int sum = 0;
if (n > 1)
{
sum = Fac(n - 1)*n;
}
else
sum = 1;
return sum;
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret=Fac(n);
printf("%d\n", ret);
return 0;
}
(3)求斐波那契数
int Fib(int n)
{
if (n > 2)
{
n = Fib(n - 1) + Fib(n - 2);
}
else
{
n= 1;
}
return n;
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fib(n);
printf("%d\n", ret);
return 0;
}
总结
- 一个 return只能返回一个值
- 函数不能嵌套定义可以嵌套调用
- 函数数据间的传递不可以用全局变量
- 函数的定义不一定放在函数使用之前
- 传值调用不影响实参,传址调用可以通过形参改变实参
- 函数设计应该高内聚低耦合,尽量少使用全局变量,参数不应过多
- C语言规定main函数位置可以任意
- 函数中复合语句定义的函数不一定能够在本函数中都能使用
如:
`int main()
{
{
int a=10;
}
printf("%d",a);
return 0;
}
运行错误:a未声明
栈溢出:就是说栈区存储空间容量满出来了
内存区域: