关于C语言中按值调用的问题

uinbv5nw  于 2023-08-03  发布在  其他
关注(0)|答案(4)|浏览(113)

当我运行这个程序时,它输出10 20(第一个代码片段)。

#include <stdio.h>

int x = 10;
int y = 20;

int main()
{
    fun(x, y);
    printf("%d %d", x, y);
}

int fun(int x, int y)
{
    x = 30;
    y = 40;
}

字符串
但是当我这样写的时候:

#include <stdio.h>

int x = 10;
int y = 20;

int main()
{
    fun(x, y);
    printf("%d %d", x, y);
}

int fun(int n1, int n2)    // I include other variables except from global variable.
{
    x = 30;
    y = 40;
}


它输出30 40。我想知道为什么它修改全局变量只有第二个代码片段,即使没有使用指针?为什么第一个不是?如果有人建议我参考这个理论部分,我会很充分。
我想正确地学习这些理论部分,因为我是编程新手。

b1uwtaje

b1uwtaje1#

对于初学者,请注意函数fun应在其在main的主体中使用之前声明。
在第一个函数中

int fun(int x, int y)
{
x = 30;
y = 40;
}

字符串
存在作为函数的局部变量的改变的函数参数xy。参数由文件范围全局变量xy的值初始化,但全局变量本身没有更改。
在函数中,全局变量xy被同名参数隐藏。因此,函数处理的是参数而不是全局变量。
您可以使用以下技巧来更改函数中的全局变量

int fun(int x, int y)
{
    x = 30;
    y = 40;
    
    {
        extern int x;
        extern int y;

        x = 30;
        y = 40;
    }
}


在这种情况下,函数内部块中的声明

extern int x;
extern int y;


引用具有外部链接的全局变量,并且全局变量被改变。
在第二个函数中,不使用参数。

int fun(int n1, int n2)    // I include other variables except from global variable.
{
x = 30;
y = 40;
}


在这种情况下,编译器会发出一条关于未使用参数的消息。
在函数中直接改变全局变量。文件作用域变量xy在函数体中是可见和可访问的。
您可以按以下方式考虑第二个函数的主体

int n1 = x;
int n2 = y;

x = 30;
y = 40;

jgwigjjp

jgwigjjp2#

在第一个示例中,您正在修改局部变量xy,它们是作为函数fun参数创建的
在第二个示例中,您将不修改这些参数,而是修改全局变量xy
如果你想修改第二个例子中的参数,你可以修改

int fun(int n1, int n2)
{
    n1 = 30;
    n2 = 40;
}

字符串

t1qtbnec

t1qtbnec3#

正如您所了解的,在C中,函数参数是通过值传递的,因此当调用fun(x, y)时,您将全局变量xy的当前值传递给函数fun
在第一个例子中,函数fun被定义为函数参数的名称xy。在函数体中,当引用xy时,参数定义在作用域中,修改xy只修改参数值,这些值是函数的局部值。全局变量不受影响。当一个局部定义在外部作用域中隐藏了另一个局部定义时,我们说外部定义被内部定义 * 遮蔽 * 了。这有点令人困惑和容易出错:如果将-Wall -Wextra传递给gccclang编译器,则会在这种情况下启用警告。
在第二个例子中,函数参数被定义为n1n2,因此函数体中的代码确实修改了全局变量xy,并且实际上程序输出了修改后的值。
还请注意这些备注:

  • 没有参数的main的原型是C中的int main(void);
  • 函数fun应该在使用前声明或定义。编译器宽容地接受这个调用,并从函数参数中推断出原型为int fun(int, int),这与后面的函数定义一致。支持这种ANSI之前的行为是为了与旧代码兼容,例如原始K&R书中的示例,但现代C程序不应依赖于此,额外的警告级别将对此提出异议。
  • main函数应该返回0成功,尽管C99在没有return语句的情况下将其作为默认行为。
  • 你应该输出一个尾随的换行符以确保在终端中正确显示。如果没有这个换行符,shell提示符可能会粘在最后一个字符输出上,导致进一步的混乱,特别是如果提示符是%$
  • 函数fun被定义为返回一个int,但是该函数在没有return语句的情况下退出。您应该将函数定义为void,以避免未定义的行为。

以下是修改后的版本:

#include <stdio.h>

int x = 10;
int y = 20;

void fun1(int x, int y) {
    x = 30;
    y = 40;
}

void fun2(int n1, int n2) {
    x = 30;
    y = 40;
}

int main(void) {
    fun1(x, y);
    printf("%d %d\n", x, y); // outputs 10 20
    fun2(x, y);
    printf("%d %d\n", x, y); // outputs 30 40
    return 0;
}

字符串

ryoqjall

ryoqjall4#

在第一个代码片段中,fun函数通过值接收参数x和y,这意味着该函数创建了这些变量的本地副本。对这些局部副本所做的任何修改都不会影响在main函数外部定义的原始全局变量x和y。因此,当您在调用fun后在main函数中打印x和y时,它们的值保持不变,导致打印“10 20”。
在第二个代码片段中,您使用了与fun函数中的全局变量相同的变量名x和y。这会产生歧义,因为函数参数n1和n2与全局变量具有相同的名称。在这种情况下,当你在fun函数中为x和y赋值时,它会修改全局变量本身,因为它们具有相同的名称。这称为隐藏,其中局部变量隐藏具有相同名称的全局变量。因此,当您在调用fun后在main函数中打印x和y时,您会看到修改后的值“30 40”,因为全局变量是在函数中直接修改的。
为了避免混淆和类似的潜在问题,通常建议在函数中为局部变量使用不同的名称,以清楚地将它们与全局变量区分开来。这有助于提高代码的可读性,并避免对全局变量的无意修改。
要进一步了解变量作用域和隐藏,您可以参考详细介绍这些主题的C编程语言教科书或在线资源。一些推荐的资源包括Brian Kernighan和Dennis里奇的“C编程语言”或tutorialspoint.com或cplusplus.com等网站。

相关问题