C语言中函数的分类:库函数、自定义函数
2.库函数 2.1 strcpy#include#include int main() { char arr1[] = "bit"; char arr2[] = "***********"; strcpy(arr2, arr1); //把arr1的内容拷贝到arr2中 printf("%sn", arr2); return 0; }
输出结果:bit
2.2 memset#include#include int main() { char arr[] = "hello world"; memset(arr, '*', 5); //把数组中,前5个字符设置为* printf("%sn", arr); return 0; }
输出结果:***** world
3.自定义函数(1)比较两个数的大小
#includeint getmax(int x, int y) { if (x > y) return x; else return y; } int main() { int a = 10; int b = 8; int max = getmax(a, b); printf("%dn", max); return max; }
(2)写一个函数可以交换两个整型变量的内容
#include4.函数参数#include void swap1(int x, int y) { int temp = 0; temp = x; x = y; y = temp; } void swap2(int *pa, int *pb) { int tmp = 0; tmp = *pa; *pa = *pb; *pb = tmp; } int main() { int a = 10; int b = 20; printf("a=%d b=%dn", a, b); // swap1(a, b); //这种方法不可以 //因为a,b 和x,y在内存中的地址不同,x,y的值会发生互换,a,b的值不会发生互换 swap2(&a, &b); // 传递地址 printf("a=%d b=%dn", a, b); }
- 实参:真实传给函数的参数叫实参,可是常量、变量、表达式等。无论实参是何种类型的变量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。
- 形参:接收实参,形参是自定义函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效。形式参数是形式上的参数,没有实际的变量空间,只有被调用时才会被实例化,调用完销毁。
- 传值调用:函数的形参和实参分别占用不同内存块,对形参的修改不会影响实参。
- 传址调用:把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。这种传参方式可以让函数外边的变量建立起真正的联系,也就是函数内部可以直接操作函数外部的变量。
- 写作规范:先在调用函数中写怎么用,再写函数如何进行实现。
练习1:写一个函数判断一个数是不是素数。
#include// 函数定义 int is_prime(int n){ int j = 0; for(j=2;j 练习2:写一个函数判断一年是不是闰年。
#include// 函数定义 int is_leap_year(int y){ if((y%4==0&&y%100!=0)||(y%400==0)) return 1; } int main() { int year = 0; for(year = 1000;year<=2000;year++) { // 判断year是否为闰年 if(1==is_leap_year(year)) printf("%dt",year); } return 0; } 练习3:写一个函数,实现一个整形有序数组的二分查找。
// 注意数组传参,传递的仅为第一个原元素的地址
// 必须传递数组元素的个数#include//二分查找 //在一个有序数组中查找具体的某个数 //如果找到返回数的下标,找不到返回-1 //本质上arr接收的为指针 int binary_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) 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(int); int ret = binary_search(arr,k,sz); // 注意数组传参,传递的仅为第一个原元素的地址 // 必须传递数组元素的个数 if(ret == -1) printf("找不到指定的数组n"); else printf("找到了,下标是:%dn",ret); return 0; } 练习4:写一个函数,每调用一次这个函数,就会将num的值加1
#include6.函数的嵌套调用和链式访问 6.1函数嵌套调用void Add(int *p){ (*p)++; } int main() { int num = 0; Add(&num); printf("num = %dn",num); //1 Add(&num); printf("num = %dn",num); //2 Add(&num); printf("num = %dn",num); //3 return 0; } 各自定义函数之间可以互相调用
6.2 链式访问把一个函数的返回值作为另外一个函数的参数。
7.函数的声明和定义
- 告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在,无关紧要。
- 函数的声明一般出现在函数的使用之前,要满足先声明后使用。
- 函数的声明一般要放在头文件中。
用法:
在源文件中写.c文件,在头文件中写.h文件
#ifndef LED_H //注意要大写,被引用的****.h为小写 #define LED_H * * * * #endif引用自己写的函数用"***.h",引用下载或自带的库函数用<***.h>
8.函数递归
- 函数调用自身的编程技巧称为递归(recursion),程序自己调用自己。递归作为一种算法在程序设计语言中广泛应用。一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的主要思考方式在于:把大事化小。
- 递归的两个必要条件:
- 存在限制条件,当满足这个限制条件的时候,递归便不再继续。防止栈溢出(递归常见的错误,stack overflow),
- 每次递归调用之后越来越接近这个限制条件。
练习1:接收一个整型值(无符号),按照顺序打印它的每一位。例如输入1234,输出1 2 3 4
#includevoid print(int n) { if (n > 9) { print(n / 10); } printf("%d ", n % 10); } int main() { unsigned int num = 0; scanf("%d", &num); // 递归 print(num); return 0; } 练习2:编写函数不允许创建临时变量,求字符串的长度
#include#include int my_strlen(char *str) { int count = 0; while (*str != ' ') { count++; str++; } return count; } int main() { char arr[] = "hello"; int len = my_strlen(arr); // arr是数组,数组传参,传过去的不是整个数组,而是第一个元素的地址 printf("%dn", len); return 0; }



