在C语言中传递引用或使用全局变量

3
如果我想修改一个函数的值并将其带回主函数,哪个方法更好?在C语言中,通过引用传递,我指的是使用指针,就像这个例子。我应该把'a'作为全局变量吗?
#include <stdio.h>
#include <conio.h>

int sum;

int example(int *a,int b)
{
    sum = *a + b;
    (*a)++;
}

int main(void)
{
    int a, b;
    printf("Tell me the value of A and B: \n");
    scanf("%d %d", &a, &b);
    example(&a, b);
    printf("The result: %d . And the new value of A: %d", sum, a);

    printf("\n\nTHE END\n");
    getch();
    return 0;
}

2
避免使用文件作用域变量。 - ouah
2
简单的回答,不要使用全局变量。另外,你的 example() 函数没有返回值,这样会更好。 - Iharob Al Asimi
尽可能避免使用全局变量:http://programmers.stackexchange.com/questions/148108/why-is-global-state-so-evil - rost0031
请注意,C函数可以返回一些struct聚合体。 - Basile Starynkevitch
你的返回类型为 int 的函数缺少了 return。不要这样做!(如果没有 return,返回类型应该是 void)但如果你从未使用返回值,则返回类型应该是 void - Jonathan Leffler
显示剩余3条评论
3个回答

6
我发现将全局变量视为一种特殊空间,存在于C程序正常函数层次结构之外,可以帮助理解。如果用每个函数的方框来绘制图表,并在方框之间连线显示程序执行过程中哪个函数调用了哪些其他函数,那么 main() 将位于顶部(因为它没有调用者),而所有其他函数都会出现在 main() 下面的某个层次上,与其它函数相连。

大多数数据仅存在于一个函数内——即在图表中的单个方框内。有些数据则从一个函数传递到另一个函数:大多数参数和返回值在像C这样的语言中都属于此类。但是全局变量则位于“所有方框之外”——任何函数都可以看到并更改它们,这种“开放性”使它们非常危险——如果任何函数中的任何代码都可以更改它们,那么对于您或对于在同一代码上工作的其他程序员来说,一旦程序变得真正庞大,就很难跟踪可能更改全局数据的所有可能位置。(这是编程语言普遍面临的“可变状态”问题,不仅仅局限于C语言,面向对象和函数式编程范式也在一定程度上解决了这个问题。)

在您的示例中,仅仅是因为您在问问题,

如果我想修改函数中的值并将其带回主函数,哪种方法更好?

这是一个线索,表明特定的值不应存储在全局变量中。您已经将此特定数据片段构想为仅在 main()example() 两个函数之间共享的内容。根据我上面给出的推理,这意味着如果可能的话,变量应作为参数传递给 example(),然后通过 example() 结尾处的 return 返回到 main()。在 C 中,将指向 a 的指针传递到 example(),然后在 example() 中修改 a,以便在控制返回调用者后改变 a,这是一种完全普通的习惯用法。但需要仔细记录哪些参数会以这种方式进行修改,否则您很快就会陷入与全局数据类似但不那么糟糕的情况,难以跟踪 a 可能发生的变化及其变化方式。

这并不是说全局变量都是坏的。它们存在有其原因。如果你的代码中许多部分需要对同一数据进行读/写访问,并且效率很重要,那么全局变量可能是实现这一点的最佳方式。在当今C语言运行最频繁的环境中——"接近硬件"的嵌入式系统或驱动程序代码中,通常会有硬件资源(如寄存器或专用内存),可以通过大量的全局变量最有效地访问。或者在某些程序中,您可能需要跟踪很多状态——一整套变量的值会影响整个程序的行为——传递这些值不仅效率低下,而且使程序清晰,因为您必须将相同的一组参数传递给大量的函数。(这的一个经典例子是游戏,其中游戏世界的当前状态、玩家位置、生命数等与大多数代码相关。)即使在这些情况下,关键是要很好地记录和命名全局变量,以便它们不会与其他类似命名的本地变量或函数参数发生冲突。

如果您想了解更高级但相关的主题,请参阅this answer进行简要说明,或this page进行更长时间的讨论,了解如何使用static关键字将C语言中全局变量的范围(即可见性)限制为单个源文件,或在多个文件之间共享。这样可以更精细地控制全局数据的可访问性,并有助于缓解我上面提到的一些关于自由使用全局变量的问题。


4
全局变量的问题是只有一个。一旦您的代码变得更加复杂,并开始使用多个线程,您将遇到一个问题,即只有一个全局变量,如果从两个线程调用函数,则会出现问题,因为两个调用都使用同一个全局变量。
另一个问题是全局变量需要一个唯一的名称。你把它叫做“sum”。从现在开始,你将有其他函数尝试将数字相加并将它们存储到名为sum的变量中的机会有多大?再次,你陷入了麻烦。如果您设法使用不同的变量名称,那么您选择错误的可能性有多大呢?
应该真正限制使用全局变量。仅将它们用于真正全局的事物,即在您的应用程序中永远不可能有两个意义的地方。

感谢您提供这样简明扼要的答案。 - deppep

0
在这种情况下,最好的做法是:
int example(int a, int b) 
 {
    return a + b;
 }


int main(void)
 {
    int a, b;

    printf("Tell me the value of A and B: \n");
    if (scanf("%d%d", &a, &b) == 2) /* Avoid Undefined Behavior */
     {
        int sum;

        sum = example(a, b);
        printf("The result: %d . And the new value of A: %d\n", sum, a);    
        printf("THE END\n");
     }
    return 0;
 }

当然,现实生活中的程序不会有这样的函数。
如果函数只是修改一个int,那么避免全局变量的另一个原因是,你可以从函数中返回它。如果情况更复杂,那么您也可以返回structs,并且如果它不符合您的需求,则可以传递/返回指针。

1
为什么不使用 int sum = example(a, b); 或者甚至是 printf("...", example(a, b), a); - Jonathan Leffler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接