函数
本章目标:
- 函数是什么
- 库函数
- 自定义函数
- 函数参数
- 函数调用
- 函数的嵌套调用和链式访问
- 函数的声明和定义
- 函数递归
C语言中函数的分类
- 库函数
- 自定义函数
C语言常用的库函数都有:
-
IO函数
-
字符串操作函数
-
字符操作函数
-
内存操作函数
-
时间/日期函数
-
数学函数
-
其他库函数
在C语言和C++的学习中,参考文档是非常重要的
在文档中: -
如果看到NULL --则表示的是空指针
-
如果看到null则表示的是\0
-
如果看到NUL则也表示的是\0
字符串拷贝函数
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[100] = { 0 };
char arr2[] = "hello world";
strcpy(arr1, arr2);
printf("%s", arr1);
return 0;
}
//拷贝的内容中是包括有\0的.
memset—设置内存块的函数
#include<stdio.h>
int main()
{
char arr1[] = "hello world";
memset(arr1, 'x', 5);
printf("%s", arr1);
return 0;
}
写一个函数找出两个数中的较大数
#include<stdio.h>
int MAX(int x, int y)
{
return x > y ? x : y;
}
int main()
{
int a = 0;
int b = 0;
int c = 0;
(void)scanf("%d %d", &a, &b);
c = MAX(a, b);
printf("%d", c);
return 0;
}
交换两个数的函数
#include<stdio.h>
void Swap(int* x, int* y)
{
int temp = *x;
*x = *y;
*y = temp;
}
int main()
{
int a = 0;
int b = 0;
(void)scanf("%d %d", &a, &b);
Swap(&a, &b);
printf("%d %d", a, b);
return 0;
}
函数的参数
实际参数(实参)
真实传给函数的参数,叫实参,实参可以是:常量,变量,表达式,函数等。无论实参是何种类型的量,在进行函数调用时,他们都必须有确定的值,以便把这些值穿给形参
形式参数(形参)
形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用过程中才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了,因此形式参数只有在函数中才有作用
所以成形式参数是实际参数的一份临时拷贝。
函数的调用
- 传值调用
- 传址调用
传值调用
函数的形参和实参分别占有不同的内存块
传址调用
- 传址调用时把函数外部创建变量的内存地址传递给函数参数的一种调用方式
- 这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操作函数外部的变量。
写一个函数,判断一个数是不是素数
#include<stdio.h>
int is_prime(int i)
{
int j = 0;
for (j = 2; j < i; j++)
{
if (i % j == 0)
return 0;
}
return 1;
}
int main()
{
int n = 0;
(void)scanf("%d", &n);
if (is_prime(n) == 1)
{
printf("是素数\n");
}
else
{
printf("不是素数\n");
}
return 0;
}
写一个函数,判断一年是不是闰年
#include<stdio.h>
int is_leapyear(int i)
{
if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0)
return 1;
else
return 0;
}
int main()
{
int n = 0;
(void)scanf("%d", &n);
if (is_leapyear(n) == 1)
{
printf("是闰年\n");
}
else
{
printf("不是闰年\n");
}
return 0;
}
用函数实现二分查找
#include<stdio.h>
void BinarySearch(int arr[], int sz)
{
int key = 7;
int left = 0;
int right = sz - 1;
while (left <= right)
{
int mid = left + (right - left) / 2;
if (arr[mid] < key)
left = mid + 1;
else if (arr[mid] > key)
right = mid - 1;
else
{
printf("找到了,下标是:%d", mid);
break;
}
}
if (left > right)
printf("找不到\n");
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int left = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
BinarySearch(arr, sz);
return 0;
}
函数的嵌套调用和链式访问
嵌套调用
#include<stdio.h>
void new_line()
{
printf("hehe\n");
}
void three_line()
{
for (int i = 0; i < 3; i++)
{
new_line();
}
}
int main()
{
three_line();
return 0;
}
链式访问
把一个函数的返回值作为另一个函数的参数
#include<stdio.h>
int main()
{
int len = strlen("abcdef");
printf("%d\n", len);
printf("%d\n", strlen("abcdef"));
return 0;
}
//把一个函数的返回值作为另一个函数的参数
#include<stdio.h>
int main()
{
printf("%d", printf("%d", printf("%d", 43)));
return 0;
}
//打印的结果为4 3 2 1
//printf函数的返回值是字符的个数
函数的声明和定义
#include<stdio.h>
int main()
{
int a = 10;
int b = 20;
int Add(int x, int y); //称为函数的声明
int c = Add(a, b);
printf("%d", c);
return 0;
}
//函数定义
int Add(int x, int y)
{
return x + y;
}
函数的声明
- 告诉编译器有一个函数叫什么,参数是什么,返回值类型是什么,但是具体是不是存在,无关紧要
- 函数的声明一般出现在函数的使用之前,要满足先声明后使用
- 函数的声明一般要放在头文件中。
函数定义
函数的定义是指函数的具体实现,交代函数的功能实现
函数递归
递归的主要思考方式:把大事化小
#include<stdio.h>
int main()
{
printf("hehe\n");
main();
}
递归的两个必要条件
- 存在限制条件,当满足这个条件的时候,递归便不再继续
- 每次递归调用之后越来月接近这个限制条件
接收一个整形值(无符号),按照顺序打印他的每一位
例如输入1234 打印: 1 2 3 4
#include<stdio.h>
void print(int n)
{
if (n > 9)
print(n / 10);
printf("%d ", n % 10);
}
int main()
{
unsigned int n = 0;
(void)scanf("%u", &n);
print(n);
return 0;
}
模拟实现求字符串长度
#include<stdio.h>
int my_strlen(const char* str)
{
int count = 0;
while(*str != '\0')
{
count++;
str++;
}
return count;
}
int main()
{
int len = my_strlen("abc");
printf("%d", len);
return 0;
}
编写函数不允许使用临时变量,求字符串的长度
#include<stdio.h>
int my_strlen(const char* str)
{
if (*str == '\0')
return 0;
else
return 1 + my_strlen(str + 1);
}
int main()
{
int len = my_strlen("abcdef");
printf("%d\n", len);
return 0;
}
递归与迭代
求n的阶乘(利用递归来求)
int fac(int n)
{
if (n <= 1)
return 1;
else
return n * fac(n - 1);
}
#include<stdio.h>
int main()
{
int n = 0;
int c = 0;
(void)scanf("%d", &n);
c = fac(n);
printf("%d\n", c);
return 0;
}
求第n个斐波那契数
#include<stdio.h>
int fib(int n)
{
if (n <= 2)
return 1;
else
return fib(n - 1) + fib(n - 2);
}
int main()
{
int n = 0;
int c = 0;
(void)scanf("%d", &n);
c=fib(n);
printf("%d\n", c);
return 0;
}
非递归写斐波那契数
#include<stdio.h>
int main()
{
int a = 1;
int b = 1;
int c = 1;
int n = 0;
(void)scanf("%d", &n);
while (n >= 3)
{
c = a + b;
a = b;
b = c;
n--;
}
printf("%d", c);
return 0;
}
//可能会溢出
//所以非递归速度是十分快的,但是可能会出现一些问题
下来自行研究
- 青蛙跳台阶问题
- 汉诺塔问题