文章目录:
1.函数的概念
2.函数的分类
2.1库函数
2.2自定义函数
3.函数的参数
3.1实际参数
3.2形式参数
4.函数的调用
4.1传值调用
4.2传址调用
5.函数的嵌套调用和链式访问
5.1嵌套调用
5.2链式访问
6.函数的声明和定义
6.1函数声明
6.2函数定义
7.函数递归
7.1什么是递归
7.2递归的两个必要条件
7.2.1实例
7.3递归和迭代
7.3.1实例1,求n的阶乘(不考虑溢出)
7.3.2求第n个斐波那契数。(不考虑溢出)
1.函数的概念
2.函数的分类C语言中函数是子程序,一般会有输入参数并有返回值,提供对过程的包装和细节的隐藏。函数也是模块化编程的一种体现,在C程序中,子模块的作用是由函数完成的。
2.1库函数C语言中函数分为库函数和自定义函数两大类。
库函数又称标准函数,由C系统提供,无需程序员定义,可直接使用,只需要在程序开头包含原型声明的头文件即可。如scanf(),printf()等。
下面就拿库函数strcpy来举个栗子,
strcpy的作用是:将源指向的C字符串复制到目标指向的数组中,包括中止的空字符(并在该点停止),下面来个代码实例:
2.2自定义函数自定义函数是由程序员根据自身需求编写,来完成特定的功能,同样也有函数名,返回类型和函数参数。需要在程序中定义后,再在主函数中调用该函数。
函数的格式
ret_type fun_name(para1)
{
statement;//语句项
}
ret_type 返回类型
fun_name 函数名
para1 函数参数(参数可能不止一个或没有)
我们拿一个简单的加法函数来举个例子
3.函数的参数 3.1实际参数3.2形式参数真实传给函数的参数叫实参。
实参可以是:常量,变量,表达式,函数等。
无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。
4.函数的调用 4.1传值调用形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效
函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参。
下面还是通过这个加法函数来,了解传值调用:
可见将实参啊a,b传值给形参x,y后二者的内容是相同的但地址是不同的,也就是说形参开辟了新的空间里面用来放实参的内容,所以说形参是实参的一份临时拷贝
4.2传址调用传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。 这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接 *** 作函数外部的变量。
我们写一个函数交换两个整形的变量的内容,来了解传址调用
可见形参px,py(指针标变量)开辟了新的空间,不过里面存的内容是实参a,b的地址,所以形参可以通过地址找到实参,并对实参进行修改。而如果这里用传值调用能否达到目标效果呢,下面我们来试试
由此可见使用传值调用是没法达到目的的,当函数调用的时候实参传给形参时,形参将是实参的一份临时拷贝所以对形参的修改是不影响实参的。
5.函数的嵌套调用和链式访问 5.1嵌套调用void new_line()
{
printf("hehe\n");
}
void three_line()
{
int i = 0;
for (i = 0; i < 3; i++)
{
new_line();
}
}
int main()
{
three_line();
return 0;
}
//three_line函数嵌套new_line函数。
注意!函数可以嵌套使用,但是不能嵌套定义。
5.2链式访问把一个函数的返回值作为另外一个函数的参数。
猜猜下面这个代码会输出什么
#include
int main()
{
printf("%d", printf("%d", printf("%d", 43)));
return 0;
}
这里我们首先要知道printf函数的返回值是打印在屏幕上字符的个数,这里会先打印43返回2,再打印2返回1,所以输出结果是4321,这就是函数的链式访问。
6.函数的声明和定义 6.1函数声明1.告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在,函数声明决定不了.(简单的说就是告诉编译器有这么个函数,声明中的形参在函数被调用时并不开辟空间)
2.函数的声明一般出现在函数的使用之前。要满足先声明后使用。
3.函数的声明一般要放在头文件中的。
具体格式
ret_type fun_name(para1,);
ret_type 返回类型
fun_name 函数名
para1 函数参数((参数可能不止一个或没有))
6.2函数定义
函数的定义是指函数的具体实现,交待函数的功能实现。7.函数递归 7.1什么是递归
7.2递归的两个必要条件程序调用自身的编程技巧称为递归( recursion)递是递推,归是回归
递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
递归的主要思考方式就是把大事化小。
1.存在限制条件,当满足这个限制条件的时候,递归便不再继续。 2.每次递归调用之后越来越接近这个限制条件。7.2.1实例
接受一个整型值(无符号),按顺序打印它的每一位
如:输入1234 ,输出1 2 3 4
#include
void print(unsigned int n)
{
if (n > 9)
{
print(n / 10);
}
printf("%d ", n % 10);
}
int main()
{
unsigned int num = 0;
scanf("%u", &num);
print(num);//按照顺序打印num的每一位
return 0;
}
画图理解
7.3递归和迭代 7.3.1实例1,求n的阶乘(不考虑溢出)递归方式
#include
int factorial(int n)
{
if (n == 0)
{
return 1;
}
else
{
return n * factorial(n - 1);
}
}
int main()
{
int n = 0;
scanf("%d", &n);
factorial(n);
printf("%d\n", factorial(n));
return 0;
}
如果考虑溢出的情况,用递归方法如果计算一个很大的数的阶乘时可能会超出int类型的大小,也就是出现栈溢出的现象,导致数据丢失,计算更大的数时程序还可能会崩溃,这时用非递归方式就可以解决这一问题:
#include
int main()
{
int n = 0;
int i = 0;
int sum = 1;
scanf("%d", &n);
for (i = 1; i <= n; i++)
{
sum = i * sum;
}
printf("%d\n", sum);
return 0;
}
7.3.2求第n个斐波那契数。(不考虑溢出)
递归方式
#include
int Fib(int x)
{
if (x <= 2)
return 1;
else
return Fib(x - 1) + Fib(x - 2);
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fib(n);
printf("%d\n", ret);
return 0;
}
但是我们发现在使用 Fib 这个函数的时候如果我们要计算第50个斐波那契数字的时候特别耗费时间。这是因为会出现很多重复计算,所以求斐波那契数是不适合使用递归求解的,而用非递归的方法来求解是个很好的选择:
#include
int Fib(int x)
{
int a = 1;
int b = 1;
int c = 1;
while (x > 2)
{
c = a + b;
a = b;
b = c;
x--;
}
return c;
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fib(n);
printf("%d\n", ret);
return 0;
}
小提示:
1. 许多问题是以递归的形式进行解释的,这只是因为它比非递归的形式更为清晰。 2. 但是这些问题的迭代实现往往比递归实现效率更高,虽然代码的可读性稍微差些。 3. 当一个问题相当复杂,难以用迭代实现时,此时递归实现的简洁性便可以补偿它所带来的运行时开销。 4.递归一定要有限制条件,不然就是死递归 5.递归并不能很好的解决每个问题,我们需要具体问题具体分析选择一个最优方法来解决。
好了以上就是今天的全部内容了,能给友友们带来收获的话不妨三连关注一波,后期会持续更新C语言干货。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)