首页 > 编程笔记 > C语言笔记 阅读:31

C语言中的形参和实参(非常详细)

在 C语言中,函数的参数分为形式参数(也称为形参)和实际参数(也称为实参)。

形式参数是函数声明或定义中定义的参数,用于描述函数所需的输入。形式参数只存在于函数内部,对于函数外部是不可见的。当函数被调用时,实参将被传递给形参,然后函数使用形参进行计算。

例如,下面是一个函数原型:
int add(int a, int b);
这个函数的原型包含两个形参,分别是 a 和 b。这个函数的功能是将 a 和 b 相加并返回结果。

当函数被调用时,需要提供实参。实参是调用函数时提供给函数的具体参数值。实参可以是常量、变量、表达式等。当调用函数时,实参被传递给函数的形参,函数使用这些值进行计算。

例如,下面是一个函数调用的示例:
int result = add(2, 3);
在对这个函数的调用中,2 和 3 是实参,它们被传递给函数 add() 的形参 a 和 b。函数 add() 使用这些值进行计算,然后返回结果。在这个例子中,函数的返回值是 5,它被赋值给变量 result。

总之,形参是函数定义中声明的参数,实参是在函数调用中传递给函数的具体参数值。函数使用形参进行计算,然后返回结果。在函数的定义和调用中,正确使用形参和实参非常重要,它们对函数的正确性和效率起着至关重要的作用。因此,我们应该尽可能地明确和清晰地定义和使用它们。

形参和实参的自动类型转换

一般情况下,形式参数与实际参数的类型应该一致,但是 C语言允许不同类型的参数进行传递,这种情况下会发生自动类型的转换。

例如:
#include <stdio.h>
int add(int a, int b) // 定义 add 函数
{
    return a + b;
}

int main()
{
    int result;
    result = add(2.2, 3.3);  // 调用 add 函数
    printf("%d", result);
    return 0;
}
在上面的示例中,我们将实参 2.2 和 3.3 分别传递给形式参数 int a 和 int b。编译并运行后,会显示如下面所示的警告信息,同时运行结果为 5。
warning C4244: “函数”: 从 “double” 转换到 “int”,可能丢失数据
warning C4244: “函数”: 从 “double” 转换到 “int”,可能丢失数据
可以看到,编译器会提示我们从 double 类型到 int 类型的转换会导致数据丢失。

当实参被传递给形参时,编译器会尝试将实参转换为形参的类型。如果可以转换,则编译器会通过;如果在转换过程中可能出现数据丢失,则编译器会发出警告。在这个示例中,2.2 和 3.3 分别被转换为整型 2 和 3,小数部分丢失。如果无法转换,则编译器会报错,编译失败。

同样,返回值也可能会发生自动类型的转换,例如:
#include <stdio.h>
double add(int a, int b) // 定义 add 函数,返回类型为 double
{
    return a + b;
}

int main()
{
    double result;
    result = add(2, 3);    // 调用 add 函数
    printf("%f", result);
    return 0;
}
程序中,我们将 add() 函数的返回类型改为 double。然而,函数的参数仍然是 int 类型,因此 a 和 b 相加的结果仍然是 int 类型。但是,当返回值时,编译器会尝试将 int 类型的值转换为 double 类型。因为 int 类型可以被转换为 double 类型,所以编译器不会报错。

形参与实参相互独立

下面的实例程序展示了一段交换两个变量值的代码。
#include <stdio.h>
int main()
{
    int a, b;
    int temp;
    a = 1;
    b = 2;
    printf("a=%d b=%d\n", a, b);

    // 交换 a、b 变量
    temp = a;
    a = b;
    b = temp;

    printf("a=%d b=%d\n", a, b);
    return 0;
}
在主函数中声明了两个整型变量 a 和 b,其中 a 被赋值为 1,b 被赋值为 2。然后,交换了 a 和 b 的值,使得 a 为 2,b 为 1。运行结果为:

a=1 b=2
a=2 b=1

现在,我们尝试将交换变量值的代码封装到函数中,具体代码如下:
#include <stdio.h>
void swap(int a, int b)
{
    int temp = a;
    a = b;
    b = temp;
}
int main()
{
    int a, b;
    a = 1;
    b = 2;
    printf("a=%d b=%d\n", a, b);
    // 交换变量 a 和 b
    swap(a, b);
    printf("a=%d b=%d\n", a, b);
    return 0;
}
运行结果为:

a=1 b=2
a=1 b=2

我们发现交换竟然失败了。这是因为,在 C语言中,函数的形参和实参是相互独立的。这意味着在函数中对形参的修改不会影响到实参。

虽然在主函数中的变量 a 和 b 与 swap() 函数中的形参 a 和 b 的名字相同,但是它们是相互独立的变量。当在主函数中调用 swap() 函数时,swap() 函数的形参 a 和 b 会被初始化为传入 main() 函数中的实参 a 和 b 的值。这里需要注意的是,在函数的调用过程中,实参的值会被复制到形参中。这意味着,形参和实参是两个不同的变量,它们互不干扰。

举一个生活中的例子,同学 A 有一份学习笔记 NoteA,同学 B 也想要一份,因此同学 A 将学习笔记 NoteA 复制了一份,并命名为 NoteB,然后把它给了同学 B。此时,同学 B 发现笔记中的一些错误,想对 NoteB 进行修改,但无论如何修改 NoteB,都不会影响同学 A 手中的 NoteA。

所以,swap() 函数无论在 main() 函数中被调用多少次,都不会影响 main() 函数中的变量 a 和 b 的值。当然,还有其他方式可以使用函数来交换两个变量的值,比如借助 C 语言中的指针实现,感兴趣的读者可阅读《C语言指针变量作为函数参数》一文。 

不同函数的变量相互独立

下面的程序展示了不同函数的变量是如何相互独立的。
#include <stdio.h>
void func()
{
    int a;
    a = 100;
    printf("a in func %d\n", a);
}

int main()
{
    int a = 0;
    printf("a in main %d\n", a);
    func();
    printf("a in main %d\n", a);
    return 0;
}
在 main() 函数中声明了一个变量 a,并将其初始化为 0。在 func() 函数中也声明了一个变量 a,并将其赋值为 100。尽管这两个变量的名称相同,但它们是两个相互独立的变量。运行结果为:

a in main 0
a in func 100
a in main 0

我们可以看出,不同函数中的变量是互相独立的。

在 C语言中,函数局部变量是指在函数内部定义的变量,只能在函数内部访问,无法在函数外部使用。函数局部变量的作用域仅限于函数内部,在函数执行结束后,变量的内存空间也会被释放。

函数局部变量的一个重要特点是,在每次函数被调用时都会重新创建它们。这意味着,每次执行函数时,函数局部变量的值都会被初始化,而不是保留上一次执行结束时的值。

相关文章