接下来让我们一起学习新的内容——函数。分两次给来大家分享。
一 函数是什么?
维基百科对函数的定义:子程序
(1)在计算机科学中,子程序是一个大型程序中的某部分代码,由一个或多个语句块组成,他负责完成某项某项特定任务,而且相较于其他代码,具备相对的独立性。
(2)一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软件库。
二 C语言中函数的分类
①库函数:C语言中本身提供的函数,例如:printf()函数
②自义定函数:自己定义的函数
2.1 库函数
C语言中本身提供的函数。例如:printf()函数
库函数的作用是提高效率,方便程序员进行软件开发。
C语言常用的库函数有:IO函数、字符串操作函数、字符操作函数、内存操作函数、时间\日期函数、数学函数、其他库函数
注意:
(1)使用库函数,必须包含#include对应的头文件
(2)对于库函数,会查即可
https://en.cppreference.com/w/(英文版)
https://zh.cppreference.com/w/%E9%A6%96%E9%A1%B5 (中文版)
2.2 自义定函数
如果库函数能干所有事情,那还要程序员干什么?所以自义定函数是非常重要的。
自义定函数和库函数一样,有函数名、返回值类型和函数参数,不一样的是这些需要我们自己来设计。
函数的组成:
关于函数的理解,友友们可以看初识C语言(2)这篇文章,里面有详细的介绍,友友们可以看一下。给大家举两个例子更深理解一下函数:
2.2.1 写一个函数可以找出两个整数的最大值
代码展示:
1. #include <stdio.h> 2. int get_max(int x, int y) 3. { 4. int z = 0; 5. z = (x > y ? x : y); 6. return z; 7. } 8. int main() 9. { 10. int a = 0; 11. int b = 0; 12. scanf("%d,%d", &a, &b); 13. int m = get_max(a, b); 14. printf("%d", m); 15. return 0; 16. }
2.2.2 写一个函数,可以交换两个整型变量的内容
swap的中文解释有交换的意思
代码1展示:
1. #include <stdio.h> 2. void Swap(int* pa , int* pb) 3. { 4. int z = 0; 5. z = *pa; 6. *pa = *pb; 7. *pb = z; 8. } 9. int main() 10. { 11. int a = 0; 12. int b = 0; 13. scanf("%d %d", &a, &b); 14. Swap(&a, &b); 15. printf("%d %d", a, b); 16. return 0; 17. }
代码2展示:
1. #include <stdio.h> 2. void test(int arr[]) 3. { 4. int a = 0; 5. a = arr[0]; 6. arr[0] = arr[1]; 7. arr[1] = a; 8. } 9. int main() 10. { 11. int arr[2] = { 0 }; 12. arr[0] = 10; 13. arr[1] = 20; 14. test(arr); 15. printf("%d %d", arr[0], arr[1]); 16. return 0; 17. }
下面我们来分析下面这个代码错误的原因。代码展示:
1. #include <stdio.h> 2. void Swap(int x, int y) 3. { 4. int z = 0; 5. z = x; 6. x = y; 7. y = z; 8. } 9. int main() 10. { 11. int a = 0; 12. int b = 0; 13. scanf("%d %d", &a, &b); 14. Swap(a, b); 15. printf("%d %d", a, b); 16. return 0; 17. }
错误分析:当函数调用的时候,实参传给形参,形参只是实参的一份临时拷贝,所以对形参的改变不会影响实参。(这个比较重要)(解决的办法是把x,y与a,b产生联系,用指针)
三 函数的参数
3.1 实际参数(实参)
真实传给函数的参数,叫实际参数(实参),实参可以是:常量、变量、表达式、函数等。无论实参是何种表达式的量,在进行函数调用时,他们都必须有确定的值,以便把这些值传递给形参。
3.2 形式参数(形参)
形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元(没有调用的时候,并没有给形式参数开辟空间)),所以叫形式参数。形式参数在函数调用完成之后就自动销毁了。因此形式参数只有在函数中有效。(形参只能是变量)
注意:
(1) 形式参数(形参)和实际参数(实参)使用的不是同一个空间。(地址不一样)
(2)形参实例化以后相当于实参的一份临时拷贝。
四 函数的调用
4.1 传值调用
函数的形参和实参分别占有不同的内存块,对形参的修改不会影响实参。
4.2 传址调用
传址调用是把函数外创建变量的内存地址传递给函数参数的一种调用函数参数的方式。
这种传参方式可以让函数和函数外的参数建立起真正的联系,也就是函数内部可以直接操纵函数外部的变量。(对形参的改变会改变实参)
4.3 练习
4.3.1 写一个函数可以判断一个数是不是素数(is_prime判断素数)
代码1展示:
1. #include <stdio.h> 2. int is_prime(int i) 3. { 4. int j = 0; 5. for (j = 2; j < i; j++) 6. { 7. if (i % j == 0) 8. { 9. return 0; 10. } 11. } 12. return 1; 13. } 14. int main() 15. { 16. int i = 0; 17. for (i = 100; i < 201; i++) 18. { 19. if (is_prime(i) == 1) 20. { 21. printf("%d ", i); 22. } 23. } 24. return 0; 25. }
对代码进行优化
代码2展示:
1. #include <stdio.h> 2. #include <math.h> 3. int is_prime(int n) 4. { 5. int j = 0; 6. for (j = 2; j <= sqrt(n); j++) 7. { 8. if (n % j == 0) 9. { 10. return 0; 11. } 12. } 13. return 1; 14. } 15. int main() 16. { 17. int i = 0; 18. for (i = 100; i < 201; i++) 19. { 20. if (is_prime(i) == 1) 21. { 22. printf("%d ", i); 23. } 24. } 25. return 0; 26. }
(1) 函数中 return 0直接结束所有循环,结束这个函数,跳回主函数
(2)if (is_prime(i))也可以这样写,因为值是1。
4.3.2 写一个函数判断一年是不是闰年(leap year 是闰年的意思)
代码1展示:(和是哪个一个代码类似)
1. #include <stdio.h> 2. int is_leap_year(int x) 3. { 4. if (((x % 4 == 0) && (x % 100 != 0)) || (x % 400 == 0)) 5. { 6. return 1; 7. } 8. else 9. { 10. return 0; 11. } 12. } 13. int main() 14. { 15. int i = 0; 16. for (i = 1000; i <= 2000; i++) 17. { 18. if (is_leap_year(i) == 1) 19. { 20. printf("%d ", i); 21. } 22. } 23. return 0; 24. }
对代码进行优化:
代码2展示:
1. #include <stdio.h> 2. int is_leap_year(int x) 3. { 4. return (((x % 4 == 0) && (x % 100 != 0)) || (x % 400 == 0)); 5. } 6. int main() 7. { 8. int i = 0; 9. for (i = 1000; i <= 2000; i++) 10. { 11. if (is_leap_year(i) == 1) 12. { 13. printf("%d ", i); 14. } 15. } 16. return 0; 17. }
4.3.3 写一个函数,实现一个整形有序数组的二分查找(binary_search 二分查找)
代码展示:
1. 2. #include <stdio.h> 3. int binary_search(int arr[], int k, int right) 4. { 5. int left = 0; 6. while (left <= right) 7. { 8. int mid = (left + right) / 2; 9. if (arr[mid] < k) 10. { 11. left = mid + 1; 12. } 13. else if (arr[mid] > k) 14. { 15. right = mid - 1; 16. } 17. else 18. { 19. return mid; 20. } 21. } 22. return -1; 23. } 24. int main() 25. { 26. int arr[] = {1,2,3,4,5,6,7,8,9,10}; 27. int k = 7; 28. int right = (sizeof(arr) / sizeof(arr[0])) - 1; 29. int m = binary_search(arr, k, right); 30. if (m == -1) 31. { 32. printf("找不到"); 33. } 34. else 35. { 36. printf("找到了,下标是%d", m); 37. } 38. return 0; 39. }
注意:
数组传递给参数的时候,传递的是首元素的地址。所以元素个数要在传递参数之前算好,并传递给函数
4.3.4 写一个函数,每调用一次这个函数,就会将num的值增加1
代码展示:
1. 2. #include <stdio.h> 3. void Add(int* num) 4. { 5. ++*num; 6. } 7. int main() 8. { 9. int num = 0; 10. Add(&num); 11. printf("%d\n", num); 12. Add(&num); 13. printf("%d\n", num); 14. Add(&num); 15. printf("%d\n", num); 16. return 0; 17. }
注意:
前置++和后置++的区别
知识点:
void ——无返回,函数中也可以有return,但是后面不可以有值。return 后面的代码不再执行
char int double ——有返回
函数(1)就到此结束了,希望友友们可以提出宝贵的意见。