关于函数的一些笔记以及心得

最近回过头又学习了下函数的内容,发现自己对于函数其实还有相当一部分没有深入了解的,于是写下这篇博客用以加强记忆,顺便与大家共勉。

首先函数分为库函数以及自定义函数,库函数是编译器自行提供的函数,只需要在.c文件中包含对应的头文件就能够使用,最常用的比如stdio.h中的printf函数以及scanf函数等等,但是如果只是有库函数,那么程序员在编写代码的时候必然会有不便的时候,这个时候就轮到自定义函数出场了。

自定义函数顾名思义,就是程序员根据需要来自己定义的函数,比如,假如我需要求多个球的体积,虽然这个代码很好实现,但是没计算依次就需要敲一次计算的代码未免过于繁琐了,于是我们可以自定义一个函数,这样我们需要计算的时候直接引用就行了,不仅缩短了代码,也使得代码可读性变强了。

#include<stdio.h>
#define N 3.14
float fun(int n)
{
    return 4/3.0*N*n*n*n;
}
int main()
{
    int n1,n2,n3;
    printf("请输入第一个球的半径:");
    scanf("%d",&n1);
    printf("该球的体积是:%f\n",fun(n1));

    printf("请输入第二个球的半径:");
    scanf("%d",&n2);
    printf("该球的体积是:%f\n",fun(n2));
    
    printf("请输入第三个球的半径:");
    scanf("%d",&n3);
    printf("该球的体积是:%f",fun(n3));
    return 0;
}

上面那条代码中,我自定义了一个名叫fun的函数,将输入的实参n1,n2,n3分别引用到函数里面,并且返回了一个float类型的数据用来输出。

一个自定义函数有以下几个要素:

1. 函数名;

我上面定义的函数中,fun就是它的函数名。

2.参数;

在上面的代码中,n1,n2,n3是fun函数的实参,而n是fun函数的形参;

3.返回值;

根据不同的需要来使用不同的类型的函数,比如这里我的函数就是float类型的,因此用的

float fun(int n);

接下来我来讲讲形参与实参的关系。

实参实际上就是在函数被引用时,用来计算的量。

而形参就是函数在使用的时候,接收实参的值的变量。

但是需要有一个注意的是,我上面引用实参的方式并不会对实参造成影响,比如我想交换两个数的值,而我的操作如下:

#include<stdio.h>
void swap(int x,int y)
{
    int z;
    z=x;
    x=y;
    y=z;
}
int main()
{
    int a,b;
    scanf("%d%d",&a,&b);
    printf("交换前:a=%d b=%d\n",a,b);
    swap(a,b);
    printf("交换后:a=%d b=%d\n",a,b);
    return 0;
}

但是实际上的结果却是:

为什么会这样呢?

其实函数的传参是有两种操作的

第一个就是我上面代码的操作,名为传值操作,第二个就是传址操作,只有当你需要更改实参的时候,才需要用到传址操作。

将上面的代码改成下面就对了:

#include<stdio.h>
void swap(int *x,int* y)
{
    int z;
    z=*x;
    *x=*y;
    *y=z;
}
int main()
{
    int a,b;
    scanf("%d%d",&a,&b);
    printf("交换前:a=%d b=%d\n",a,b);
    swap(&a,&b);
    printf("交换后:a=%d b=%d\n",a,b);
    return 0;
}

代码结果如下: 

 大家可以看到,在main函数中的n前面有一个&符号,这个符号表示取地址符号,所以这里实际上是传了一个int类型的地址给函数,而函数接收需要int类型的指针,也就是int *;

其交换操作也是如上面代码,需要用

        z=*x;
      *x=*y;
      *y=z;

来更换。

其中,我们还可以将数组的首地址传给函数,因为数组在地址上实际上是相邻的,所以将数组的首地址传给函数,我们就能顺势读取数组的所以数据;

比如我给个问题,将字符串的数据反向输出,列入输入abcde输出edcba;

代码如下:

#include<stdio.h>
void fun(char* arr)
{
	if (*arr == '\0')
		return;
	else
	{
		fun(arr + 1);
		printf("%c", *arr);
	}
}
int main()
{
	char arr[] = "abcdef";
	fun(arr);
	return 0;
}

这里我使用了函数递归的操作执行,大家可以看到我用char *接收数组的首地址,然后在函数内部根据条件不同来决定是否继续调用函数,而调用函数的操作相信大家也看到了;

fun(s+1);

这里大家可能会有不同意见,为什么这里不用fun(s++)呢?实际上,s+1和s++有不同,s+1实际上并没有改变s的值,而s++改变了s的值,就会导致地址改变,有的编译器上就会报错。

既然我们已经讲到函数的递归操作了,那我们继续深入讲讲递归是怎么一回事吧。

递归有两个条件,一个是递归的停止条件,一个是每一次调用函数,都必须向递归的停止条件接近,比如我上面的操作,递归的停止操作时如果数组访问到 '\0' 的时候就返回,而每一次调用函数都会使得数组向 '\0' 接近。

函数还有其他操作

比如嵌套调用;

就是在函数中调用其它函数,比如你在main函数使用printf函数,这也是一种嵌套调用。

还有链式操作,就是将函数的返回值作为其他函数的参数;

最典型的就是下面的代码:

#include<stdio.h>
int main()
{
	printf("%d",printf("%d",printf("%d",43)));
	return 0;
}

结果如下: 

 这里插入一下其他知识以便大家理解,实际上printf函数是有返回值的,它返回的数字就是输出字符的长度,这条代码最里面的printf函数输出43两个字符,所以第二个输出2一个字符,之后第三个输出1一个字符。

接下来还有一个就是函数声明。

当我们函数定义在main函数下面时,我们需要在main函数上面或者进行函数调用的前面进行函数声明,否则我们的函数是用不了的。

比如:

 这里我将代码放在了函数调用下面了,于是编译器就报错了。

还插一句就是,实际上头文件的引用相当于函数声明,比如我在vs里面新建一个项目,然后像下面几张图这样写:

 

 

 

 这样我们也能够成功的调用函数。

这样的好处就是能够方便调试,以便以后同事的协作。

以上就是我个人的一些心得,感谢看到这里的各位。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值