C语言函数反恐集

函数在我们C语言里可谓是经常可以用到,所以了解函数,学会函数怎么使用是很重要的。

目录

1.什么是函数?

2.函数分类

2.1库函数

2.2自定义函数

3.函数的参数

3.1实际参数

3.2形式参数

4.函数的调用

4.1分类

4.2嵌套调用​​​​​​​

4.3链式访问

5.函数的声明

6.函数的递归与迭代

6.1递归

6.2迭代


1.什么是函数?

  • 函数是一个大型程序中的某部分代码,由一个或多个语句块组成,它负责完成某个特定的任务,相较于其它代码,函数具有相对独立性。
  • 一般有输入参数和返回值,提供对过程的分装和细节的隐藏。

2.函数分类

函数分为库函数和自定义函数。

2.1库函数

库函数分类

  • I/O函数 :input与output函数  printf  scanf  getchar  putchar等
  • 字符串操作函数:strlen strcmp等
  • 字符操作函数:大小写转换  字符分类等
  • 内存操作函数:memcpy  memove memset等
  • 时间/日期函数:time等
  • 数学函数:pow sqrt等
  • 其它库函数

使用库函数

这里给大家推荐两个网站来了解C语言中的库函数,在网站里我们可以查找对应库函数如何使用,它所对应的头文件。

www.cplusplus.com(英文版)

http://zn.cppreference.com(中文版)

在这里给大家演示一个库函数

strcpy函数——string copy 字符串拷贝

 在红框框柱的地方我们输入要查找的库函数,就会找到它所对应的内容

这样我们就了解了一个库函数的基本使用方法,让我们用这个库函数实现把一个字符串复制到另一个字符串中。

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "hello world!!!" ;
	char arr2[] = "##################################";
	printf("%s\n", arr2);
	strcpy(arr2, arr1);
	printf("%s\n", arr2);
	return 0;
}

 我们可以看到字符串arr1被复制到了arr2,实现了库函数的使用。

2.2自定义函数

库函数在很大程度上确实方便了编程,但是作为一个程序员,最重要的还是要学会自定义函数,我们总会遇到库函数里所没有模板,函数自定义能力才是最有力的工具。

自定义函数的函数名、返回类型、函数参数都是由我们自己来设计的。

return_type funcation_name(paral *)
{
   starement;
}

下面我们来看个例子:例如用函数实现求俩个数中的较大值。

#include<stdio.h>
int Max(int num1, int num2)
{
	return(num1 > num2 ? num1 : num2);
}
int main()
{
	int a = 0;
	int b = 0;
	scanf("%d %d", &a, &b);
	int max = Max(a, b);
	printf("max=%d\n", max);
	return 0;
}

 我们可以清楚的看到这个函数的函数名、返回类型、函数参数都是由我们自己来设计的,max接受函数Max的返回值。

我们再来看一个例子,用函数的方法交换俩个整型变量的内容。

#include<stdio.h>
void swap1(int x, int y)
{
	int tmp = 0;
	tmp = x;
	x = y;
	y = tmp;
}
int main()
{
	int a = 0;
	int b = 0;
	scanf("%d %d", a, b);
	printf("a=%d,b=%d\n", a, b);
	swap1(a, b);
	printf("a=%d,b=%d\n", a, b);
	return 0;
}

我们依旧用定义上一个函数的方法定义这个函数,我们会发现函数没有使两个变量交换内容,没有达到交换俩个整型值的目的。因为这涉及到传值调用还是传址调用的问题,我们把这个问题放到函数调用的目录下解决。

3.函数的参数

3.1实际参数

函数的实际参数是指真实传递给函数的参数。

实参可以是:常量,变量,表达式,函数等。

无论实参是何种类型的量,在进行函数调用时,它们都必须是确定的值,以便把这些值传递给形参。

3.2形式参数

函数的形式参数指的是函数名后括号中的变量。

形参只有在函数被调用过程中才实例化(即给函数分配内存单元),形参在函数调用完成后就自动销毁了,它只在函数中起作用。

 当实参传给形参时,形参其实是实参的一份临时拷贝,对形参的修改是不会改变实参的。

4.函数的调用

4.1分类

  • 传值调用函数的形参和实参分别占用不同的内存块(即a,b,x,y它们的地址是不同的),对形参的修改是不会影响实参的。所以回到我们交换两个整型变量内容的问题上

 可见,我们在这里用的是传值调用,当实参传给形参时,形参其实是实参的一份临时拷贝,对形参的修改是不会改变实参的。所以x和y的值虽然在函数体中交换了,但它们交换后的值是无法传递给a,b的,即a,b的值依然没有交换,所以我们引入传址调用。

  • 传址调用:把函数外部创建的内存地址传递给函数参数的方式。这种方式可以让函数和函数外边的变量真正建立起联系,也就是函数内部可以直接操作函数外部的变量。

这里我们在来解决这个问题:

#include<stdio.h>
void swap2(int* x, int* y)
{
	int tmp = 0;
	tmp = *x;
	*x = *y;
	*y = tmp;
}
int main()
{
	int a = 0;
	int b = 0;
	scanf("%d %d",& a, &b);
	printf("a=%d,b=%d\n", a, b);
	swap2(&a, &b);
	//swap1(a, b);
	printf("a=%d,b=%d\n", a, b);
	return 0;
}

 这种直接传地址的方法,交换了整型变量的内容。

其实想要区分清楚什么时候用传值调用,什么时候用传址调用很简单。在这里给大家分享我的办法。

不改变实参内容的用传值调用,要改变实参的值的用传址调用。

函数有返回值的一般是传值调用(因为笔者目前还没有见过有返回值的是传址调用),函数无返回值的大多是传址调用(除非直接在函数内部打印)。

4.2嵌套调用

看个例子来理解它

4.3链式访问

链式访问就是把一个函数的返回值作为另一个函数的参数。

5.函数的声明

创建一个头文件,文件名后缀为.h,将函数的声明放入头文件,例如

#ifndef __ADD_H__
#define __ADD_H__
int binary_search(int arr[], int k, int sz);
#endif

再创建一个源文件add.c,这里放函数的定义,即函数是怎么实现的。

int binary_search(int arr[], int k, int sz)
{
	int left = 0;
	int right = sz - 1;
	int mid = 0;
	while (left <= right)
	{
		mid = (left + right) / 2;
		if (arr[mid] < k)
			left = mid++;
		else if (arr[mid] > k)
			right = mid--;
		else
			return mid;
	}
	return -1;
}

最后在我们原来创建的源文件中留下我们的主函数

#include<stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int k = 7;
	int sz = sizeof(arr) / sizeof(arr[0]);
	int ret = binary_search(arr, k, sz);
	if (ret == -1)
		printf("Ҳ\n");
	else
		printf("ҵˣ±%d\n", ret);
	return 0;
}

1.函数声明是告诉编译器有一个函数叫什么,参数是什么,返回类型是什么,但具体存不存在,无关紧要。

2.函数声明一般出现在函数使用之前,要满足先声明在使用

3.函数的声明一般放在头文件中。

6.函数的递归与迭代

6.1递归

函数调用自身编程技巧为递归,即一个函数自己调用自己,直接调用或间接调用自身的一种方法。

递归的主要思想是把大事化小

接收一个整型值(无符号),按顺序打印它的每一位。例如输入1234,输出1 2 3 4 。

void print(int n)
{
	if (n > 9)
	{
		print(n / 10);
	}
	printf("%d ", n % 10);
}
int main()
{
	unsigned int num = 0;
	scanf("%d", &num);
	print(num);
	return 0;
}

递归的两个必要条件:

  • 存在限制条件,当满足这个条件时,递归便不再继续。
  • 每次递归调用之后越来越接近这个限制条件。

6.2迭代

迭代就是一直重复做一件事情。

例如求第n个斐波那契数

#include<stdio.h>
int Fib(int num)
{
	int a = 1;
	int b = 1;
	int c = 1;
	while (num > 2)
	{
		c = a + b;
		a = b;
		b = c;
		num--;
	}
	return c;
}
int main()
{
	int n = 0;
	int ret = 0;
	scanf("%d", &n);
	ret= Fib(n);
	printf("ret=%d\n", ret);
	return 0;
}

这种迭代的方法在这个算法中比递归更加高效。

递归和迭代的选择

当俩种方法在使用时都没有问题时,可随意选择;

当在使用时存在明显问题如栈溢出,这种方法就不可以使用了。


OK了,各位家人们,今天的分享就到这里啦,有什么问题欢迎评论。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

月亮夹馍干

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值