形参和实参
形参(形式参数)
定义:
函数定义时的参数,形参是用来接受数据的,函数定义时,系统不会为形参申请内存,只有当函数调用时,系统才会为形参申请内存。主要用于存储实际参数,并且当函数返回时(执行return),系统会自动回收为形参申请的内存资源。
- C语言中所有参数传递都是值传递
- 若要修改实参,需要传递指针
案例:
- 需求:判断一个数是偶数还是奇数
- 代码
#include <stdio.h>
/**
* 方式1
*/
void fun0(int n) // 这里的n就是形式参数
{
if (n % 2 == 0) printf("%d是偶数!\n", n);
else printf("%d是奇数!\n", n);
}
/**
* 方式2 推荐
*/
void fun1(int n)
{
if (n % 2 == 0)
{
printf("%d是偶数!\n", n);
return; // 提前结束函数,return后的代码不再执行
}
printf("%d是奇数!\n", n);
}
/**
* 方式3
*/
int fun2(int n)
{
if (n % 2 == 0)
{
printf("%d是偶数!\n", n);
return -1;// 提前结束函数,return后的代码不再执行
}
printf("%d是奇数!\n", n);
return 0;
}
int main(int argc,char *argv[])
{
fun0(5);
fun1(5);
fun2(5);
return 0;
}
实参(实际参数)
定义
实参是函数调用时由主调函数传递给背调函数的具体的数据。实参可以是常量、变量、表达式。
关键特性
1.类型多样性
-
实参可以是常量、变量或表达式。
-
例如:
fun(12); //常量作为实参 fun(a); //变量作为实参 fun(a + 12); //表达式作为实参
2.类型转化:
- 当实参和形参类型不同时,会按照赋值规则进行隐式类型转换
- 类型转换可能导致精度损失
- 例如:
/**
* 求一个数的绝对值
*/
double fads(double a)
{
return a < 0 ? -a : a;
}
int main()
{
int x = 12, y = - 12;
//函数调用时,自动将int类型隐式转换为double类型;函数调用:主调函数→被调函数
//函数返回时,需要将double类型转换为int类型,此时需要显示转换;团数返回:被调函数→主调函数
int x = (int)fabs(x);
int x = (int)fabs(y);//同上
}
注意:函数调用的时候,通过实参给形参赋值。
- 单向值传递
- C语言采用单向值传递机制(赋值的方向:实参 → 形参)
- 实参仅将其值赋给形参,不传递实参本身
- 形参值的改变不会影响实参。
- 案例:
void modify(int n) // n的变量地址:0x11
{
n = 20; // 修改形参 n = 20
}
int main()
{
int n = 10; // 实参变量 n = 10 n的变量地址:0x22
modify(n);
printf("%d\n", n); // 10
}
- 内存独立性
- 实参和形参在内存中占据不同的空间
- 形参拥有独立的内存地址
演示
#include <stdio.h>
int fun(int n) // n 是形参
{
printf("形参n的值: %d\n", n);
n += 5; // 修改形参
return n;
}
int main()
{
int a = 10;
printf("调用前实参a的值: %d\n", a);
// 变量作为实参
int result = fun(a); // a 是实参
printf("调用后实参a的值: %d\n", a); // a保持不变
printf("函数返回值: %d\n", result);
// 常量作为实参
fun(12); // 字面量12是实参
// 表达式作为实参
fun(a + 12); // 表达式a+12是实参
return 0;
}
上述示例程序会输出:
调用前实参a的值: 10
形参n的值: 10
调用后实参a的值: 10
函数返回值: 15
形参n的值: 12
形参n的值: 22
案例
- 需求:输入4个整数,要求用一个函数求出最大数
- 分析:
- 设计一个函数,这个函数只实现2个数求最大值
- 多次复用这个函数实现最终求值 代码:
代码:
#include <stdio.h>
/**
* 定义一个函数,求两个数中的最大值
* @param x,y
* @return 最大值
*/
int max(int x, int y)
{
return x > y ? x : y;
}
int main(int argc,char *argv[])
{
// 定义4个变量,用来接收控制台输入
int a,b,c,d,m;
printf("请输入四个整数:\n");
scanf("%d%d%d%d",&a, &b, &c, &d);
// 求a,b中的最大值
m = max(a,b);
// 求a,b,c中的最大值
m = max(m,c);
// 求a,b,c,d中的最大值
m = max(m,d);
printf("%d,%d,%d,%d中最大的数是%d\n",a,b,c,d,m);
return 0;
}
- 运行结果
函数返回值
定义
-
若不需要返回值,函数可以没有return语句。
// 如果返回类型是void,return关键字可以省略 void fun1() { ... } // 这种写法,return关键字也可以省略,但是此时默认返回是 return 0 int fun2() { } // 这种写法,return关键字也可以省略,但是此时默认返回是 return 0 fun3() // 如果不写返回类型,默认返回int,C99/C11之后不再支持省略返回类型 { }
-
一个函数中可以有多个return语句,但是同一时刻只有一个return语句被执行。
int eq(int num) { if(num % 2 == 0) { printf("%d是偶数!\n", num); return 0; } printf("%d是奇数!\n", num); return 0; }
-
返回值类型一般情况下要和函数中return语句返回的数据类型一致,如果不一致,以函数定义时指定的返回值类型为标准。
案例
-
用一个函数求出最大数需求:输入两个整数,要求
-
用一个函数求出最大数
#include <stdio.h> /** * 定义一个函数,求两个数中的最大数 * @param x,y 外部传入的整数 * @return 最大数 */ int get_max(int x, int y) { if (x > y) return x; return y; } int main(int argc,char *argv[]) { // 定义三个变量,用来存储控制台输入的两个整数以及最大值 int a,b,max; // 通过控制台录入数据 printf("请输入两个整数:\n"); scanf("%d%d",&a,&b); // 调用函数进行比较 max = get_max(a,b); printf("%d,%d中的最大值是%d\n",a,b,max); return 0; }
-
案例2:涉及类型转换-隐式转换
#include <stdio.h>
/**
* 定义一个函数,求两个数中的最大数
* @param x,y 外部传入的整数
* @return 最大数
*/
double get_max(int x, int y)
{
if (x > y) return x;
return y;
}
int main(int argc,char *argv[])
{
// 定义三个变量,用来存储控制台输入的两个整数以及最大值
int a,b,max;
// 通过控制台录入数据
printf("请输入两个整数:\n");
scanf("%d%d",&a,&b);
// 调用函数进行比较
max = (int)get_max(a,b); // double → int 需要显示转换
printf("%d,%d中的最大值是%d\n",a,b,max);
return 0;
}
-
案例3:涉及类型转换-显示转换
#include <stdio.h> /** * 定义一个函数,求两个数中的最大数 * @param x,y 外部传入的整数 * @return 最大数 */ int get_max(int x, int y) { double z; z = x > y ? x : y; return (int)z; // double → int } int main(int argc,char *argv[]) { // 定义三个变量,用来存储控制台输入的两个整数以及最大值 int a,b,max; // 通过控制台录入数据 printf("请输入两个整数:\n"); scanf("%d%d",&a,&b); // 调用函数进行比较 max = get_max(a,b); printf("%d,%d中的最大值是%d\n",a,b,max); return 0; }