第16题  整除问题1

试编写函数fun,通过形参x接收一个整数,求出能整除x的全部偶因数,通过int指针p把求出的因数由小到大存储于main的数组中,通过int指针n把所求因数的个数存储于main的变量中。

例如:若x接收90,则fun所求出的偶因数为2,6,10,18,30,90,总个数为6。

注意:部分源程序在PROG1.C中,请勿改动已给定的任何内容,只在函数fun的指定位置填入你编写的若干语句。

PROG1.C:

PROG16-01

参考答案:

PROG16-02

运行结果:

PROG16-03

程序解析:

在程序执行期间,函数main和fun各自维持自己的局部变量和形式参数变量,当fun被调用时,fun的形参变量首先通过传值方式从其调用者main那里获取初值,因此函数形参在本质上是具有初值的局部变量,main和fun各自局部变量所占存储的总和构成各自的存储区,如下图所示:

PROG16-04

要注意的是,在C语言中,各个函数各自为政,各自的局部变量可以同名而不会互相冲突,而且调用者的实参与被调函数的形参同名是C程序员的编程习惯之一。只要心里清楚它们虽然同名却是不同的对象,习惯之后,反而提高程序易读性。在本题中,main和fun均有int变量x、均有int指针p(亦可称int数组p),此外,main有int变量n,而fun有int指针n,它们或者同名同类型,或者同名不同型。

C语言把数组名定义为指向首元素的常量指针,只供引用但不能被改变,该指针的存储空间是(在含有数组名的表达式求值过程中)临时自动分配的,并不是数组存储块的组成部分,因此,p是指向第0元素的整型常量指针,必须通过指针式∗(p+i)才能访问数组p的第i元素,但也可采用下标式p[i]访问p的第i元素,p[i]会自动转换为∗(p+i)。机器内存是一维连续字节阵列,数组元素连续占据一段内存,数组下标从0开始。

当main调用fun时,第一项工作就是完成实参向对应形参传值,其实就是一种赋值。main的int变量x当前值90传值于fun的int形参x使之也为90;main的数组名p当前指向main的数组首元素,传值于fun的int指针形参p使之也指向main的数组首元素;main的int变量n的地址&n(int指针),传值于fun的int指针形参n使之指向main的变量n。上图所示即为传值工作完成后的效果。声明int  p[ ]; 和声明int  ∗p; 是一回事。

有了上面的概念,理解程序就很容易了。变量j初值为0,既充当数组下标,又充当所求因数个数计数器。for循控变量i依次取2,4,6,…,等偶数直到x,在这一循环过程中,用i的每个当前取值去试除x,若能整除(条件x%i == 0为真),则将i的当前值转储于下标j指示的元素p[j]之中,而后使j加1,既指示下一个因数的存储位置,又实现对刚刚存储因数的计数。当for循环结束后,j的当前值就是所求因数的总个数6,借助于指针n将其存储于main的变量n之中,这是由语句∗n = j; 完成的,如上图所示。

知识点:

① 函数参数传值的含义。

② 数组名与指针的等价性。

③ 数组元素的两种存取方式。

④ 被调函数可通过指针形参存取调用者存储区域内的变量或对象,从而实现将计算结果反馈给调用者。fun通过其指针p访问main的数组p,通过指针n访问main的变量n。

⑤ 函数局部变量与函数存储区的概念。

⑥ 不同函数的局部变量可以同名而不会相互冲突。

练习题:

试改变代码行for (i = 2; i <= x; i += 2)中的i = 2,为自己命新题,举一反三。

返回