提问人:Thilina 提问时间:7/4/2023 最后编辑:chqrlieThilina 更新时间:7/5/2023 访问量:169
关于C语言中按值调用的问题
Question about call by value in C language
问:
当我运行这个程序时,它会输出(第一个代码片段)。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
我想正确地学习这些理论部分,因为我是编程新手。
答:
在第一个示例中,您正在修改局部变量 x
和 y
,这些变量被创建为函数的参数fun
在第二个示例中,您将不理会这些参数,而是修改全局变量和x
y
如果要修改第二个示例中的参数,则将
int fun(int n1, int n2)
{
n1 = 30;
n2 = 40;
}
首先,请注意,该函数应在 的主体中使用之前声明。fun
main
在第一个函数中
int fun(int x, int y)
{
x = 30;
y = 40;
}
函数参数已更改,这些参数是函数的局部变量。参数由文件范围全局变量的值初始化,但全局变量本身未更改。x
y
x
y
在函数中,全局变量 和 被同名的参数隐藏。因此,该函数处理的是参数而不是全局变量。x
y
您可以使用以下技巧来更改函数中的全局变量
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;
}
在这种情况下,编译器会发出有关未使用参数的消息。
在函数中,直接更改了全局变量。文件作用域变量,在函数主体中可见且可访问。x
y
您可以按以下方式考虑第二个函数的主体
int n1 = x;
int n2 = y;
x = 30;
y = 40;
在第一个代码片段中,fun 函数按值接收参数 x 和 y,这意味着该函数创建这些变量的本地副本。对这些本地副本所做的任何修改都不会影响在 main 函数外部定义的原始全局变量 x 和 y。因此,当你调用 fun 后在 main 函数中打印 x 和 y 时,它们的值保持不变,导致打印“10 20”。
在第二个代码片段中,您使用的变量名称 x 和 y 与 fun 函数中的全局变量相同。这会产生歧义,因为函数参数 n1 和 n2 与全局变量同名。在这种情况下,当您在 fun 函数中为 x 和 y 赋值时,它会修改全局变量本身,因为它们具有相同的名称。这称为重影,其中局部变量对具有相同名称的全局变量进行重影。因此,当您在调用 fun 后在 main 函数中打印 x 和 y 时,您会看到修改后的值“30 40”,因为全局变量是在函数中直接修改的。
为了避免混淆和潜在的问题,通常建议对函数中的局部变量使用不同的名称,以清楚地将它们与全局变量区分开来。这有助于提高代码的可读性,并避免对全局变量进行无意的修改。
要进一步了解变量范围和阴影,您可以参考 C 编程语言教科书或详细介绍这些主题的在线资源。一些推荐的资源包括 Brian Kernighan 和 Dennis Ritchie 的“The C Programming Language”,或者 tutorialspoint.com 或 cplusplus.com 等网站。
评论
n1
n2
如您所见,函数参数在 C 中是按值传递的,因此在调用时,您将全局变量的当前值传递给函数。fun(x, y)
x
y
fun
在第一个示例中,函数是用名称和函数参数定义的。在函数的主体中,当您引用 和 时,参数定义在作用域内,并且正在修改,并且仅修改函数的局部参数值。全局变量不受影响。当一个局部定义从外部范围隐藏另一个定义时,我们说外部定义被内部定义所掩盖。这有点令人困惑且容易出错:传递给 gcc 或 clang 编译器将在这种情况下启用警告。fun
x
y
x
y
x
y
-Wall -Wextra
在第二个示例中,函数参数定义为 和 ,因此函数体中的代码确实修改了全局变量 和 ,并且程序确实输出了修改后的值。n1
n2
x
y
另请注意以下备注:
- 没有参数的原型是 C 语言;
main
int main(void)
- 该函数应在使用前声明或定义。编译器宽容地接受此调用,并从函数参数推断原型,这与后面的函数定义一致。这种ANSI之前的行为是为了与旧代码兼容,例如原始K&R书中的示例,但现代C程序不应该依赖它,额外的警告级别会抱怨它。
fun
int fun(int, int)
- 该函数应返回成功,尽管 C99 已将此作为没有语句的默认行为。
main
0
return
- 您应该输出尾随换行符以确保在终端中正确显示。如果没有此换行符,shell 提示符可能会粘附在最后一个字符输出上,从而导致进一步的混淆,尤其是当提示符为 or 时。
%
$
- 该函数被定义为返回一个 ,但该函数在没有语句的情况下退出。您应该定义函数以避免未定义的行为。
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;
}
评论
x
x