函数—递归的内容先跳过了,后面再补

提示:

文章目录

  • 1、函数是什么
  • 2、库函数
    • C语言常用的库函数:
  • 3、自定义函数
    • (1)写一个函数可以找出两个整数中的最大值
    • (2)写一个函数可以交换两个整型变量的内容
  • 4、函数参数
    • (1)实际参数(实参)
    • (2)形式参数(形参)
  • 5、函数调用
    • (1)传值调用:不需要改变实参
    • (2)传址调用:需要改变实参
    • (3)练习
      • (1)写一个函数判断一个数是不是素数
        • 方法1:
        • 方法2:不推荐
        • 方法3:最好的方法
      • (2)判断100~200之间的素数
      • (3)判断是否为闰年
      • (4)实现一个整型有序数组的二分查找
      • (5)写一个函数,每调用一次函数,就会将 num 的值增加 1
  • 6、函数的c嵌套调用和链式访问
    • (1)嵌套调用
      • (a).函数和函数之间可以有机的组合的。
      • (b)不可以嵌套定义!
    • (2)链式访问
      • (a)
      • (b) “printf 函数”返回的是:打印在屏幕上的字符的个数
  • 7、函数的声明和定义
    • (1)函数声明
    • (1)函数定义
  • 8、函数递归

1、函数是什么

子程序

2、库函数

C语言并不会直接实现库函数,而是提供了C语言的标准和库函数的约定。
比如:scanf 功能,名字,参数,返回值。
库函数的实现一般是由编译器去实现的。

C语言常用的库函数:

IO函数
字符串操作函数
字符操作函数
内存操作函数
时间/日期函数
数学函数
其他库函数

3、自定义函数

(1)写一个函数可以找出两个整数中的最大值

#include <stdio.h>

int maxab(int a, int b)
{
	return (a > b) ? (a) : (b);  //条件运算符(三目运算符)
}

int main()
{
	int x = 10;
	int y = 18;
	int max = maxab(x, y);
	printf("max=%d
", max);
	return 0;
}

(2)写一个函数可以交换两个整型变量的内容

知识点
由于返回值类型是:void,所以可以写 return ,但是后面什么都不要写了。

#include <stdio.h>

void change(int *a, int *b)  //void 表示这个函数不返回任何值,也不需要返回。
{
	int c;
	c = *a;  //指针
	*a = *b;
	*b = c;
	return;     //由于返回值类型是:void,所以可以写 return ,但是后面什么都不要写了。
}

int main()
{
	int x = 10;
	int y = 15;
	printf("交换之前:x=%d;y=%d
", x, y);
	change(&x, &y);
	printf("交换之后:x=%d;y=%d
", x, y);
	return 0;
}

4、函数参数

(1)实际参数(实参)

实参可以是:常量,变量,表达式,函数等。
无论实参是何种类型的量,在进行函数调用时,它们必须有确定的值,以便把这些值传送给形参。

max = get_max(3, 5);  //常量
max = get_max(x, y);  //变量
max = get_max(3 + 5, 8);  //表达式
max = get_max(2 + 4, get_max(4, 7));  //函数

(2)形式参数(形参)

形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。
形式参数当函数调用完成之后就自动销毁了。
因此,形式参数只在函数中有效。

5、函数调用

(1)传值调用:不需要改变实参

函数的形参和实参分别占有不同的内存块,对形参的修改不会影响。

(2)传址调用:需要改变实参

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

(3)练习

(1)写一个函数判断一个数是不是素数

方法1:
#include <stdio.h>
#include <math.h>

int main()
{
	int input;
	printf("请输入一个整数:");
	scanf("%d", &input);
	int i=2;
	for (i = 2; i <= sqrt(input); i++)  //必须从 i=2 开始
	{
		if (input % i == 0)
		{
			puts("这个数不是素数");
			break;
		}
	}
	if (i > sqrt(input))
	{
		puts("找到了");
	}
	return 0;
}
方法2:不推荐
#cinclude <stdio.h>
#include <math.h>

int sushu(int input)
{
	int i = 2;
	for (i = 2; i <= sqrt(input); i++)  //必须从 i=2 开始
	{
		if (input % i == 0)
		{
			puts("这个数不是素数");
			break;
		}
	}
	if (i > sqrt(input))
	{
		puts("找到了");
	}
}

int main()
{
	int input;
	printf("请输入一个整数:");
	scanf("%d", &input);
	sushu(input);
	return 0;
}
方法3:最好的方法

方法2和方法3的区别在于:
功能要“单一”,“独立”。
sushu() 是用来判断素数的,而不是像方法2那样用来打印的,要保持功能的单一化。

#include <stdio.h>
#include <math.h>

int sushu(int a)
{
	int i = 0;
	for (i = 2; i <= sqrt(a); i++)  //必须从 i=2 开始
	{
		if (a % i == 0)
		{
			return 0;  //不是素数,返回 0 
		}
	}
	return 1;  //是素数,返回 1
}

int main()
{
	int input;
	int x;
	printf("请输入一个整数:");
	scanf("%d", &input);
	x=sushu(input);
	if (1 == x)
	{
		printf("%d是素数
", input);
	}
	else
	{
		printf("%d不是素数
", input);
	}
	return 0;
}

(2)判断100~200之间的素数

功能要单一,独立

#include <stdio.h>
#include <math.h>

int sushu(int a)   //功能要单一,独立
{
	int i = 0;
	for (i = 2; i <= sqrt(a); i++)
	{
		if (a % i == 0)
		{
			return 0;  //不是素数,返回 0 
		}
	}
	return 1;  //是素数,返回 1
}

int main()
{
	int i = 0;
	int a;
	for (i = 100; i <= 200; i++)
	{
		a = sushu(i);
		if (a == 1)
		{
			printf("%d是素数
", i);
		}
		else
		{
			printf("%d不是素数
", i);
		}
	}
	return 0;
}

(3)判断是否为闰年

功能要单一,独立

#include <stdio.h>

int leapyear(int year)   //功能要单一,独立
{
	if ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0))
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

int main()
{
	int i = 0;
	int j = 0;
	for (i = 1000; i <= 2000; i++)
	{
		j = leapyear(i);
		if (j == 1)
		{
			printf("%d是闰年
", i);
		}
	}
	return 0;
}

(4)实现一个整型有序数组的二分查找

功能要单一,独立

#include<stdio.h>

int search(int a[], int k, int sz)  //功能要单一,独立
{
	int left = 0;
	int right = sz - 1;  //为什么减去1,因为是数组的下标
	
	while (left <= right)
	{
		int mid = (left + right) / 2;
		if (a[mid]<k)
		{
			left = mid + 1;
		}
		else if (a[mid] > k)
		{
			right = mid - 1;
		}
		else
		{
			return mid;
		}
	}
	return -1;  //找不到了!
}

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int key = 7;
	int size = sizeof(arr) / sizeof(arr[0]);  //不用减1,因为没有结束标志 ''
	int ret = search(arr, key, size);
	if (-1 == ret)
	{
		puts("找不到了");
	}
	else
	{
		printf("找到了,下标是:%d
", ret);
	}
	return 0;
}

(5)写一个函数,每调用一次函数,就会将 num 的值增加 1

#include <stdio.h>

void add(int *p)  
{
	(*p)++;
}

int main()
{
	int num = 0;
	add(&num);
	add(&num);
	printf("调用的次数:%d
", num);
	return 0;
}

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

(1)嵌套调用

(a).函数和函数之间可以有机的组合的。

#include <stdio.h>

void new_line()
{
	printf("hehe
");
}

void three_line()
{
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		new_line();  //嵌套调用
	}
}

int main()
{
	three_line();
	return 0;
}

(b)不可以嵌套定义!

int test1
{
	int test2()
	{
		.....//这是错误的,不支持 int test2() 嵌套定义
	}
}

(2)链式访问

把 一个函数的返回值 作为 另外一个函数的参数

(a)

#include <stdio.h>
#include <string.h>

int main()
{
	char arr[20] = "hello";
	int sz = strlen(strcat(arr, "world"));  //链式访问
	printf("%d
", sz);
	return 0;
}

(b) “printf 函数”返回的是:打印在屏幕上的字符的个数

#include <stdio.h>
#include <string.h>

int main()
{
	printf("%d
", printf("%d
", printf("%d
", 43)));
	return 0;
}

在这里插入图片描述
解释:------43
------ 3个字符
---------------3
-------- 2个字符
换行符’
’,也是一个字符!(容易忽略)

7、函数的声明和定义

(1)函数声明

函数的声明一般出现在函数的使用之前。要满足 先声明,后使用。
函数的声明一般要放在头文件中的。

(1)函数定义

函数的定义是指函数的具体实现,交代函数的功能实现

8、函数递归

微软雅黑字体
黑体
3号字
4号字
红色
绿色
蓝色