文章目录
- 一,C语言函数与数学函数的区别
- 1,回忆杀-初中数学
- 2,C语言中的函数
- 二, 函数的声明
- 1,函数头
- 1.1,函数名称
- 1.2,返回值类型
- 1.3,参数列表
- 2,函数体
- 2.1,函数体
- 2.2,return语句
- 三,main函数
- 四,函数的参数与传递方式
- 1,实参和形参
- 1.1,函数定义(含形参)
- 1.2,函数调用(使用实参)
- 2,参数传递方式
- 2.1,值传递
- 2.2,引用传递
- 五,函数原型与预声明
- 1,什么是函数原型
- 2,为什么函数要预声明
- 六,函数的返回值
一,C语言函数与数学函数的区别
1,回忆杀-初中数学
说起函数这个词,大多数程序员应该是耳熟能用,初中数学就开始学习函数,到现在已经有了多年的函数经验。
对于下面这张图,想必大家并不陌生吧。
以最简单的一元一次函数为例:
y=3x
在上述函数表达式y = 3x
中,组成部分如下:
- y 被称为因变量(Dependent Variable)或函数值,它依赖于自变量x的值。
- x 被称为自变量(Independent Variable),它是你可以自由选择的输入值。
- 3 是系数(Coefficient),在这个线性函数中表示自变量x每增加1单位,因变量y增加的数量。
- = 表示等于,表明两边的量在给定x的值时是相等的。
- y = 3x 整体构成了一个函数关系,其中y是x的函数,通常会定义一个特定的函数名称,如f(x),写作f(x) = 3x,这里f即为函数名。
2,C语言中的函数
尽管C语言函数借鉴了数学函数的思想,两者间存在根本差异。
数学函数专注于描述数学关系,无需考虑实现细节,而C语言函数则是实现特定任务的代码集合,需关注数据类型、内存管理等编程细节。
数学函数的输入输出都是数字,C语言中的函数可以处理的数据除了数字之外,还可以是字符、指针,甚至是另一个函数。
二, 函数的声明
函数是C语言中一种可以被重复使用的对象,包含一段可以重复执行的代码。函数可以接收不同的参数值,经过相同的逻辑处理,返回对应的结果。
C语言函数由函数头
和函数体
两部分组成:
- 函数头包括函数返回类型、函数名和参数列表(如果有)。
- 函数体包含执行语句,实现函数的具体功能。
下面是一个函数的示例。
int plus1(int num) {
return num + 1;
}
上面的代码声明了一个函数plus1()
,包含函数头和函数体。
1,函数头
1.1,函数名称
上面代码示例定义了名为plus1
的函数。
1.2,返回值类型
函数名plus1
前面的int
指明了函数的返回值类型,这个函数将返回一个整数。
当然,函数可以没有返回值,没有返回值时,返回值类型为void
。
void showNum(int num) {
printf("num=%d", num);
}
1.3,参数列表
函数名plus1
后面的圆括号里面就是参数列表,每个参数由参数类型和参数名组成,可以有多个参数,plus1(int num)
表示这个函数有一个整数参数num
。
2,函数体
2.1,函数体
函数体位于参数列表之后,包裹在一对大括号里面,下图中蓝色部分就是函数体。
注意:大括号前后都不需要加分号。
2.2,return语句
return语句是函数体中的特殊语句,它给出函数的返回值,程序运行到return语句,表示当前函数运行完毕,完成函数调用,返回到调用函数处。
需要注意的是,函数可以没有返回值,所以return语句不是必须得。如果函数没有返回值,可以省略return语句,或者写成return;
。
void showNum(int num) {
printf("num=%d", num);
// 省略return
}
等价于:
void showNum(int num) {
printf("num=%d", num);
return;
}
三,main函数
一个C程序至少包含一个函数,这个函数就是main()
函数,它是程序的入口点。
main()
负责调用其他函数,完成程序的主要任务。
#include <stdio.h>
int main() {
printf("Hello, World!\n");
return 0; // 程序正常结束
}
main()
函数的声明和普通函数并无区别,也包含函数头和函数体,函数头包含返回值类型、函数名称、参数列表,函数体包含return
语句。
正常情况下,如果main()里面省略return 0这一行,编译器会自动加上,即main()的默认返回值为0。所以,写成下面这样,效果完全一样。
#include <stdio.h>
int main() {
printf("Hello, World!\n");
// 省略return 0; 程序正常结束
}
四,函数的参数与传递方式
1,实参和形参
在C语言中,函数的参数分为形式参数(形参,Formal Parameters)和实际参数(实参,Actual Parameters)。
形参是在函数定义中使用的占位符,代表将来调用该函数时传递进来的值。
实参则是函数调用时实际传递给函数的具体值或变量。
下面通过一个简单的示例来说明这一概念。
1.1,函数定义(含形参)
// 函数声明和定义
// 形参:a 和 b 分别代表将要相加的两个整数
int addNumbers(int a, int b) {
int sum = a + b; // 使用形参a和b计算和
return sum; // 返回计算结果
}
在这个例子中,a
和b
是形式参数,它们在函数定义中作为接收外部数据的占位符。
1.2,函数调用(使用实参)
#include <stdio.h>
int main() {
int num1 = 5; // 实际数值1
int num2 = 3; // 实际数值2
// 函数调用,传递实参:num1 和 num2
int result = addNumbers(num1, num2);
// 输出结果
printf("The sum of %d and %d is %d\n", num1, num2, result);
return 0;
}
在main
函数中,当调用addNumbers
函数时,num1
和num2
是实际参数。
这两个实参的值(5和3)会被传递给对应的形参a
和b
,函数内部使用这些值进行计算。
2,参数传递方式
函数参数用于向函数传递数据,C语言支持两种传递方式:值传递和引用传递。
2.1,值传递
传递参数的副本,函数内对参数的修改不影响原变量。
void swapByValue(int x, int y) {
int temp = x;
x = y;
y = temp; // 交换操作仅影响局部副本
}
int main() {
int a = 5, b = 10;
swapByValue(a, b);
printf("a = %d, b = %d\n", a, b); // 输出不变:a = 5, b = 10
}
上述代码,通过值传递调用函数swapByValue(int x, int y)
,表面上起到了交换a和b的值的作用,实则并未改变a和b的值。
这是因为调用函数时是将a
和b
的值复制一份后,赋值给形参变量x
和y
,之后对x
和y
的操作不会影响a
和b
的值。
2.2,引用传递
传递参数的地址,通过指针实现,函数内可通过地址修改原变量。
void swapByReference(int* x, int* y) {
int temp = *x;
*x = *y;
*y = temp; // 实际交换变量的值
}
int main() {
int a = 5, b = 10;
swapByReference(&a, &b);
printf("a = %d, b = %d\n", a, b); // 输出交换后:a = 10, b = 5
}
上述代码,通过值传递调用函数swapByValue(int* x, int* y)
,表面上起到了交换a和b的值的作用,实际上的确起到了这个作用。
这是因为调用函数时是将a
和b
的地址传递给了指针变量x
和y
,函数体内通过运算符*
对x
和y
进行运算,本质上操作x
和y
指向的内存中的数据,也即是变量a
和b
的数据。
五,函数原型与预声明
1,什么是函数原型
函数原型是在函数定义之前提供的一种声明方式,用于告诉编译器函数的返回类型、名称和参数列表。
// 函数原型
int max(int, int);
int main() {
int larger = max(10, 20);
printf("Larger number is: %d\n", larger);
return 0;
}
// 函数定义
int max(int x, int y) {
return (x > y) ? x : y;
}
2,为什么函数要预声明
我们知道,函数一定要先声明后使用。
我们还知道,main()
函数是C程序第一个运行的函数,这就导致所有的函数都必须在main()
函数之前声明。
void func1(void) {
}
void func2(void) {
}
int main(void) {
func1();
func2();
return 0;
}
上面代码中,main()
函数必须在最后声明,否则编译时会产生警告,找不到func1()
或func2()
的声明。
但是,这样编写代码有很多实践上的困难:
- 一方面,main()是整个程序的入口,也是主要逻辑,放在最前面更好。
- 另一方面,对于函数较多的程序,保证每个函数的顺序正确,会变得很麻烦。
C 语言的解决方案是在程序文件最前面给出函数原型,函数就可以先使用、后声明。
所谓函数原型,就是函数头,不需要函数体,函数体包含在之后的完整函数声明中。
int twice(int);
int main(int num) {
return twice(num);
}
int twice(int num) {
return 2 * num;
}
上面示例中,函数twice()的完整声明是放在main()后面,但是代码头部先给出了函数原型,所以可以正确编译。
只要提前给出函数原型,函数具体的实现放在哪里,就不重要了。
函数原型包括参数名也可以,虽然这样对于编译器是多余的,但是阅读代码的时候,可能有助于理解函数的意图。
int twice(int);
// 等同于
int twice(int num);
上面示例中,twice函数的参数名num,无论是否出现在原型里面,都是可以的。
注意,函数原型必须以分号结尾。
六,函数的返回值
函数通过return
语句返回一个值给调用者。
返回类型在函数声明和定义中指定,可以是任何基本类型、结构体、甚至指针。
float average(int a, int b) {
return (a + b) / 2.0f;
}
int main() {
float avg = average(3, 7);
printf("Average is: %.1f\n", avg); // 输出:Average is: 5.0
return 0;
}
void
类型的函数表示不返回任何值。
void showNum(int num) {
printf("num=%d", num);
}
int main() {
int num = 10;\
showNum(10);
return 0;
}