目录
函数是什么?
数学中我们常见到函数的概念。但是你了解C语言中的函数吗? 维基百科中对函数的定义:子程序 在计算机科学中,子程序(英语:Subroutine, procedure, function, routine, method, subprogram, callable unit),是一个大型程序中的某部分代码, 由一个或多个语句块组成。它负责完成某项特定任务,而且相较于其他代 码,具备相对的独立性。一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软件库。
C语言中函数的分类
1. 库函数 (C语言提供的库函数)2. 自定义函数(自己编写的函数)
库函数举例
strcpy()函数
功能:
拷贝字符串将源所指向的 C 字符串复制到目标所指向的数组中,包括终止空字符(并在该点停止)。将(a,b)将b拷贝到a中,包含b的\0,会覆盖掉a中的内容
memset()函数
功能:将 ptr 指向的内存块最开始的num个字节数设置为指定的值(解释为无符号字符),将ptr向后的num个字节,设置成value
自定义函数
ret_type fun_name(para1, * )
{ statement;//语句项 }
ret_type 返回类型
fun_name 函数名
para1 函数参数
此时函数并没有交换,这是因为:当实参传递给形参的时候,形参是实参的一份临时拷贝
,对形参的修改不会影响实参。
若想让形参对实参产生影响,我们应进行传地址调用,这样就能正确的实现我们想要的功能
函数的参数
实际参数(实参):
真实传给函数的参数,叫实参。 实参可以是:常量、变量、表达式、函数等。 无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。
形式参数(形参):
形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内 存单 元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效。
当实参传递给形参的时候,形参是实参的一份临时拷贝,对形参的修改不能改变实参
函数的调用:
传值调用
函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参。
这种情况就是进行传值调用,传值调用后进入函数的时候,会自动创建俩个不同的变量,在函数内对这俩个变量进行操作,当函数结束时,这俩个变量会被释放, 因此修改形参不会对实参造成任何影响
传址调用
传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。 这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操 作函数外部的变量。
此函数进行的是传址调用,传址调用后,当执行到函数,不会自动创建变量,而是将传进来变量的地址传给函数,此时会对原实参地址上的内容进行操作,此时对形参的修改会影响实参的值
由于是传址调用,但是当调用后如果在函数内部不给形参加*,当执行完函数后,我们发现实参没有任何变化,这是因为px和py都是int *类型,指向的是num1和num2的地址,若对px py进行操作,则是交换他们的地址,但是对他们地址里面的内容没有任何影响
例题
写一个函数可以判断一个数是不是闰年
#include <stdio.h>
int is_leap_year(int y)
{
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++)
{
//判断year是不是闰年
if (is_leap_year(year))
{
printf("%d ", year);
}
}
return 0;
}
写一个函数判断一年是不是素数
#include <stdio.h>
#include<math.h>
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 i = 0;
int count = 0;
for (i = 101; i <= 200; i+=2)
{
if (is_prime(i)==1)
{
printf("%d ", i);
count++;
}
}
printf("\ncount = %d\n", count);
return 0;
}
写一个函数,实现一个整形有序数组的二分查找。
#include <stdio.h>
int binary_search(int a[],int x,int y,int z)
{
while (x <= y)
{
int mid = x + (y - x) / 2;
if (z ==a[ mid])
{
return mid;
}
else if (z>a[ mid])
{
x = mid + 1;
}
else if (z < a[mid])
{
y = mid - 1;
}
}
if (x > y)
return -1;
}
int main()
{
int a[10] = { 1,2,3,4,5,6,7,8,9,10 };
int left = 0;
int right = sizeof(a) / sizeof(a[0]);
int k = 0;
scanf("%d", &k);
int h=binary_search(a, left, right,k);
if (h == -1)
printf("没找到");
else
printf("找到了,下表是:%d", h);
return 0;
}
当我们在函数内部计算数组大小时,此时数组大小会变为1,这是因为数组在传参时传的是首元素的地址,函数形参的int a[]看似是个数组,其实是指针,接受的是首元素的地址
因此int y = sizeof(a) / sizeof(a[0])
sizeof(a)实际是算指针变量的大小,sizeof a[0]是首元素大小,指针大小为4或8,a[0]为4,所以最终结果为1
这是一个错误的示范
数组传参实际上传递的是数组首元素的地址
而不是整个数组
所以在函数内部计算一个函数参数部分的数组的元素个数是不靠谱的
int binary_search(int a[])//形参a看上去是数组,本质是指针变量
布尔类型
bool:用来表示真假的变量
如 bool flag
flag只有俩种情况return true或return false
头文件#include<stdbool.h>
嵌套调用
#include <stdio.h>
void new_line()
{
printf("hehe\n");
}
void three_line()
{
int i = 0;
for (i = 0; i < 3; i++)
{
new_line();
}
}
int main()
{
three_line();
return 0;
}
函数可以嵌套调用,但不能嵌套定义
若嵌套定义,则函数会报错
链式访问
一个函数的返回值,作为其它函数的参数
函数返回值
函数不写返回值,默认返回类型是int,当用int类型的函数没有返回值时,在一些编译器上程序会默认返回最后一条语句的返回值
不推荐这种写法
100传过去了,但是没有使用 ,若想拒绝这个100,加void即可,此时编译器会产生警报,但程序仍会运行成功