在 C 中通过引用传递或使用全局变量

Passing by reference or use global variable in C

如果我想把值修改成一个函数,再带回main,用哪个比较好?说在 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;
}

在这种特殊情况下,最好的办法是

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 这是避免全局变量的另一个原因,因为你可以从函数中 return 它,如果情况更复杂,那么你return structs 也可以,如果它不符合您的需要,您可以 pass/return 指点。

全局变量的问题是只有一个。一旦你的代码变得有点复杂,并开始使用多线程,你 运行 就会陷入只有一个全局变量的问题,如果从两个线程调用该函数,就会有麻烦,因为两个调用都使用一些全局变量。

全局变量的另一个问题是它需要一个唯一的名称。你打电话给你的 "sum"。从现在开始的某个时间,您将有其他函数将数字相加并尝试将它们存储到名为 sum 的变量中的可能性有多大?再一次,你有大麻烦了。如果您设法使用不同的变量名,那么您选错一个的可能性有多大?

全局变量的使用确实应该受到限制。仅将它们用于真正全局的事物,即在您的应用程序中拥有两个没有任何意义的地方。

我发现将全局变量视为存在于 C 程序中正常函数层次结构之外的一种特殊 space 中会有所帮助。如果你画了一个图表,每个函数都在一个方框里,方框之间的线条显示了在程序执行期间哪个函数调用了哪个其他函数,main() 将在顶部(因为它没有调用者),并且所有其他功能会出现在 main() 下方的某一层或另一层,并带有通向其上方其他功能的线。

大多数数据只存在于一个函数中——在图中的一个框内。有些是从一个函数传递到另一个函数:大多数参数和 return 语言中的值(如 C)都属于这一类。但是全局变量是"outside all the boxes"——在一个任何函数都可以看到和改变它们的地方,而这个"openness"让它们变得非常危险——如果任何函数中的任何代码都可以改变它们,那就很难了对于您或使用相同代码的其他程序员,一旦它达到真实世界的大小,就可以跟踪所有可能更改全局数据的地方。 (这是 "mutable state" 的问题,它在一般编程语言中都很常见,而不仅仅是 C,面向对象和函数式编程范例在一定程度上解决了这个问题。)

在你的例子中,只是你在问这个问题

Which one is better if I want to modify the value into a function and bring it back to the main?

提示该特定值不应存储在全局变量中。您已经将这个特定的数据概念化为仅在两个函数 main()example() 之间共享的东西。按照我上面给出的推理,这意味着如果可能的话,变量应该作为参数传递给 example(),然后通过 return 将 returned 到 main()example() 结束时。将指向 a 的指针传递到 example(),然后在 example() 中修改 a,以便在控制 return 之后对 a 的更改仍然存在调用者,在 C 中是一个非常普通的习语。但是需要仔细记录哪些参数以这种方式进行修改,否则您很快就会遇到像全局数据那样的情况,只是没有那么糟糕,它在哪里很难跟踪 a 可能会更改的位置以及可能更改的内容。

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

有关更高级但相关的主题,请参阅 this answer for a brief explanation, or this page 进行更长时间的讨论,关于如何使用 static 关键字,或跨多个文件共享。这对全局数据的可访问性提供了更细粒度的控制,并有助于减轻我上面提到的对免费使用全局变量的一些担忧。