预计阅读本页时间:-
现在您已经对不同的存储类有了一定的了解,我们来看几个使用这些存储类的程序。首先,来看一个随机数函数,该函数使用了一个具有内部链接的静态变量。ANSI C程序库提供了rand()函数来产生随机数。有多种产生随机数的算法,ANSI C标准允许C实现使用针对特定机器的最佳算法。不过,ANSI C也提供了一个可移植的标准算法,可以在不同的系统中产生相同的随机数。事实上,rand()是一个“伪随机数发生器”,这意味着可以预测数字的实际顺序(计算机不具有自发性),但这些数字在可能的取值范围内均匀地分布。
为了看清楚程序内部发生了什么,我们使用可移植的ANSI版本程序,而不是编译器内置的rand()函数。这一方案始于一个称为“种子”的数字。函数使用这个种子来产生一个新数,而这个新数又称为新的种子。接着,这个新种子被用来产生一个更新的种子,依此类推。这种方案要想行之有效,随机数函数必须记下上次被调用时所使用的种子。对,这需要一个静态变量。程序清单12.7中的程序是版本0(很快您将看到版本1)。
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
程序清单12.7 randO.c函数文件
在程序清单12.7中静态变量next的初始值为1,在每次调用函数时它的值被一个魔术般的公式修改。结果是一个在0到32767范围内的返回值。注意next是静态、具有内部链接的,而不只是静态、空链接的。这是为了稍后在将本例扩展时,便于next为同一文件中的两个函数共享。
我们用程序清单12.8所示的简单驱动程序来测试一下rand0()函数。
程序清单12.8 r_drive0.c驱动程序
现在又有一个机会来练习使用多文件。程序清单12.7和程序清单12.8分别使用一个文件。关键字extern提醒您rand0()在一个单独的文件中定义。输出如下:
输出看起来是随机的。但让我们再来运行一次,这次结果如下:
唔,看起来很像啊,这就是“伪”的特征了。每次运行主程序时,都从同一个种子值1开始。可以通过引入允许重置种子的第二个函数srand1()来解决这个问题。关键是使next成为一个具有内部链接的静态变量,并只对rand1()和srand1()可见(C程序库中与srandl()等效的函数被称为srand())。把srandl()添加到包含randl()的文件中。程序清单12.9给出了修改后的程序。
程序清单12.9 s_and_r.c程序
注意next是一个具有内部链接的文件作用域变量。这意味着它可以同时被randl()和srand1()使用,但不可以被其他文件中的函数使用。使用程序清单12.10中的驱动程序来测试这些函数。
程序清单12.10 r_drive1.c程序
又使用了两个文件。运行一次程序。
将1作为seed的值,产生了与前面相同的结果。现在来试试将3作为seed的值: