C语言学习入门之函数详解【上】

目录

  • 1.函数是什么
  • 2.C语言中函数的分类
    • 2.1 库函数
    • 2.2自定义函数
  • 3.函数的参数
    • 3.1实际参数(实参):
    • 3.2形式参数(形参):
  • 4.函数调用
    • 4.1传值调用
    • 4.2传址调用
    • 4.3练习

1.函数是什么

维基百科中对函数的定义:子程序
在计算机科学中,子程序(英语:Subroutine, procedure, function, routine, method, subprogram, callable unit),是一个大型程序中的某部分代码,由一个或多个语句块组成。它负责完成某项特定任务,而且相较于其他代码,具备相对的独立性
一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软件库

2.C语言中函数的分类

1.库函数
2.自定义函数

2.1 库函数

为什么会有库函数?
我们在学习c语言的过程中,会经常用到一些基础功能,不是业务性的代码,每个程序员都可能用到,为了支持可移植性和提高程序的效率,所以c语言的基础库中提供了一系列库函数,方便程序员进行开发

学习库函数的网站:www.cplusplus.com

C语言常用的库函数都有:
IO函数
字符串操作函数
字符操作函数
内存操作函数
时间/日期函数
数学函数
其他库函数

注:使用库函数,必须包含#include对应的头文件

2.2自定义函数

自定义函数和库函数一样,有函数名,返回值类型和函数参数。但是不一样的是这些都是我们自己来设计。这给程序员一个很大的发挥空间
函数的组成:
ret_typefun_name(para1, * )
{
statement;//语句项
}
ret_type返回类型
fun_name函数名
para1 函数参数

举个栗子:写一个函数可以找出两个整数中的最大值

代码演示:

#define _CRT_SECURE_NO_WARNINGS
#include
int get_max(int x ,int y)
{
	return (x > y ? (x):(y));
}
int main()
{
	int num1 = 10;
	int num2 = 20;
	int max = get_max(num1, num2);
	printf("%d\n", max);
	return 0;
}

运行结果:
在这里插入图片描述

再举个栗子:写一个函数可以交换两个整形变量的内容

代码演示:

#define _CRT_SECURE_NO_WARNINGS
#include
//错误写法:
void Swap1(int x ,int y)
{
	int z = 0;
	z = x;
	x = y;
	y = z;
}
//正确写法:
void Swap2(int* px, int* py)
{
	int z = 0;
	z = *px;
	*px = *py;
	*py = z;
}
int main()
{
	int a = 10;
	int b = 20;
	Swap1(a,b);
	printf("Swap1:a=%d,b=%d\n", a, b);
	Swap2(&a,&b);
	printf("Swap2:a=%d,b=%d\n", a, b);
	return 0;
}

运行结果:
在这里插入图片描述

分析:当实参传递给形参的时候,形参是实参的一份临时拷贝,对形参的修改不能改变实参,那么对xy的值进行交换是不能 影响ab的值的
int *px接收a的地址,int *py接收b的地址,才能对ab的值进行修改

3.函数的参数

3.1实际参数(实参):

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

3.2形式参数(形参):

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

上面Swap1和Swap2函数中的参数x,y,px,py都是形式参数
在main函数中传给Swap1的a,b和传给Swap2函数的&a,&b是实际参数
C语言学习入门之函数详解【上】_第1张图片
C语言学习入门之函数详解【上】_第2张图片

这里可以看到Swap1函数在调用的时候,x,y拥有自己的空间,同时拥有了和实参一模一样的内容。所以我们可以简单的认为:形参实例化之后其实相当于实参的一份临时拷贝

4.函数调用

4.1传值调用

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

4.2传址调用

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

4.3练习

  1. 写一个函数可以判断一个数是不是素数

素数:只能被1和自己整除的数

代码演示:

#define _CRT_SECURE_NO_WARNINGS
#include
#include
int is_prime(int  n)
{
	int j = 0;
	for (j = 2; j <= sqrt(n); j++)//函数要写头文件
	{
		if (n % j == 0)
			return 0;
	}
	return 1;

}
int main()
{
	int count = 0;
	int i = 0;
	for (i = 101; i <= 200; i+=2)//偶数不用考虑了
	{
		if (is_prime(i))
		{
			printf("%d ",i);
			count++;
		}
			
	}
	printf("\n共有%d个素数", count);
	return 0;
}

运行结果:
在这里插入图片描述

  1. 写一个函数判断一年是不是闰年

判断闰年的规则:能被4整除,并且不被100整除或能被400整除

代码演示:

#define _CRT_SECURE_NO_WARNINGS
#include
 int is_leap_year(int y)//是闰年返回1
{
	 if ((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0))
		 return 1;
	 else 
		 return 0;
}
int main()
{
	int year= 0;
	for (year = 1000;year<= 2000; year++)
	{
		if (is_leap_year(year))
		{
			printf("%d ",year);
			
		}		
	}
	return 0;
}

运行结果:
C语言学习入门之函数详解【上】_第3张图片

  1. 写一个函数,实现一个整形有序数组的二分查找

代码演示:

#define _CRT_SECURE_NO_WARNINGS
#include
int binary_search(int arr[], int k, int sz)
{
	int left = 0;
	int right = sz - 1;
	
	while(left<=right)
	{
		int mid = left + (right - left) / 2;
		if (arr[mid] < k)
		{
			left = mid + 1;
		}
		else if (arr[mid] > k)
		{
			right = mid - 1;
		}
		else
		{
			return mid;//找到了,返回下标mid
		}
	}
	return -1;//没有找到
 }
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;
}

因为数组下标从0开始,所以没有找到时不能返回0

运行结果:
在这里插入图片描述

再来看这段代码:
我们不传参数sz到函数binary_search中去,直接在函数中写:int sz = sizeof(arr) / sizeof(arr[0]);
结果是什么都找不到

#define _CRT_SECURE_NO_WARNINGS
#include
int binary_search(int arr[], int k)
{
	int sz = sizeof(arr) / sizeof(arr[0]);
	int left = 0;
	int right = sz - 1;
	while(left<=right)
	{
		int mid = left + (right - left) / 2;
		if (arr[mid] < k)
		{
			left = mid + 1;
		}
		else if (arr[mid] > k)
		{
			right = mid - 1;
		}
		else
		{
			return mid;
		}
	}
	return -1;//因为数组下标从0开始,所以这里不能返回0
 }
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int k = 7;
	int ret = binary_search(arr, k);
	if (ret == -1)
		printf("找不到\n");
	else
		printf("找到了,下标是:%d\n", ret);
	return 0;
}

运行结果:

C语言学习入门之函数详解【上】_第4张图片

分析: 数组传参时为了不浪费空间,只传过去数组的首地址,那这就是一个指针,就不需要一个很大的数组了,所以arr本质上是一个指针变量,所以binary_search函数访问和使用的数组,实际上还是主函数中的数组,因此,sizeof (arr)的值为4,sizeof arr[0]的值为4,得到sz=1,那么right=0,循环直接结束,自然找不到

  1. 写一个函数,每调用一次这个函数,就会将num的值增加1

代码演示:

#define _CRT_SECURE_NO_WARNINGS
#include
int Add(int *p)
{
	(*p)++;
 }
int main()
{
	int num = 0;
	Add(&num);
	printf("%d\n", num);//1
	Add(&num);
	printf("%d\n", num);//2
	return 0;
}

运行结果:
在这里插入图片描述

封面来自小王~( ̄▽ ̄~)~
下期预告:

函数的嵌套调用和链式访问
函数的声明和定义
函数递归

你可能感兴趣的:(c语言,c语言,visual,studio,code,开发语言,学习,经验分享)