目录
1.C语言中函数的分类
1)库函数
2)自定义函数
1.1 库函数的简单介绍
strcpy
char * strcpy ( char * destination, const char * source );
int main()
{
char arr1[] = "abcdef";
char arr2[20] = "xxxxxxx";
//将arr1的内容拷贝到arr2中
strcpy(arr2, arr1);
printf("%s", arr2);
return 0;
}
memset
void * memset ( void * ptr, int value, size_t num );
int main()
{
char arr[] = "hello world";
//设置内存的时候,以字节为单位
//将字符串arr的第二个位置后的3个字符替换成'Y',heYYY world
memset(arr + 2, 'Y', 3);
printf("%s", arr);
return 0;
}
注:但是库函数必须知道的一个秘密就是:使用库函数,必须包含 #include 对应的头文件。
自主学习库函数可参考
www.cplusplus.com
http://en.cppreference.com(英文版)
http://zh.cppreference.com(中文版)
1.2 自定义函数
自定义函数和库函数一样,有函数名,返回值类型和函数参数。
函数的组成
ret_type fun_name(para1, * )
{
statement;//语句项
}
ret_type 返回类型
fun_name 函数名
para1 函数参数
举栗子:
1.写一个函数可以交换俩个整形变量
void swap1(int x, int y)
{
int tmp = x;
x = y;
y = tmp;
}
void swap2(int *px, int *py)
{
int tmp = *px;
*px = *py;
*py = 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);
swap2(&a, &b);
printf("交换后a=%d,b=%d\n", a, b);
return 0;
}
注: 此代码 函数swap2可以正确执行得到结果 swap1是错误演示
只是因为,当实参传递给形参的时候,形参是实参的一份临时拷贝,对形参的修改不会影响实参
实参a和b,形参x和y使用的不是同一空间
2.函数的参数
2.1实际参数(实参)
实参,顾名思义,真实传给函数的参数叫做实参
实参可以是:常量,变量,表达式,函数等
在进行函数调用时,无论是何种类型的实参,都必须要有确定的值,以便把这些值传递给形参
2.2形式参数(形参)
形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效。
形参实例化后其实相当于实参的一份临时拷贝
3.函数的调用
3.1传值调用
函数的形参和实参分别占用不同的内存块,对形参的修改不会影响实参
3.2传址调用
传址调用是把函数外部创建变量的内存地址传递给函数参数的一种函数调用方式
函数内部可以直接操作函数外部的变量
举栗子:
1.写一个函数可以判断一个数是不是素数
#include<math.h>
int is_prime(int n)
{
int x = 0;
//2~sqrt(n)试除
for (x = 2; x <= sqrt(n); x++)
{
if (n % x == 0)
return 0;
}
//2~n-1试除
/*for (x = 2; x < n; x++)
{
if (n % x == 0)
return 0;
}*/
//if (n == x) 可有可无
return 1;
}
int main()
{
int i = 0;
for (i = 1; i <= 200; i++)
{
if (is_prime(i) == 1)
printf("%d ", i);
}
return 0;
}
2. 写一个函数,实现一个整形有序数组的二分查找
int binary_search(int *a,int n,int len)
{
int min = 0, max = len - 1;
while(min<=max)
{
int mid = min + (max - min) / 2;
if (n > a[mid])
min = mid + 1;
else if (n < a[mid])
max = mid - 1;
else
return mid;
}
return -1;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int len = sizeof(arr) / sizeof(arr[0]);
int x = 0;
scanf("%d", &x);
if (binary_search(arr,x,len) == -1)
printf("找不到\n");
else
printf("找到了\n");
return 0;
}
注: 数组在进行传参的时候,传递的不是整个数组,传递的是数组首元素的地址.所以在进行计算数组长度的时候,需要在main主函数体内进行计算,不能在自定义函数内计算
4.函数的嵌套调用和链式访问
4.1嵌套调用
函数可以嵌套调用,但是不能嵌套定义
4.2链式访问
把一个函数的返回值作为另一个函数的参数
举栗子:
printf( "%d", printf("%d" ,printf("%d" ,43))); //4321
1 2 43
printf函数的返回值是打印在屏幕上字符的个数
5.函数的声明和定义
5.1 函数的声明
1.声明函数名,参数,返回类型
2.函数的声明一般出现在函数使用之前,满足先声明后使用的原则
3.函数的声明一般要放在头文件中
自己定义的头文件用 " " 括
形参的名字可以省略
5.2 函数的定义
函数的定义是指函数的具体实现,交代函数的功能实现
6.函数的递归
6.1什么是递归?
程序调用自身的编程技巧(自己调用自己)
主要思考方式:大事化小
6.2递归的两个必要条件
1)存在限制条件,当满足这个限制条件的时候,递归便不再继续
2)每次递归调用之后越来越接近这个限制条件
6.2.1举栗子
1.编写函数不允许创建临时变量,求字符串的长度
//创建临时变量
/*int my_strlen(char* str)
{
int count = 0;
while (*str != '\0')
{
count++;
str++;
}
return count;
}*/
//不创建临时变量
int my_strlen(char* str)
{
if (*str != '\0')
return 1 + my_strlen(str + 1);
else
return 0;
}
int main()
{
char arr[] = "123456abcdef";
/*int len = strlen(arr);*/
int len = my_strlen(arr);
printf("%d", len);
return 0;
}
6.3递归与迭代
6.3.1 求n的阶乘 5 5*4*3*2*1
//常规思路
int fac1(int num)
{
if (num <= 1)
return num;
else
return num * fac1(num - 1);
}
//改进版
int fac2(int num)
{
int ret = 1;
for (int i = 1; i <= num; i++)
{
ret = ret * i;
}
return ret;
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = fac2(n);
printf("%d", ret);
return 0;
}
6.3.2 求第n个斐波那契数列
//改进版
int fib1(int num)
{
int a = 1, b = 1, c = 1;
while (num > 2)
{
c = a + b;
a = b;
b = c;
num--;
}
return c;
}
//常规思路
int fib2(int num)
{
if (num <= 2)
return 1;
else
return fib(num - 1) + fib(num - 2);
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = fib1(n);
printf("%d", ret);
return 0;
}