C语言02——函数【重点:递归】

函数

一、函数是什么

  • 某一个大型程序中的部分代码,由一个或多个语句块组成。

  • 会有输入参数或返回值

二、库函数

  • https://cplusplus.com/reference/
  • C语言常用的库函数有:
    • IO函数
    • 字符串操作函数
    • 字符操作函数
    • 内存操作函数
    • 时间/日期函数
    • 数学函数
    • 其他库函数
int main()
{
	//库函数:memset 内存设置:(某个数组,用什么填充,前几个字符)
	char arr[] = "hello bit";
	memset(arr,'x',5);
	printf("%s\n",arr);
	return 0;
}
int main()
{
	//库函数:memset:
	//strcpy:函数是将一个字符串的全部内容(包括'\0')拷贝到另一个字符串里
	char arr1[20] = {0};
	char arr2[10] = "hello bit";
	strcpy(arr1, arr2);		//将arr2的值赋给arr1
	printf("%s\n", arr1);
	printf("%s\n", arr2);
	return 0;
}

三、自定义函数

有函数名、返回值类型、函数参数

3.1 找出两个整数中的最大值
int get_max(int x, int y)	//传值调用:交换两个数 
{
	int z = 0;
	if (x > y)
		z = x;
	else
		z = y;
	return z;
}

int main()
{
	//自定义函数:返回两数之间的最大的那个数
	int a = 0;
	int b = 0;
	scanf("%d%d",&a,&b);
	int max = get_max(a,b);
	printf("%d\n",max);
	return 0;
}
3.2 交换两个整型变量的内容
void Swap(int* pa, int* pb)   //传址调用
{
	/*
	Swap 在被调用的时候,实参传给形参,其实形参是实参的一个临时拷贝
	改变形参,不会改变实参的值
	*/
	int z = 0;
	z = *pa;
	*pa = *pb;
	*pb = z;
}
int main()
{
	//自定义函数:交换两个整型变量的内容
	/*int a = 10;
	int* pa = &a;
	*pa = 20;
	printf("%d\n",a);*/
	int a = 10;
	int b = 20;

	printf("交换前:a=%d,b=%d\n", a, b);
	Swap(&a,&b);
	printf("交换后:a=%d,b=%d\n",a,b);

	return 0;
}
3.3 自定义函数输出100-200间的素数
int is_prime(int n)
{
	//2 - (n-1) 之间的数字
	int j = 0;
	for (j = 2;j < n;j++)
	{
		if (n % j == 0)
			return 0;
	}
	return 1;
}
int main()
{
	//自定义函数输出100-200间的素数
	int i = 0;
	int count = 0;
	for (i = 100; i <= 200; i++)
	{
		if (is_prime(i) == 1)
		{
			count++;
			printf("%d ",i);
		}
	}
	printf("\ncount = %d\n",count);
	return 0;
}
3.4 判断1000-2000年里的闰年有哪些且有几个
int is_leap_year(int n)
{
	//if ((n % 4 == 0 && n % 100 != 0) || n % 400 == 0) 
	//	return 1;	//如果n符合if中的条件,则return 1,否则return 0
	//return 0;

	//也可以写成:直接return返回,正确返回1否则返回0
	return ((n % 4 == 0 && n % 100 != 0) || n % 400 == 0);
}
int main()
{
	//自定义函数:判断1000-2000里的是不是闰年
	int year = 0;
	int count = 0;
	for (year = 1000; year <= 2000; year++)
	{
		if (is_leap_year(year) == 1)
		{
			count++;
			printf("%d ", year);
		}
	}
	printf("\ncount = %d\n", count);
	return 0;
}
3.5 写个函数实现一个整型有序数组的二分查找
int binary_search(int a[], int k, int s)
{
	int left = 0;
	int right = s - 1;
	while (left <= right)
	{
		int mid = (left + right) / 2;
		if (a[mid] > k)
		{
			right = mid - 1;
		}
		else if (a[mid] < k)
		{
			left = mid + 1;
		}
		else
		{
			return mid;
		}
	}
	return -1;		//找不到了
}
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int key = 0;	//想要查找的数
	printf("请输入您想查找的数:>");
	scanf("%d",&key);
	int sz = sizeof(arr) / sizeof(arr[0]);
	int ret = binary_search(arr, key, sz);
	if (-1 == ret)
	{
		printf("找不到\n");
	}
	else
	{
		printf("找到了,下标是:%d\n",ret);
	}
	return 0;
}
3.6 写一个函数,每调用一次这个函数,就会将num 的值增加1。
void Add1(int* p)
{
	(*p)++;
}
int main()
{
	//自定义函数:每调用一次这个函数,就会将num的值加1
	int num = 0;
	Add1(&num);
	printf("%d\n", num);
	Add1(&num);
	printf("%d\n", num);
	Add1(&num);
	printf("%d\n", num);
	Add1(&num);
	printf("%d\n", num);
	return 0;
}

四、函数调用

void Test2()
{
	printf("hehehehe\n");
}
void Test1()
{
	Test2();
}
int main()
{
	//函数嵌套定义和嵌套调用
	//嵌套定义:在一个函数里定义另一个函数——不可以
	//嵌套调用:可以调用 
	Test1();
	return 0;
}

五、函数的嵌套调用和链式访问

int main()
{
	//链式访问:把一个函数的返回值作为另外一个函数的参数
	int len = strlen("abc");
	printf("%d\n",len);

	//链式访问例一:
	printf("%d\n",strlen("abc"));

	//链式访问例二:
	char arr1[10] = { 0 };
	char arr2[] = "bit";
	printf("%s\n",strcpy(arr1,arr2));

	//链式访问例三:printf函数返回的是打印在屏幕上的个数:打印出43(两个字符返回2),打印出2(1个字符返回1),所以4321
	printf("%d", printf("%d", printf("%d", 43)));	//4321
	return 0;
}

六、函数的声明和定义

  1. 先定义后使用,定义是一种强有力的声明
  2. 先使用后定义,少见
  3. 函数声明一般放在对应头文件中,函数定义一般放在对应 .c 文件中
int main()
{
	int a = 9;
	int b = 10;
	//声明一下Add函数:(只写类型)只声明,不能说明存在
	int Add(int, int);
	int c = Add(a, b);
	printf("%d\n", c);
	return 0;
}
int Add(int x, int y)
{
	return x + y;
}

七、函数递归recursion

什么是递归:将一个大的问题层层转化为一个与原问题相似的较小问题来求解。用少量的程序来描述解题过程中所需要的多次重复计算,从而减少程序代码量。大事化小

必须有的两个条件:

  • 存在限制条件:当递归满足这个条件时,递归则不会继续。
  • 每次递归调用之后越来越接近这个限制条件
7.1 接受一个整型值(无符号),按照顺序打印出它的每一位

输入:1234,输出1 2 3 4

void print(unsigned int n)
{
	if (n > 9)
	{
		print(n / 10);
	}
	printf("%d ",n % 10);
}
int main()
{
	unsigned int num = 0;
	printf("请输入一个无符号整数:>\n");
	scanf("%u",&num);		//%u  表示获取一个无符号整数:
	print(num);	//自定义的一个函数:用于打印参数中的每一位数字
	return 0;
}
7.2 编写函数不允许创建临时变量,求字符串的长度
void print(unsigned int n)
{
	if (n > 9)
	{
		print(n / 10);
	}
	printf("%d ",n % 10);
}
int main()
{
	unsigned int num = 0;
	printf("请输入一个无符号整数:>\n");
	scanf("%u",&num);		//%u  表示获取一个无符号整数:
	print(num);	//自定义的一个函数:用于打印参数中的每一位数字
	return 0;
}
7.3 自定义一个函数求字符串的长度
int my_strlen(char* str)
{
	//用递归的方法写:
	/*int count = 0;
	while (*str != '\0')
	{
		count++;
		str++;
	}
	return count;*/

	if (*str != '\0')
		return 1 + my_strlen(str + 1);
	else
		return 0;
}
int main()
{
	char arr[] = "bit";
	//['b']['i']['t']['\0']
	printf("%d\n",my_strlen(arr));			//括号里的参数是首元素的地址,即字符的地址
	return 0;
}

八、 递归与迭代

递归是重复调用函数自身实现循环。迭代是函数内某段代码实现循环,而迭代与普通循环的区别是:循环代码中参与运算的变量同时是保存结果的变量,当前保存的结果作为下一次循环计算的初始值。

8.1 求n的阶乘,不考虑溢出
int Fac(int n)
{
	if (n < 1)
		return 1;
	else
		return n * Fac(n - 1);
}
int main()
{
	int i = 0;
	int n = 0;
	printf("请输入一个数:>");
	scanf("%d",&n);
	int ret = Fac(n);
	printf("ret = %d\n",ret);
	return 0;
}
8.2 求第n个斐波那契数,不考虑溢出
  • 使用递归:但效率太低
int Fib(int n)
{
	//计算第3个fib斐波那契数的计算次数
	if (n <= 2)
		return 1;
	else
		return Fib(n - 1) + Fib(n - 2);
}
int main()
{
	int n = 0;
	printf("请输入一个数:>");
	scanf("%d",&n);
	int ret = Fib(n);
	printf("%d\n",ret);
	return 0;
}
  • 使用循环:效率提高
int Fib(int n)
{
	int a = 1;
	int b = 1;
	int c = 1;
	while (n > 2)
	{
		c = a + b;
		a = b;
		b = c;
		n--;
	}
	return c;
}
int main()
{
	int n = 0;
	printf("请输入一个数:>");
	scanf("%d",&n);
	int ret = Fib(n);
	printf("%d\n",ret);
	return 0;
}
8.3 接受一个整型值(无符号),按照顺序打印出它的每一位。例如:输入1234,输出1 2 3 4
void print(unsigned int n)
{
	if (n > 9)
	{
		print(n / 10);
	}
	printf("%d ",n % 10);
}
int main()
{
	unsigned int num = 0;
	printf("请输入一个无符号整数:>\n");
	scanf("%u",&num);		//%u  表示获取一个无符号整数:
	print(num);	//自定义的一个函数:用于打印参数中的每一位数字
	return 0;
}

例如:1234 最容易得到的数是4

1234 / 10 =123 1234 % 10 = 4

123 / 10 = 12 123 % 10 = 3

12 / 10 = 1 12 % 10 = 2

1 / 10 = 0 1 % 10 = 1

8.4 求字符串的长度
int my_strlen(char* str)
{
	//用递归的方法写:
	/*int count = 0;
	while (*str != '\0')
	{
		count++;
		str++;
	}
	return count;*/

	if (*str != '\0')
		return 1 + my_strlen(str + 1);
	else
		return 0;
}
int main()
{
	char arr[] = "bit";
	//['b']['i']['t']['\0']
	printf("%d\n",my_strlen(arr));			//括号里的参数是首元素的地址,即字符的地址
	return 0;
}
8.5 计算从1-100的所有整数中出现了多少个数字9
int main()
{
	int i = 0;
	int count = 0;
	for (i = 1; i <= 100; i++)
	{
		if (i % 10 == 9)
			count++;			//这里不能写成()||()的形式,因为99两个if都得count++
		if (i / 10 == 9)
			count++;
	}
	printf("count = %d\n",count);
	return 0;
}
8.6 计算1/1-1/2+1/3-1/4+1/5-1/6+…+1/99-1/100的值,方法一:
int main()
{
	int i = 0;
	double sum = 0.0;
	for (i = 1; i <= 100; i++)
	{
		if(i % 2 == 0) 
			sum -= 1.0 / i;				//a / b 只要有一个是小数,即是精确除,结果为小数
		else
			sum += 1.0  / i;

	}
	printf("sum = %lf\n",sum);
	return  0;
}

除法分为整除和精确除,整除即两个数都是整数,精确除:a、b至少一个是小数

//方法二:使用flag
int main()
{
	int i = 0;
	double sum = 0.0;
	int flag = 1;
	for (i = 1; i <= 100; i++)
	{
		sum += flag * 1.0 / i;
		flag = -flag;
	}
	printf("sum = %lf\n", sum);
	return 0;
}

使用flag来表示一个判断的变量,flag作为一个指示变量变化的名称

8.7 计算一个数的每位之和

调用DigitSum(1729),返回1+7+2+9

int DigitSum(int n)
{
	if (n > 9)
	{
		return DigitSum(n / 10) + n % 10;
	}
	else
	{
		return n;
	}
}
int main()
{
	int i = 1729;
	int ret = DigitSum(i);
	printf("ret = %d\n",ret);
	return 0;
}
8.9 递归实现n的k次方

使用小数是为了可以计算负数 ,除法a/b,ab至少有一个为小数,则结果为小数

double Pow(int n, int k)
{
	if (k == 0)
		return 1.0;
	else if (k > 0)
		return n * Pow(n, k - 1);
	else
		return 1.0 / (Pow(n,-k));
}
int main()
{
	int n = 0;
	int k = 0;
	scanf("%d %d",&n,&k);
	double ret = Pow(n,k);
	printf("%lf\n",ret);
	return 0;
}

你可能感兴趣的:(C,c语言)