第1题  串−数转换

本题程序中,函数fun通过字符型指针形参a、b接收两个数字字符串,把它们分别转换为面值相等的长整数,再将二者之积作为函数值返回。

例如:fun接收数字串″41638″″13579″,返回长整数565402402。

请在程序的下划线处填入正确内容并把下划线删除,使程序得出正确结果。注意:源程序存放在考生文件夹下的BLANK1.C中。 不许增行或删行,也不许更改程序结构。

BLANK1.C:

BLANK1-01

参考答案:

BLANK1-02

运行结果:

BLANK1-03

程序解析:

#include <stdio.h>

#define N 10

文件包含预处理指令#include <stdio.h>支持标准库函数printf、gets的正常调用。程序要调用某个库函数,就必须包含与之对应的头文件。预处理指令通常位于源文件开头处,单独占一行,行尾无标点。

宏定义预处理指令#define N 10定义标识符N为字符序列10,在程序下文中,N的每次出现均被自动替换成字符序列10,这种标识符叫做符号常量或宏。例如:main中的s1[N]经替换变成s1[10]

程序从函数main开始执行。声明:

char s1[N], s2[N];
long l;

定义长度为N即10的字符型数组s1、s2,分配存储,不作初始化,用于从标准输入设备(通常是键盘)读取数字字符串。定义长整型变量 l,分配存储,不作初始化,用于接收函数fun的返回值。凡未经初始化的变量,其初值无意义,仅反映新分配内存的当前随机性物理状态。至此,当前存储状态如下图所示,变量的无意义垃圾值以空白表示。C语言把数组名定义为指向首元素的常量指针,只供引用但不能被改变,该指针的存储空间是(在含有数组名的表达式求值过程中)临时自动分配的,并不是数组存储块的组成部分,因此,s1是指向第0元素的字符型常量指针,必须通过指针式∗(s1+i)才能访问数组s1的第i元素,但也可采用下标式s1[i]访问s1的第i元素,s1[i]会自动转换为∗(s1+i)。机器内存是一维连续字节阵列,数组元素连续占据一段内存,数组下标从0开始。若p是字符型指针变量且指向某字符元素,则可通过∗p访问p所指向的字符。

BLANK1-04

在函数main中,首先执行下列语句:

printf(″请输入第1个数字串: ″);
gets(s1);
printf(″请输入第2个数字串: ″);
gets(s2);

printf语句在标准输出设备(通常是显示器)给出提示,gets语句从标准输入设备(通常是键盘)读取两行字符(以换行符′\n′结尾、对应键盘上的回车键)、存储于字符型数组s1和s2中、并以空字符′\0′取代换行符′\n′。至此,当前存储状态如下图所示。

BLANK1-05

然后,执行下面函数调用语句:

l = fun(s1, s2);

以数组名s1、s2(自动转换为字符指针)为实参调用函数fun,于是,main的执行被挂起(暂停),函数fun开始执行。首先,为形参变量a、b分配存储,完成参数传递:将main中的数组s1、s2的第0元素的地址值(即指向第0个字符元素的指针)分别复制于fun的形参a、b,即让fun的指针a、b分别指向main中的数组s1、s2的第0字符元素,以便通过fun中的指针a、b来访问main中的数组s1、s2。

BLANK1-06

在函数fun中,形参a、b也是fun的局部变量。局部变量分属不同的函数fun和main、分别存在于不同的存储空间、各有自己的作用域。局部变量只能在其所属函数中访问。

在函数fun中,执行其唯一语句:

return stod(a) ∗ stod(b);

分别以实参a、b调用函数stod,将数字字符串a、b先后转换成面值相等的长整数,再计算这两个长整数的乘积,并作为函数值返回其调用者main。

不妨先看以字符指针变量a为实参调用函数stod的过程。以字符指针变量a为实参调用函数stod,于是,fun的执行被挂起(暂停),函数stod开始执行。首先,为形参变量s分配存储,完成参数传递:将fun中的字符指针a(即指向main的数组s1的第0字符的指针)复制于stod的形参s,即让stod的指针s也指向main中的数组s1的第0字符元素,以便通过stod的指针s来访问main中的数组s1。

在函数stod中,声明:

long d;

定义长整型变量d,分配存储,不作初始化,用于辅助计算与数字字符串s面值相等的长整数值。至此,当前存储状态如下图所示。形参s是stod的局部变量。局部变量分属不同的函数main、fun和stod、分别存在于不同的存储空间、各有自己的作用域。局部变量只能在其所属函数中访问。

BLANK1-07

在函数stod中,首先执行下面语句:

for (d = 0; ∗s; s++)
­      d = d∗10 + ∗s−′0′;

先执行d = 0(仅一次)将d初始化为0,为后续操作做好准备。接着就是循环执行过程:判别∗s的值,若为真,即不等于0,则执行循环体语句d = d∗10 + ∗s−′0′;,再执行s++,如此反复,直到∗s的值为假(变成0)时,循环终止。这个循环过程能把数字字符串″41638″转换成长整数41638。

转换算法为  41638 = ((((0×10+4)×10+1)×10+6)×10+3)×10+8,即从0开始,反复乘10再加各位数字值的循环。

循环开始前,d已被清0,且s已指向首字符 ′4′。先看首轮循环,因∗s的值不等于0(在机器字符集中,只有空字符′\0′的值为0),执行d = d∗10 + ∗s−′0′;将∗s−′0′的数值4赋于变量d中,接着执行s++令指针s加1指向下一字符 ′1′,如此循环,∗s依次取数字字符′4′′1′′6′′3′′8′,而 ∗s−′0′ 依次取数字字符的字面数值4、1、6、3、8(因为从′0′′9′十个数字字符的机器内码值是连续递增的,其ASCII码从48连续递增到57)。当s指向空字符′\0′时,∗s取值为0,循环终止。由于d的初值为0,for语句实现了从0开始反复乘10再加各位数字值的循环。当for循环结束时,变量d的值即为面值相等的长整型数值41638。至此,当前存储状态如下图所示:

BLANK1-08接着执行下面语句:

return d;

将转换所得d的值41638作为函数值返回调用者fun,函数stod执行结束,同时收回其存储空间。至此,当前存储状态如下图所示:

BLANK1-09

函数stod返回后,fun从挂起点即语句return stod(a) ∗ stod(b);处恢复继续执行,将stod的返回值41638暂存于自动生成的临时变量中。至此,当前存储状态如上图所示。

接着,按照上面同样的方式,以字符指针变量b为实参调用函数stod,于是,fun的执行再次被挂起(暂停),函数stod再次开始执行。首先,为形参变量s再次分配存储,完成参数传递:将fun中的字符指针b(即指向main的数组s2的第0字符的指针)复制于stod的形参s,即让stod的指针s也指向main中的数组s2的第0字符元素,以便通过stod的指针s来访问main中的数组s2。

在函数stod中,声明:

long d;

再次定义长整型变量d,分配存储,不作初始化,用于辅助计算与数字字符串s面值相等的长整数值。至此,当前存储状态如下图所示。形参s是stod的局部变量。局部变量分属不同的函数main、fun和stod、分别存在于不同的存储空间、各有自己的作用域。局部变量只能在其所属函数中访问。

BLANK1-10

在函数stod中,再次执行下面语句:

for (d = 0; ∗s; s++)
­      d = d∗10 + ∗s−′0′;

这个循环过程能把数字字符串″13579″转换成长整数13579。

转换算法为  13579 = ((((0×10+1)×10+3)×10+5)×10+7)×10+9,即从0开始,反复乘10再加各位数字值的循环。

for循环结束时,变量d的值即为面值相等的长整型数值13579。至此,当前存储状态如下图所示:

BLANK1-11

接着执行下面语句:

return d;

将转换所得d的值13579作为函数值返回调用者fun,函数stod执行结束,同时收回其存储空间。至此,当前存储状态如下图所示:

BLANK1-12

函数stod返回后,fun从挂起点即语句return stod(a) ∗ stod(b);处恢复继续执行,将stod的返回值13579暂存于自动生成的另一临时变量中。至此,当前存储状态如上图所示。接着,将这两个临时变量的值相乘,并把所得乘积565402402暂存于自动生成的另一临时变量中。至此,当前存储状态如下图所示:

BLANK1-13

紧接着,将所得乘积565402402作为函数值返回调用者main,函数fun执行结束,同时收回其存储空间。至此,当前存储状态如下图所示:

BLANK1-14

函数fun返回后,main从挂起点即语句 l = fun(s1, s2);处恢复继续执行,将fun的返回值565402402赋值于变量 l 中。至此,当前存储状态如上图所示。接着执行下面语句:

printf(″结果是: %ld\n″, l);

将所求结果即变量 l 的值565402402以适当格式输出。由于这是main的最后语句,随即函数main执行结束、同时收回其存储空间。

知识点:

① 程序执行是动态过程,语句不断执行,变量值不断变化,同时伴随函数局部变量(含形参变量)的创生与消亡。当函数进入时,局部变量因自动分配存储而创生;当函数返回时,因自动收回存储而消亡。形参变量经参数传递获得初值且有意义,非形参局部变量若未经显式初始化,则其初值无意义,称为垃圾值,仅反映新分配内存的当前随机性物理状态。参数传递发生在函数进入后、函数的语句开始执行前,实参表达式(含变量)的值被复制于形参变量之中,名曰″传值″。不同函数的局部变量可以同名,不会冲突,驻留各自的存储空间,只能被所属函数自己的语句访问,这就是局部变量的作用域。函数通过对形参指针的间接引用可以访问调用者函数内的变量,是函数之间双向通信的重要方式,既能从调用者接收数据,又能向调用者回送计算结果。函数通过非指针形参只能从调用者函数接收数据,通过函数返回值只能向调用者回送计算结果,都只是单向通信。

② 将复杂任务分解为多个简单任务的″分而治之″程序设计思想,具体表现为函数 main读取两个数字串,以其为参数调用函数fun完成串-数转换并求积的任务,而函数fun又将串-数转换的子任务分解出来,并交由函数stod去完成。

③ 函数通过字符型指针接收并处理字符串(即字符数组),如 fun(char ∗a, char ∗b)和stod(char ∗s), 也可采取其等价形式: fun(char a[ ], char b[ ] ) 和 stod(char s[ ] ),作为函数形参的char数组名等价于char指针。

④ 在for语句中,循环条件是∗s,当s指向′\0′时,∗s取值为0,意为逻辑假,循环终止;当s指向其它字符时,∗s取值非0,意为逻辑真,循环继续。循环条件∗s的等价形式为∗s != 0。

在C语言中,逻辑表达式的结果类型为int,结果值只取0或1,结果取0表示逻辑假,结果取1表示逻辑真。充当whileforif等语句的条件表达式,可以是任何数值型表达式,包括字符型、整型、浮点型(实型),其值为0视为逻辑假,其值非0视为逻辑真。

′\0′ 的数值的确是 0,之所以写成 ′\0′ 是为了强调其字符本性。当它在表达式中出现时,其类型为 int;当它在字符串或字符数组中被存储时,其类型为 char

⑥ 设char变量 c 存储 ′0′′9′ 的任一数字字符,则表达式 c−′0′ 的值就是相应字符的字面­数值,其类型为 int。这是因为从′0′′9′十个数字字符的机器内码值是连续递增的。例如:在ASCII字符集中,其编码从48连续递增到57。

⑦ 字符数组与字符串的关系。字符数组是用来存储字符数据的,每个元素可以存放机器字符集的任一字符。长度为n的字符串是长度为n+1的字符数组,最后一个字符必须是空字符′\0′,空字符′\0′不计入字符串长度,这是C语言的规定,供程序检测是否到达串尾之用。长度为n的字符数组,可以容纳n个任意字符,因此可以存储长度小于或等于n−1的任意字符串。

⑧ 设有字符指针p,且已指向字符数组内某字符元素,那么,++p使p指向下一字符元素,而−−p使p指向上一字符元素。

凡字符串处理程序,通常采用字符指针扫描字符串的方法解决问题。扫描终止的标志就是遇到串尾标记空字符′\0′,而空字符′\0′的机内码值的确为0。像′\0′′\n′′a′等字符常量以及其它字符变量,当出现在表达式中时,自动转换为int类型。

⑨  设有字符指针变量p,且已指向某字符变量(设其值为字符′A′),则可通过∗p间接访问p所指的字符。所谓指针p ″指向″ 某变量,就是p中存储着那个变量的地址值。MODI3-08在这种情形下,可通过∗p间接访问p所指的字符′A′,即字符变量∗p的值是′A′,注意:p和∗p是两个不同类型的变量,p的类型是字符指针类型,即char ∗类型,而∗p的类型是字符类型,即char类型。设另有字符指针变量s,且已指向某字符变量(设其值为字符′B′),同理,字符变量∗s的值是′B′

⑩  库函数char  ∗gets(char  ∗s),需要头文件stdio.h支持。

从标准输入设备(通常是键盘),读取下一输入文本行于字符数组s中,并用空字符′\0′替代换行符′\n′,返回s。若遇文件尾或发生错误,则返回NULL。

库函数int  puts(const  char  ∗s),需要头文件stdio.h支持。

向标准输出设备(通常是显示器),输出字符串s的内容之后,再输出换行符′\n′。若发生错误,则返回EOF,否则返回一个非负值。

NULL和EOF是头文件stdio.h中定义的符号常量。NULL常定义为0,表示不指向任何对象的空指针,充当程序测试的标志值。EOF常定义为−1,也是一个标志值。

练习题:

试改变代码行 return stod(a) ∗ stod(b);中的适当内容,试将for语句改写为while语句,为自己命新题,举一反三。

 返回