1. 函数是什么
- 在计算机科学中,函数是一个大型程序中的某部分代码, 由一个或多个语句块组
成,它负责完成某项特定任务,而且相较于其他代码,具备相对的独立性。- 函数一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏,这些代码通常被集成为软件库。
2. 库函数
为什么会有库函数?
对于一些在开发过程中每个程序员都可能用到的基础功能,为了支持可移植性和提高程序的效率,C语言的基础库中提供了一系列类似的库函数,方便程序员进行软件开发。
那怎么学习库函数呢?
- www.cplusplus.com
- MSDN(Microsoft Developer Network)
- http://en.cppreference.com(英文版)
- http://zh.cppreference.com(中文版)
以下为具体的两个例子:
#include <stdio.h> #include <string.h> int main() { char arr1[] = "hello bit";//源头 char arr2[20] = { 0 };//目的地 //对于数组,数组名其实是数组第一个元素的地址,也就是起始地址 strcpy(arr2, arr1); printf("%s\n", arr2); return 0; }
#include <stdio.h> #include <string.h> int main() { char arr[] = "hello bit"; memset(arr, 'x', 5); printf("%s\n", arr); return 0; }
注: 使用库函数,必须包含 #include 对应的头文件。
3. 自定义函数
自定义函数和库函数一样,有函数名、返回值类型和函数参数。
写一个函数可以找出两个整数中的最大值。
#include <stdio.h> int get_max(int x, int y) { int z = (x > y ? x : y); return z; } int main() { int a = 0; int b = 0; //输入 scanf("%d %d", &a, &b); //计算 //int m = (a > b ? a : b); //使用函数来完成 int m = get_max(a, b); //输出 printf("较大值是: %d\n", m); return 0; }
写一个函数可以交换两个整形变量的内容。
//以下写法是有问题的 #include <stdio.h> //形式参数 - 形参 void Swap(int x, int y) { int tmp = x; x = y; y = tmp; } int main() { int a = 0; int b = 0; scanf("%d %d", &a, &b); 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 tmp = *pa;//tmp = a *pa = *pb;//a = b *pb = tmp;//b = tmp } int main() { int a = 0; int b = 0; scanf("%d %d", &a, &b); printf("交换前:a=%d b=%d\n", a, b); Swap(&a, &b); printf("交换后:a=%d b=%d\n", a, b); return 0; }
4. 函数的参数
4.1 实际参数(实参)
- 真实传给函数的参数,叫实参。
- 实参可以是:常量、变量、表达式、函数等。
- 无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。
#include <stdio.h> int get_max(int x, int y) { int z = (x > y ? x : y); return z; } int main() { int a = 0; int b = 0; //输入 scanf("%d %d", &a, &b);//3 5 //使用函数来完成 int m = get_max(a, b);//变量 m = get_max(a, 7);//变量,常量 m = get_max(a, 2+3);//表达式 m = get_max(a, get_max(4, 8));//函数的参数是函数调用 //输出 printf("较大值是: %d\n", m); return 0; }
4.2 形式参数(形参)
形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了,因此形式参数只在函数中有效。
这里可以看到Swap1函数在调用的时候,x、y 拥有自己的空间,同时拥有了和实参一模一样的内容。所以我们可以简单的认为:形参实例化之后其实相当于实参的一份临时拷贝。
5. 函数的调用
5.1 传值调用
函数的形参和实参分别占有不同的内存块,对形参的修改不会影响实参。
#include <stdio.h> void Swap1(int x, int y) { int tmp = 0; tmp = x; x = y; y = tmp; } int main() { int num1 = 1; int num2 = 2; Swap1(num1, num2); printf("Swap1::num1 = %d num2 = %d\n", num1, num2); return 0; }
5.2 传址调用
- 传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。
- 这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操作函数外部的变量。
#include <stdio.h> void Swap2(int* px, int* py) { int tmp = 0; tmp = *px; *px = *py; *py = tmp; } int main() { int num1 = 1; int num2 = 2; Swap2(&num1, &num2); printf("Swap2::num1 = %d num2 = %d\n", num1, num2); return 0; }
5.3 练习
- 写一个函数可以判断一个数是不是素数。
//是素数返回1 //不是素数返回0 //2~sqrt(n) #include <stdio.h> #include <math.h> //判断素数 int is_prime(int n) { int j = 0; for (j = 2; j <= sqrt(n); j++) { if (0 == n % j) { return 0; } } return 1; } int main() { int i = 0; for (i = 100; i <= 200; i++) { //判断i是否为素数 if (1 == is_prime(i)) { printf("%d ", i); } } return 0; }
- 写一个函数判断一年是不是闰年。
//是闰年返回1 //非闰年返回0 #include <stdio.h> /*int is_leap_year(int y) { if (((0 == y % 4) && (y % 100 != 0)) || (0 == y % 400)) { return 1; } else { return 0; } }*/上下两种写法都可 //2. 实现函数 int is_leap_year(int y) { return ((0 == y % 4) && (y % 100 != 0)) || (0 == y % 400); } int main() { int y = 0; for (y = 1000; y <= 2000; y++) { //1. 函数怎么使用 //TDD - 测试驱动开发 //test driven development // if (1 == is_leap_year(y)) { printf("%d ", y); } } return 0; }
- 写一个函数,实现一个整形有序数组的二分查找。
#include <stdio.h> int binary_search(int arr[], int k, int sz) { int left = 0; int right = sz - 1; while (left <= right) { //int mid = (left + right) / 2; int mid = left + (right - left) / 2;//这样写可以避免left+right超过int的最大值 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]); //二分查找 //找到了: 返回下标 //找不到: 返回-1 int ret = binary_search(arr, k, sz); if (-1 == ret) { printf("找不到\n"); } else { printf("找到了,下标是:%d\n", ret); } return 0; }
- 写一个函数,每调用一次这个函数,就会将 num 的值增加1。
#include <stdio.h> void test(int* p) { (*p)++; } int main() { int num = 0; test(&num); test(&num); printf("%d\n", num); return 0; } //以下方法不是很好 //int test(int n) //{ // return (n + 1); //} // //int main() //{ // int num = 0; // num = test(num); // num = test(num); // printf("%d\n", num); // // return 0; //}