本章主要掌握函数的基本使用和递归
1.函数是什么
是一个大型程序中的某部分代码,由一个或多个语句块组成。它负责完成某项特定任务,而且相较于其他代码,具备相对的独立性。
一般会有输入参数并由返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软件库。
2.库函数
www.cplusplus.com
分类:(1.)IO函数 printf scanf getchar putchar
(2.)字符串操作函数 strcmp strlen
(3.)字符操作函数 toupper
(4.)内存操作函数 memcpy memcmp memset
(5.)时间/日期函数 time
(6.)数学函数 sqrt pow
(7.)其他库函数
strcpy - 把arr2这个字符串复制给arr1
int main()
{
char arr1[20] = { 0 };
char arr2[] = "hello bit";
strcpy(arr1, arr2);
printf("%s", arr1);//打印arr1这个字符串 %s - 以字符串的格式打印
return 0;
}
memset - 内存设置 -- 把“hello”换成5个x
int main()
{
char arr[] = "hello bit";
memset(arr, 'x', 5);
printf("%s\n", arr);
return 0;
}
3.自定义函数
- - 和库函数一样,有函数名,返回值类型和函数参数,但是不一样的是,这些都是我们自己来设计。
4.函数参数
实际参数
(实参):真实传给函数的参数,叫实参。实参可以是:常量,变量,表达式,函数等。无论实参是何种类型的量,在进行函数调用时,他们都必须有确定的值,以便把这些值传送给形参。
形式参数:
形式参数的指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效。
形参实例化之后其实相当于实参的一份临时拷贝。
5.函数调用
传值调用:
函数的形参和实参分别占有不同的内存块,对形参的修改不会影响实参
传址调用:
传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式
这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操作函数外部的变量
void Add(int* p)
{
(*p)++;
}
int main()
{
int num = 0;
Add(&num);
printf("%d\n", num);
Add(&num);
printf("%d\n", num);
Add(&num);
printf("%d\n", num);
return 0;
}
6.函数的嵌套调用和链式访问
函数和函数之间可以有机的组合的。
链式访问:把一个函数的返回值作为另外一个函数的参数。
//函数的嵌套使用和链式访问
//void test3()
//{
// printf("hehe\n");
//}
//
//int test2()
//{
// test3();
// return 0;
//}
//
//int main()
//{
// test2();
// return 0;
//}
#include<string.h>
int main()
{
//int len = strlen("abc");
//printf("%d\n", len);
链式访问
//printf("%d\n", strlen("abc"));
//char arr1[20] = { 0 };
//char arr2[] = "bit";
//strcpy(arr1, arr2);
//printf("%s\n", strcpy(arr1, arr2));
printf("%d", printf("%d", printf("%d",43)));
return 0;
}
7.函数的声明和定义
函数声明:
1.告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在,五关键要
2.函数的声明一般出现在函数的使用之前。要满足先声明后使用。
3.函数的声明一般要放在头文件中的。
函数的定义:
函数的定义是指函数的具体实现,交代函数的功能实现。
8.函数递归
什么是递归?
程序调用自身的编程技巧称为递归(recursion。递归作为一种算法在程序设计语言中广泛应用。一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,他通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需要少量的程序就可描述出解题过程所需要的多次重复计算,大大减少了程序的代码量。递归的主要思考方式在于:把大事化小。
递归的两个必要条件
存在限制条件,当满足这个限制条件的时候,递归便不再继续。
每次递归调用之后越来越接近这个限制条件。
- unsigned int(无符号常数) %u无符号整型
栈溢出
栈溢出
写递归代码的时候:
1.不能死递归,要有跳出条件,每次递归逼近跳出条件
2.递归层次不能太深
www,stackoverflow.com
strlen的模拟实现用递归
int my_strlen(char* str)
{
if (*str != '\0')
return 1 + my_strlen(str + 1);
else
return 0;
}
int main()
{
char arr[] = "bit";
//['b']['i']['t']['\0']
//
//模拟实现一个strlen函数
printf("%d\n", my_strlen(arr));
return 0;
}
递归与迭代
迭代就是重复的做一件事情
n!
int Fac(int n)
{
if (n <= 1)
return 1;
else
return n * Fac(n - 1);
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fac(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;
scanf("%d", &n);
int ret = Fib(n);
printf("%d\n", ret);
return 0;
}
青蛙跳台阶
//青蛙跳台阶,每次只能跳上一个或两个台阶时,假设有n级台阶,有多少种方法
int jump(int n)
{
if (n == 1)
return 1;
else if (n == 2)
return 2;
else
return jump(n - 1) + jump(n - 2);
}
int main()
{
int n;
printf("请输入台阶数:");
scanf("%d", & n);
printf("青蛙跳上%d级台阶的方法数为:%d\n", n, jump(n));
return 0;
}
Ⅰ-在while(条件表达式)循环体,条件表达式的执行次数总是比循环体的执行次数多一次。
int my_strlen(char* str)
{
int count = 0;
while (*str != '\0')
{
count++;
str++;
}
return count;
}
void reverse_string(char* str)
{
char tmp = *str;//1
int len = my_strlen(str);
*str = *(str + len - 1);//2
*(str + len - 1) = '\0';//3
//判断条件
if (my_strlen(str + 1) >= 2)
{
reverse_string(str + 1);//4
}
*(str + len - 1) = tmp;//5
}
int main()
{
char arr[] = "abcdef";
reverse_string(arr);//数组名arr是数组arr首元素的地址
printf("%s\n", arr);//fedcba
return 0;
}
int Digitsum(int n)
{
if (n > 9)
{
return Digitsum(n / 10) + n % 10;
}
else
{
return n;
}
}
int main()
{
int num = 1729;
int sum = Digitsum(num);
printf("%d\n", sum);
return 0;
}
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;
}