当我们可以选择将变量设为外部时,为什么我们通过引用传递?

时间:2010-10-26 17:03:15

标签: c pointers pass-by-reference

假设我们有一个数组说:

int arr[1000];

我有一个适用于该阵列的函数:

void Func(void);

当我可以将arr [1000]作为main()之外的外部变量时,为什么需要通过引用传递(通过更改void)?

  1. 有什么区别?有什么不同吗?
  2. 为什么人们更喜欢通过引用传递而不是将其作为外部传递? (我自己认为将它制作成外部更容易)。

9 个答案:

答案 0 :(得分:10)

如果使用全局变量arr,则Func仅限于始终与该一个变量一起使用,而不是其他任何变量。以下是可能导致错误的一些原因:

  • arr是您正在使用的“当前文档”的一部分,之后您决定要让您的程序支持打开多个文档。
  • 您稍后决定(或者某人使用您的代码作为库决定)使用线程,当两个线程在arr中相互破坏时,您的程序突然随机崩溃。
  • 你后来决定让你的代码成为一个库,现在它对调用者是有意义的(如果在一个程序中使用了多个点,以提供缓冲区);否则调用代码的独立部分就会知道彼此的实现。

一旦消除全局变量并使函数指向需要操作的数据,所有这些问题都会消失。

答案 1 :(得分:7)

我想你在问global variables are bad。引用an excellent answer

  

全局变量的问题是   因为每个功能都有访问权限   对于这些,它变得越来越难   找出实际的功能   读写这些变量。

     

了解应用程序的方式   工作,你几乎要采取   考虑到每个功能   修改全局状态。那可以   完成,但随着应用程序的发展   会越来越难以存在   几乎不可能(或至少是一个   完全浪费时间)。

     

如果您不依赖全局变量,   你可以在两者之间传递状态   根据需要不同的功能。那   你有更好的机会   了解每个功能的作用,   因为你不需要采取全球性的   国家考虑到了。

答案 2 :(得分:3)

如果arr是外部的,那么任何人都可以修改它,而不仅仅是Func。这是官方不好的。

传递参数可确保您知道要更改的数据以及更改数据的人。

编辑:官方坏处的意思是“通常不好,但并非总是如此。除非你有充分的理由,否则一般都不要这样做。”就像软件开发的所有其他“规则”一样:)

答案 3 :(得分:2)

通过使变量在函数外部,函数现在紧密耦合到定义变量的模块,因此在其他程序中更难重用。这也意味着你的函数只能在那个数组上工作,这限制了函数的灵活性。假设有一天您的需求发生变化,现在您必须使用Func处理多个数组。

通过将数组作为参数(以及数组大小)传递,该函数变得更容易解耦使用它(意味着它可以更容易被其他程序/模块使用) ,现在您可以使用该函数处理多个数组。

从一般代码维护的角度来看,函数及其调用者最好通过参数和返回值进行通信,而不是依赖于共享变量。

答案 4 :(得分:1)

这主要是范围问题;如果你把所有的变量都放在外部/全局的范围内,那么会有多么混乱?

不仅如此,您还将拥有大量的变量,这些变量在任何给定时间都不需要存在。传递函数参数而不是拥有大量的全局变量可以让你更容易地摆脱不再需要的东西。

答案 5 :(得分:1)

通过引用传递(而不是使用全局变量)使得读取代码的人更清楚该函数可能会更改数组的值。

此外,如果您想要在多个阵列上执行操作,您可以反复使用相同的功能,并且每次都会向其传递不同的数组。

另一个原因是,在编写多线程代码时,您通常希望每个线程专门拥有它必须处理的数据(共享可写数据很昂贵,如果没有正确完成,可能会导致竞争条件)。通过限制全局变量访问并创建局部变量和传递引用,您可以更轻松地编写更多线程(和信号处理程序)友好的代码。

举一个例子,让我们看一下简单的puts函数。

int puts(const char *s);

此函数将C字符串写入标准输出,这可能很有用。您可能会编写一些复杂的代码,使用puts输出有关在不同执行阶段执行操作的消息。

 int my_complicated_code( int x, int y, int z);

现在,假设您在程序中多次调用该函数,但其​​中一次您实际上不希望它写入标准输出,而是其他FILE *。如果您对[{1}}的所有来电实际上都是puts,而fputs需要一个FILE *来表示要打印到哪个文件,那么如果您将my_complicated_code更改为FILE *,这将很容易实现接受 int my_complicated_code(int x, int y, int z, FILE * out_file); 以及其他论据。

my_complicated_code

现在,您可以通过向FILE *传递对任何memcpy的引用(可以写作)来决定在打{{1}}时打印到哪个文件。

数组也是如此。如果{{1}}函数只将数据复制到一个特定位置,那么它就没用了。或者,如果它只从一个特定位置复制,因为它实际上需要两次引用数组。

为引用引用的函数编写单元测试通常更容易,因为它们不会假设它们需要的数据位置或名称是什么。您不必继续更新具有特定名称的数组来模拟您要测试的输入,只需为每个测试创建一个不同的数组并将其传递给您的函数。

在许多简单程序中,使用像这样的全局变量编写代码似乎更容易,但随着程序变大,情况并非如此。

答案 6 :(得分:1)

作为所有其他答案的补充,已经有充分的理由:编程中的每一个决定都是在不同优点和缺点之间进行权衡。几代程序员的数十年编程经验表明,在大多数情况下,全局状态是一件坏事。甚至还有一种围绕避免它的编程范式,将其置于避免状态的极端:

http://en.wikipedia.org/wiki/Functional_programming

目前你可能会觉得它更容易,但是当你的项目不断变得越来越大时,你会发现你已经为同时出现的问题实施了很多变通办法,你将会发现自己无法维护自己的代码。

答案 7 :(得分:0)

  1. 范围有所不同。如果你声明“int arr [1000]” 例如,在main()中,您无法在函数“another_function()”中访问它。您必须通过引用显式传递它,以便您在其中使用它。如果它是外部的,那么每个功能都可以访问它。

  2. 见(1。)

答案 8 :(得分:0)

这也是一个维护问题。当我只能查看函数并看看它应该是什么时,我为什么要在某处跟踪某些外部?