函数
用于解决特定问题的代码
分类
- 库函数
- 自定义函数
库函数
为提高程序效率,减少繁琐重复的代码
自定义函数
返回类型 函数名(形参)
{
语句项;
}
函数的声明和定义
声明:交代函数的名称,形参,返回类型。
定义:交代函数的功能。
用函数比较两个数的大小
#include<stdio.h>
int Max(int x, int y)
{
if (x > y)
return x;
else
return y;
}
int main()
{
int a = 10;
int b = 20;
int max = Max(a, b);
printf("max=%d\n", max);
return 0;
}
函数的两种调用方式
- 传值调用常用于不改变实参
- 传址调用常用于改变实参
传值VS传址
利用函数交换两个数植
传值调用
当实参传递给形参时,形参相当于实参的一份临时拷贝
对形参的修改不影响实参
#include<stdio.h>
void Swap(int x, int y)
{
int i = x;
x = y;
y = i;
}
int main()
{
int a = 10;
int b = 20;
printf("a=%d b=%d\n", a, b);
Swap(a, b);
printf("a=%d b=%d\n", a, b);
return 0;
}
传址调用
#include<stdio.h>
void Swap(int*pa, int*pb)
{
int i = *pa;
*pa = *pb;
*pb = i;
}
int main()
{
int a = 10;
int b = 20;
printf("a=%d b=%d\n", a, b);
Swap(&a, &b);
printf("a=%d b=%d\n", a, b);
return 0;
}
总结:
函数的参数:实参,形参。
实参:真实传给函数的参数;形参:自定义函数名括号内的变量,形式上的参数。
传值:对形参的修改不影响实参。
传址:将变量的地址传给函数,能够建立函数与外部变量真正的联系。
在有序数组中查找某一数字
#include<stdio.h>
int Search(int arr[], int k)
{
int left = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
int right = sz - 1;
while (left <= right)
{
int mid = (left + right) / 2;
if (arr[mid] < k)
left = mid + 1;
else if (arr[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 k = 7;
int ret = Search(arr, k);
if (ret == -1)
{
printf("没找到");
}
else
{
printf("找到啦,下标为%d", ret);
}
return 0;
}
易错点:数组arr是以首元素地址的形式被传递过去的,是以指针的形式被接收的。所以Int sz 的值并不是数组元素的个数。
#include<stdio.h>
int Search(int arr[], int k, int sz)
{
int left = 0;
int right = sz - 1;
while (left <= right)
{
int mid = (left + right) / 2;
if (arr[mid] < k)
left = mid + 1;
else if (arr[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 k = 7;
int sz = sizeof(arr) / sizeof(arr[0]);
int ret = Search(arr, k, sz);
if (ret == -1)
{
printf("没找到");
}
else
{
printf("找到啦,下标为%d", ret);
}
return 0;
}
函数的嵌套调用和链式访问
嵌套调用
函数之间互相调用
函数可以嵌套调用,但是不能嵌套定义
链式访问
把一个函数的返回值作为另一个函数的参数
#include<stdio.h>
int main()
{
printf("%d", printf("%d", printf("%d", 43)));
//printf函数的返回值
//打印的字符个数,作为函数的返回值
//printf("%d", printf("%d", 2));
//printf("%d", 1);
// 43 2 1
return 0;
}
函数递归
简称:函数调用自身。主要思想,把大事化小。
两个条件
1,存在限制条件。
2,每次递归之后,越来越接近限制条件。
题目:接受一个整型无符号数,按顺序打印每一位。
使用递归
分析
第一步 Print(678)
第二步 Print(67) 8
第三步 Print(6) 7 8
#include<stdio.h>
void Print(int n)
{
if (n > 9)
{
Print(n / 10);
}
printf("%d ", n % 10);
}
int main()
{
unsigned int i = 0;
scanf("%d", &i);
Print(i);
return 0;
}
计算一个数的每位之和
分析
Digitsum(123)
Digitsum(12)+3
Digit(1)+2+3
#include<stdio.h>
int Digitsum(int i)
{
if (i > 9)
{
return Digitsum(i / 10) + i % 10;
}
return i;
}
int main()
{
int i = 0;
scanf("%d", &i);
int sum = Digitsum(i);
printf("%d\n", sum);
return 0;
}
实现n的k次方
#include<stdio.h>
double Pow(int n, int k)
{
if (k > 0)
{
return n * Pow(n, k - 1);
}
else if (k == 0)
{
return 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;
}
编写代码求字符串长度
方法一
利用库函数 strlen() #include< string >(头文件)
#include<stdio.h>
#include<string>
int main()
{
char arr[] = "crush";
int len = strlen(arr);
printf("%d\n", len);
return 0;
}
方法二
创建临时变量
#include<stdio.h>
int Count_lenght(char*arr)
{
int count = 0;
while (*arr != '\0')
{
count++;
arr++;
}
return count;
}
int main()
{
char arr[] = "crush";
int len = Count_lenght(arr);
printf("%d\n", len);
return 0;
}
方法三
函数递归
#include<stdio.h>
int Count_lenght(char* arr)
{
if (*arr != '\0')
return 1 + Count_lenght(arr + 1);
else
return 0;
}
int main()
{
char arr[] = "crush";
int len = Count_lenght(arr);
printf("%d\n", len);
return 0;
}
递归与迭代(循环)
求n的阶乘
递归
#include<stdio.h>
int Fac(int i)
{
if (i < 2)
return 1;
else
return i * Fac(i - 1);
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fac(n);
printf("%d\n", ret);
return 0;
}
迭代(循环)
#include<stdio.h>
int Fac(int n)
{
int i = 0;
int ret = 1;
for (i = 1; i <= n; i++)
{
ret *= i;
}
return ret;
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fac(n);
printf("%d\n", ret);
return 0;
}
求第n个斐波那契数
函数递归
#include<stdio.h>
int Fb(int i)
{
if (i > 2)
return Fb(i - 1) + Fb(i - 2);
else
return 1;
}
int main()
{
int n = 0;
int ret = 0;
scanf("%d", &n);
ret = Fb(n);
printf("%d", ret);
return 0;
}
该函数的缺点是重复多次计算,不适用于计算较大的斐波那契数。
改进如下
迭代(循环)
#include<stdio.h>
int Fb(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 = Fb(n);
printf("ret = %d\n", ret);
return 0;
}
字符串逆序
迭代
#include<stdio.h>
int my_strlen(char* str)
{
if ('\0' != *str)
{
return 1 + my_strlen(str + 1);
}
return 0;
}
void Reverse(char ch[])
{
int left = 0;
int right = my_strlen(ch) - 1;
while (left < right)
{
char tmp = ch[left];
ch[left] = ch[right];
ch[right] = tmp;
left++;
right--;
}
}
int main()
{
char ch[] = "crush";
printf("%s\n", ch);
Reverse(ch);
printf("%s\n", ch);
return 0;
}
递归 1
#include<stdio.h>
int my_strlen(char* str)
{
if ('\0' != *str)
{
return 1 + my_strlen(str + 1);
}
return 0;
}
void Reverse(char* str)
{
//1.先保存第一个字符
char tmp = *str;
int len = my_strlen(str);
//2.将最后一个字符存放在第一个字符的位置
*str = *(str + len - 1);
//3.将最后一个字符设置为\0,以便字符串长度的计算
*(str + len - 1) = '\0';
//4.进行中间字符串的逆序(除去第一个和最后一个字符)
if (my_strlen(str + 1) > 1)
{
Reverse(str + 1);
}
//5.将第一个字符存放在最后一个字符的位置
*(str + len - 1) = tmp;
}
int main()
{
char ch[] = "crush";
printf("%s\n", ch);
Reverse(ch);
printf("%s\n", ch);
return 0;
}
递归 2
#include<stdio.h>
int my_strlen(char* str)
{
if ('\0' != *str)
{
return 1 + my_strlen(str + 1);
}
return 0;
}
void Reverse(char ch[], int left, int right)
{
if (left < right)
{
char tmp = ch[left];
ch[left] = ch[right];
ch[right] = tmp;
Reverse(ch, left + 1, right - 1);
}
}
int main()
{
char ch[] = "crush";
printf("%s\n", ch);
int left = 0;
int right = my_strlen(ch) - 1;
Reverse(ch,left,right);
printf("%s\n", ch);
return 0;
}
总结,函数递归与迭代的选择。
只要不出现错误,哪个都行。