C语言:函数
这是很基础的教程,我只是写给自己看,作为一个学习笔记记录一下,如果正在阅读的你觉得简单,请不要批评,可以关掉选择离开
如何学好一门编程语言
- 掌握基础知识,为将来进一步学习打下良好的基础。
- 上机实践,通过大量的例题学习怎么设计算法,培养解题思路。
- 养成良好的编码习惯,注释一定要写,要不然保你一周后自己写的代码都不认识了。
函数
每个 C 程序都至少有一个主函数 main() ,和0个或若干个额外定义的函数。
函数定义
函数定义提供了函数的实际主体,告诉编译器 函数名、返回类型 和 参数 等信息
返回类型 函数名( 参数列表 )
{
函数主体
}
- 返回类型:指定函数返回值的数据类型。void 表示没有返回值
- 函数名:函数的名字
- 参数:当函数被调用时,向函数传递的值。这个参数可以是变量,也可以是函数,也可以没有参数。没有参数可以不写也可以写 void
- 函数主体:包含函数执行任务的语句
return 0 是终止该函数,和 exit(0) 是终止程序。
函数声明
- 当函数定义在函数调用前 则不需要函数声明
- 当函数定义在函数调用后 则需要在调用前需要先声明
返回类型 函数名( 参数列表 );
在函数声明中,参数的名称并不重要,只有参数的类型是必需的,因此下面也是有效的声明:
int max(int num1, int num2); int max(int, int);
调用函数
函数名(实参); // 无返回 调用函数 返回值 = 函数名(实参); // 有返回 调用函数
案例:
#include <stdio.h> int max(int num1, int num2); /* 函数声明 */ int main () { /* 局部变量定义 */ int a = 100; int b = 200; int ret; /* 调用函数来获取最大值 */ ret = max(a, b); printf( "最大值为 : %d\n", ret ); // 200 return 0; } /* 函数返回两个数中较大的那个数 */ int max(int num1, int num2) { /* 局部变量声明 */ int result; if (num1 > num2) result = num1; else result = num2; return result; }
函数传参
函数参数被分为 形参 和 实参;
- 形参:在函数定义及函数说明时的参数,形参变量只有被调用时才分配内存单元
- 实参:在函数调用时给出的参数
当调用函数时,有两种向函数传递参数的方式:
位置传参:实参和形参的位置必须一一对应
#include <stdio.h> /* 函数声明 */ void swap(int x, int y); int main () { /* 局部变量定义 */ int a = 100; int b = 200; printf("交换前,a 的值: %d\n", a ); // 100 printf("交换前,b 的值: %d\n", b ); // 200 /* 调用函数来交换值 */ swap(a, b); printf("交换后,a 的值: %d\n", a ); // 100 printf("交换后,b 的值: %d\n", b ); // 200 return 0; } /* 函数定义 */ void swap(int x, int y) { int temp; temp = x; /* 保存 x 的值 */ x = y; /* 把 y 赋值给 x */ y = temp; /* 把 temp 赋值给 y */ return; }
关键字传参:按形参的名字给形参赋值,实参名必须与形参名进行匹配,因此实参的顺序和形参的顺序可以不一致。
指针传参:通过指针传递方式,形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作。
#include <stdio.h> /* 函数声明 */ void swap(int *x, int *y); int main () { /* 局部变量定义 */ int a = 100; int b = 200; printf("交换前,a 的值: %d\n", a ); // 100 printf("交换前,b 的值: %d\n", b ); // 200 /* 调用函数来交换值 * &a 表示指向 a 的指针,即变量 a 的地址 * &b 表示指向 b 的指针,即变量 b 的地址 */ swap(&a, &b); printf("交换后,a 的值: %d\n", a ); // 200 printf("交换后,b 的值: %d\n", b ); // 100 return 0; } /* 函数定义 */ void swap(int *x, int *y) { int temp; temp = *x; /* 保存地址 x 的值 */ *x = *y; /* 把 y 赋值给 x */ *y = temp; /* 把 temp 赋值给 y */ return; }
默认情况下,C 使用关键字传参,不能改变调用函数的实际参数,但是用关键字传参,可以改变实际参数。
作用域
作用域定义变量所存在的区域,超过该区域变量就不能被访问。
局部变量:在函数或块的内部声明的变量。只能被该函数或该代码块内部的语句使用。
全局变量:定义在函数外部,通常是在程序的顶部。全局变量可以被任何函数访问。
注意:在程序中,局部变量和全局变量的名称可以相同,但是在函数内,如果两个名字相同,会使用局部变量值,全局变量不会被使用。
当局部变量被定义时,系统不会对其初始化,您必须自行对其初始化。定义全局变量时,系统会自动对其初始化,如下所示:
| 数据类型 | 初始化默认值 |
|---|---|
| int | 0 |
| char | '\0' |
| float | 0 |
| double | 0 |
| pointer | NULL |
正确地初始化变量是一个良好的编程习惯,否则有时候程序可能会产生意想不到的结果。
参数
数组传入函数
在函数中传递一个一维数组作为参数,
方式1:形参是一个指针
void myFunction(int *param) {...}
方式 2:形参是一个已定义大小的数组
void myFunction(int param[10]) {...}
方式3:形式参数是一个未定义大小的数组:
void myFunction(int param[]) {...}
案例
#include <stdio.h> double getAverage(int arr[], int size); /* 函数声明 */ int main() { /* 带有 5 个元素的整型数组 */ int balance[5] = {1000, 2, 3, 17, 50}; double avg; /* 传递一个指向数组的指针作为参数 */ avg = getAverage(balance, 5); /* 输出返回值 */ printf("平均值是: %f ", avg); // 214.400000 return 0; } double getAverage(int arr[], int size) { int i; double avg; double sum = 0; for (i = 0; i < size; ++i) { sum += arr[i]; } avg = sum / size; return avg; }
函数返回数组
如果您想要从函数返回一个一维数组,您必须声明一个返回指针的函数,
int * myFunction() {...}
案例
补充知识点:C 不支持在函数外返回局部变量的地址,除非定义局部变量为 static 变量。
#include <stdio.h> #include <stdlib.h> #include <time.h> /* 要生成和返回随机数的函数 */ int *getRandom() { static int r[10]; int i; /* 设置种子 */ srand((unsigned) time(NULL)); for (i = 0; i < 10; ++i) { r[i] = rand(); printf("r[%d] = %d\n", i, r[i]); } return r; } /* 要调用上面定义函数的主函数 */ int main() { int *p; /* 一个指向整数的指针 */ int i; p = getRandom(); for (i = 0; i < 10; i++) { printf("*(p + %d) : %d\n", i, *(p + i)); } return 0; }
r[0] = 313959809 r[1] = 1759055877 r[2] = 1113101911 r[3] = 2133832223 r[4] = 2073354073 r[5] = 167288147 r[6] = 1827471542 r[7] = 834791014 r[8] = 1901409888 r[9] = 1990469526 *(p + 0) : 313959809 *(p + 1) : 1759055877 *(p + 2) : 1113101911 *(p + 3) : 2133832223 *(p + 4) : 2073354073 *(p + 5) : 167288147 *(p + 6) : 1827471542 *(p + 7) : 834791014 *(p + 8) : 1901409888 *(p + 9) : 1990469526
可变参数
有时候我们可能会希望 函数带有可变数量的参数,C语言的 stdarg.h 头文件 提供了实现可变参数功能的函数和宏。
int func(int, ... ) { ... } int main(){ func(2, 2, 3); func(3, 2, 3, 4); }
函数 func() 最后一个参数写成省略号,即三个点号(...),省略号之前的那个参数是 int,代表了要传递的可变参数的总数。
具体步骤如下:
- 定义一个函数,最后一个参数为省略号,省略号前面可以设置自定义参数数量。
- 在函数定义中创建一个 va_list 类型变量,该类型是在 stdarg.h 头文件中定义的。
- 使用 va_start 宏来 初始化 va_list 变量。宏 va_start 是在 stdarg.h 头文件中定义的。
- 使用 va_arg 宏来访问 va_list 变量中的每一项
- 使用宏 va_end 来清理赋予 va_list 变量的内存。
#include <stdio.h> #include <stdarg.h> double average(int num, ...){ va_list valist; //创建一个 va_list 类型变量 valist double sum = 0.0; int i; va_start(valist, num); // va_start宏初始化变量valist for (i = 0; i < num; i++){ sum += va_arg(valist, int); // va_arg宏访问valist成员 } va_end(valist);// 清理 valist 内存 return sum / num; } int main(){ printf("2, 3, 4, 5的平均值为:%f\n", average(4, 2, 3, 4, 5)); // 3.500000 printf("5, 10, 15的平均值为:%f\n", average(3, 5, 10, 15)); // 10.000000 }
递归
递归就是 函数自己调用自己(在使用递归时,程序员需要注意定义一个从函数退出的条件,否则会进入死循环)
案例:计算一个数的阶乘
#include <stdio.h> // 声明定义一个函数 double factorial(unsigned int i){ if (i <= 1){ return 1; } return i * factorial(i - 1); } int main(){ int i = 15; printf("%d 的阶乘为 %f\n", i, factorial(i)); // 15 的阶乘为 1307674368000.000000 return 0; }
案例:生成斐波那契数列
#include <stdio.h> int fibonaci(int i){ if (i == 0){ return 0; } if (i == 1){ return 1; } return fibonaci(i - 1) + fibonaci(i - 2); } int main(){ int i; for (i = 0; i < 10; i++){ printf("%d\t\n", fibonaci(i)); } return 0; }
0 1 1 2 3 5 8 13 21 34
命令行参数
命令行参数也是main函数的参数,执行程序时,可以从命令行传值给 C 程序。这些值被称为命令行参数,它们对程序很重要,特别是当您想从外部控制程序,而不是在代码内对这些值进行硬编码时,就显得尤为重要了。
命令行参数是使用 main() 函数参数来处理的,main函数的参数只能有两个,习惯上这两个参数写为 main (int argc, char *argv[])
- argc:整型实参,传入参数的个数,如果没有提供任何参数,argc 将为 1
- argv[ ]:字符型指针数组,指向传递给程序的每个参数。
- argv[0]:程序的名称
- argv[1]:指向第一个命令行参数的指针
- *argv[n]:最后一个参数
实例:先把代码编译成.exe文件,然后在cmd中执行 ./**.exe 参数1 参数2
#include <stdio.h> int main(int argc, char* argv[]){ if (argc == 2){ printf("提供的参数是 %s\n", argv[1]); } else if (argc > 2){ printf("提供的参数太多.\n"); } else{ printf("期望一个参数.\n"); } }
多个命令行参数之间用空格分隔,但是如果参数本身带有空格,那么传递参数的时候应把参数放置在双引号 "" 或单引号 '' 内部。让我们重新编写上面的实例
$./a.out "testing1 testing2" Progranm name ./a.out The argument supplied is testing1 testing2
参考
浙公网安备 33010602011771号