栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C语言 初识函数

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C语言 初识函数

1.函数是什么?

函数其实就是子程序,是一个具有特定功能的代码块

2.函数有库函数,也有自定义函数

函数存在形参,实参,(可以是内存,变量,表达式,甚至是函数)

形式参数,只在调用的时候分配内存,而且一旦函数结束内存立马销毁,因此称为形式参数

 main函数里面调用函数时的是实参,main函数上面定义函数时使用的是形参。

注意:当函数调用的时候,实参传给形参时,形参其实只是实参的一份临时拷贝(另外的内存空间),对形参修改数值不会影响实参的值(当然return回去另当别论)

举例:写一个交换a,b变量的函数,先来错误示范,

#include
void exchange(int x, int y)
{
	int z = 0;
	z = x;
	x = y;
	y = z;
}
int main()
{
	int a, b;
	scanf("%d %d", &a, &b);
	printf("交换前:a=%d,b=%dn", a, b);
	exchange(a, b);
	printf("交换后:a=%d,b=%dn", a, b);
	return 0;
}

我们可以看到代码结果是有问题的,这是为什么?

 

 原因就是实参a,b传到形参时,电脑为形参x,y创建了新的内存空间,x,y的互换只是另一片存储空间的值的改变,结果并未影响到实参所在的内存地址。

那么我们应该怎么利用形参影响实参呢?

3.函数调用

函数调用分两种:传值调用和传址调用

上面用的就是传值调用,把实参的值调给形参(形参不会影响实参)

那不得不提另一种方法了,传地址给函数,然后函数接受对应的地址后解引用隔空操作另一边的变量

#include 
void exchange2(int* pa, int* pb)//拿a,b的地址
{
	int z = 0;
	z = *pa;
	*pa = *pb;//解引用操作,对*pa操作就是对变量a操作
	*pb = z;
}
int main()
{
	int a, b;
	scanf("%d %d", &a, &b);
	//交换2个变量
	printf("交换前:a=%d b=%dn", a, b);


	//exchange1(a, b);//传值调用
	exchange2(&a, &b);//传址调用
	printf("交换后:a=%d b=%dn", a, b);

	return 0;
}

ps:数组在传递到函数的时候不是传递一串地址,而是首个元素的地址,

#include
int binary_search(int arr[], int k)
{
    //代码就不写全了,水平有限
    int sz = sizeof(arr) / sizeof(arr[0]);//这里形参其实取到了实参数组的首个元素的地址,所以想                    
                                            利用这个操作求arr数组的长度是不现实的,最后sz是1
}

int main()
{

    int ret = binary_search(arr, k);
    return 0;
}

总结:函数要尽可能简洁(不是简单!)明了,功能单一,不要杂七杂八全往里塞,

在不需要改变实参的值是可以用传值调用;需要改变实参时考虑传址调用。

---------------------------------------------------------------------------------------------------------------------------------

4.函数的嵌套调用,如在函数A中调用B,注意是调用,不是定义

C语言支持函数嵌套调用,但不支持嵌套定义

5.函数的链式访问,指函数的返回值作为函数的实参

如printf("%dn", printf("%dn", printf("%dn",123)));   就是链式调用

printf函数的返回值是printf实际控制输出的字符数,如第一次是123n四个字符,因此第一次先打印123,返回4;

第二次是4n两个字符,所以返回2

 

6.函数的定义与声明 (ps:建议先写调用函数然后再回到mian函数上面定义)【先想好怎么用在定义不容易错】--仅代表个人观点

函数一般有两种使用方式 第一种先声明,然后再main函数里调用,最后定义函数(大部分经典计算机书上都这么写,感觉麻烦)

第二种 在main函数前定义,然后使用

【函数建议写在头文件里,然后在源文件里引用】

7.函数递归,

    1.就是函数调用的过程中调用了自身,从而将一个复杂的问题一次次转化为相对简单的同类型问题。递归,先递后归,把问题一步步递到简单的问题,然后回归

如:想知道5个人的年龄,a说他一岁,b说比a大一岁,c说比b大一岁以此类推,

我们想知道e的年龄就要知道d的,然后就要知道c的····直到直到a的,这就是递的过程;

知道了a的年龄,我们就可以知道b的,然后知道c的,一步步归回e的年龄

   2.函数递归有两个必要条件(没有程序会死递归出错)

    一个是设置递归的结束条件,还是上面的例子,想知道的e的年年龄我们只需要递到a就可以了,a的年龄为1岁就是结束条件;

还有一个是递归的关系式(能让问题不断趋于简单的方向,如果不能那还用什么递归)

   3.函数递归的stackoverflow(栈溢出)【为什么死递归会导致程序崩溃】

内存分为三块,函数调用时程序会在栈区请求开辟一块空间,每一次调用函数函数都会开辟一片空间,如果是死循环那么当栈区没有空间可用时编译器就会报stackoverflow。

      

ps:stackoverflow也是国外一个网站,相当于程序员的知乎,不过是英文的

Stack Overflow - Where Developers Learn, Share, & Build Careers

 

        

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/429591.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号