- 函数的分类
- 函数的参数
- 函数的调用
- 函数的声明和定义
- 函数的递归
- 函数的分类
库函数
自定义函数
1.1 库函数
C语言的基础库中所提供的函数,方便进行软件开发
在使用库函数的时候有,必须包含相应的头文件 #include
可以在www.cplusplus.com进行查询比如:
#include<stdio.h> #include<string.h> #include<windows.h> //编写代码,演示多个字符从两端移动,向中间汇聚 void main() { char str1[] = "welcome to world!"; char str2[] = "#################"; int n = strlen(str1); for (int i = 0; i < n / 2 + 1; i++) { str2[i] = str1[i]; str2[n - i - 1] = str1[n - i - 1]; printf("%s\n", str2); Sleep(1000); //隔1000ms执行一次 system("cls"); //命令行窗口清屏,第二次的输出结果会覆盖第一次的,有动画效果 } return 0; } //在上述代码中,printf(); strlen(); Sleep(); system("pause");都是库函数。
1.2 自定义函数
自定义函数与库函数一样,有函数名、返回值类型以及函数参数,可以进行设计以完成相应功能
返回值类型 函数名(函数参数)
{
语句;
}
比如:#include<stdio.h> //定义一个查找数组中的最大值的函数 int findMax(int arr[], int n) //返回值类型是int,函数名findMax,参数是数组和整型 { int maxindex = 0; int i; for (i = 0; i < n; i++) { if (arr[i] > arr[maxindex]) maxindex = i; } return maxindex; //返回了数组中最大值的索引位置 } void main() { int arr[] = { -123,-3344,-4,-1,-54,-32,-44,-22,-666,-73 }; //数组是无序排列的 int n = sizeof(arr) / sizeof(arr[0]); int index = findMax(arr, n); printf("最大值在数组中的第%d索引处\n",index); printf("最大值是%d\n", arr[index]); return 0; }
- 函数的参数
实际参数:
真实传给函数的参数叫实参。实参可以是常量、变量、表达式、函数等。在进行函数调用时,实参必须有确定的值,以便讲这些值传给形参。形式参数:
函数名后括号中的变量就是形参。形参只有在函数被调用的过程中才分配内存单元,在函数调用完成之后就自动销毁了,也就是说形参只在函数中有效。
比如:#include<stdio.h> //定义了一个函数,本意是想互换值,但此代码并未实现功能 void swap(int a, int b) { int temp = a; a = b; b = temp; } void main() { int a = 100; int b = 200; printf("交换之前:a = %d; b = %d\n", a, b); swap(a, b); printf("交换之后:a = %d; b = %d\n", a, b); //运行发现,a和b的值并没有发生变化,并没有互相交换 return 0; }
在主函数内调用自定义函数时,swap的形式参数虽然发生了变化,但是形式参数的改变不会影响实际参数,形参可以理解成实参的拷贝,在函数执行完后,形参就无效了,
//对上述代码修改如下,交换功能就被实现了: void swap(int *a, int *b) { int temp = *a; *a = *b; *b = temp; return 0; } void main() { int a = 100; int b = 200; printf("交换之前:a = %d; b = %d\n", a, b); swap(&a, &b); printf("交换之后:a = %d; b = %d\n", a, b); return 0; } //这里面涉及到指针,将在后续更新中进行解释...
- 函数的调用
传值调用:函数的形参和实参分别占有不同的内存块,对形参的修改不会影响实参
传址调用:传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用方式,这种传参方式可以让函数和函数外边的变量建立起真正的联系也就是函数内部可以直接操作函数外部的变量函数的嵌套调用和链式访问
函数和函数之间是可以有机组合的。
链式访问就是把一个函数的返回值作为另一个函数的参数。
例如:int fun1(int a, int b) { return a+b; } int fun2(int a, int b) { return fun1(a,b)*fun1(a,b); } void main() { int a = 1; int b = 2; int num; num = fun2(a, b); // num = 9 = (1 + 2) * (1 + 2); }
- 函数的声明和定义
4.1 函数声明
告诉编译器有这么一个函数(函数名、参数、返回类型)
函数的声明一般出现在函数的使用之前,要满足先声明后使用
函数的声明一般是要放在头文件中
4.2 函数的定义
函数的定义是指函数的具体实现,交代函数的功能实现例如:
//新增一个头文件test.h,放置函数的声明 #ifndef _TEST_H_ //预处理语句,if not define 如果没有定义过_TEST_H_则为真继续执行 //或者用#pragma once(后面就不用#endif了) #define _TEST_H_ //函数声明 int Add(int x, int y); #endif // _TEST_H_ //文件test.c,放置函数的实现 //函数Add的实现 # include"test.h" int Add(int a, int b) { return a+b; }
- 函数的递归
递归:程序调用自身的编程技巧成为递归。使用递归可以将需要多次重复计算的内容用少 量程序实现,大大减少了代码量
递归的必要条件:
需要有结束条件,当满足该条件时,递归结束
递归调用之后应该越来越接近结束条件
例如://接收一个无符号整型数,按照顺序打印它的每一位 void NumPrint(size_t n) { if (n > 9) NumPrint(n / 10); printf("%d\n", n % 10); } void main() { size_t n; printf("请输入一个整数:\n"); scanf("%d", &n); NumPrint(n); }
》许多问题是以递归地形式进行解释的,这是因为递归形成更加清晰;
》递归实现效率往往低于迭代实现效率,但是代码简洁;
》当问题比较复杂,迭代法难以描述时,考虑递归实现,其代码的简洁性性可以补偿运行时的开销。