1、程序员-C 语言程序设计(三)及答案解析(总分:100.00,做题时间:90 分钟)一、试题一(总题数:1,分数:15.00)阅读以下说明和 C 函数,填充函数中的空缺。说明函数 GetDateId(DATE date)的功能是计算并返回指定合法日期 date 是其所在年份的第几天。例如,date表示 2008 年 1 月 25 曰时,函数的返回值为 25,date 表示 2008 年 3 月 3 日时,函数返回值为 63。函数 Kday_Date(int theyear,int k)的功能是计算并返回指定合法年份 theyear(theyear1900)的第天(1k365)所对应的日期。例如
2、,2008 年的第 60 天是 2008 年 2 月 29 日,2009 年的第 60 天是 2009 年3 月 1 日。函数 isLeapYear(int y)的功能是判断 y 代表的年份是否为闰年,是则返回 1,否则返回 0。DATE 类型定义如下:typedef structint year,month,day;DATE;C 函数 1int GetDateId(DATE date)Const int days_month13=(0,31,28,31,30,31,30,31,31,30,31,30,31);int i,date_id=date.day;for(i=0;i_;i+)date_
3、id+=days_monthi;if(_isLeapYear(date.year)date_id+;return date_id;C 函数 2_Kday_Date(int theyear,int k)int i;DATE date;int days_month13=(0,31,28,31,30,31,30,31,31,30,31,30,31);assert(k=1k=365theyear=1900); /*不满足断言时程序终止*/date.year=_;if(isLeapYear(date.year)days_month2+;for(i=1;)k=k-davs_monthi+;if(k=0)(
4、date.day=k+_;date.month=i-1;break;return date;(分数:15.00)填空项 1:_填空项 1:_填空项 1:_填空项 1:_填空项 1:_二、试题二(总题数:1,分数:15.00)阅读以下说明和 C 程序,填充程序中的空缺。说明埃拉托斯特尼筛法求不超过自然数 N 的所有素数的做法是:先把 N 个自然数按次序排列起来,1 不是素数,也不是合数,要划去;2 是素数,取出 2(输出),然后将 2 的倍数都划去;剩下的数中最小者为 3,3 是素数,取出 3(输出),再把 3 的倍数都划去;剩下的数中最小者为 5,5 是素数(输出),再把 5 的倍数都划去。这
5、样一直做下去,就会把不超过 N 的全部合数都筛掉,每次从序列中取出的最小数构成的序列就是不超过 N 的全部质数。下面的程序实现埃拉托斯特尼筛法求素数,其中,数组元素 sievei(i0)的下标 i 对应自然数i,sievei的值为 1/0 分别表示 i 在/不在序列中,也就是将 i 划去(去掉)时,就将 sievei设置为 0。C 程序#include stdio.h#define N 10000int main()char sieveN+1=(0);int i=0,k;/*初始时 2N 都放入 sieve 数组*/for(i=2;_;i+)sievei=1;for(k=2;)/*找出剩下的数
6、中最小者并用 K 表示*/for(;kN+1sievek=0;_);if(_) break;print(“%d/t“,k); /*输出素数*/*从 sieve 中去掉 k 及其倍数*/for(i=k;iN+1;i=_)_;return 0;/*end of main*/(分数:15.00)填空项 1:_填空项 1:_填空项 1:_填空项 1:_填空项 1:_三、试题三(总题数:1,分数:15.00)阅读以下说明和 C 程序,填充函数中的空缺。说明N 个游戏者围成一圈,从 1N 顺序编号,游戏方式如下;从第一个人开始报数(从 1 到 3 报数),凡报到3 的人退出圈子,直到剩余一个游戏者为止,该
7、游戏者即为获胜者。下面的函数 playing(Linklist head)模拟上述游戏过程并返回获胜者的编号。其中,N 个人围成的圈用一个包含 N 个结点的单循环链表来表示,如图 1 所示,游戏者的编号放在结点的数据域中。在函数中,以删除结点来模拟游戏者退出圈子的处理。整型变量 c(初值为 1)用于计数,指针变量 p 的初始值为 head(如图 1 所示)。游戏时,从 p 所指向的结点开始计数,p 沿链表中的指针方向遍历结点,c 的值随 p 的移动相应地递增。当 c 计数到 2 时,就删除 p 所指结点的下一个结点(因下一个结点就表示报数到 3 的游戏者),如图 2 所示,然后将 c 设置为
8、0 后继续游戏过程。(分数:15.00)填空项 1:_填空项 1:_填空项 1:_填空项 1:_填空项 1:_四、试题四(总题数:1,分数:15.00)阅读以下说明和 C 函数,将应填入_处的语句或语句成分写在对应栏内。说明 1函数 deldigit(char*s)的功能是将字符串 s 中的数字字符去掉,使剩余字符按原次序构成个新串,并保存在原串空间中。其思路是:先申请一个与 s 等长的临时字符串空间并令 t 指向它,将非数字字符按次序暂存入该空间,最后再复制给 s。C 函数void deldigit(char*s)char*t=(char*)malloc(_); /*申请串空间*/int i
9、,k=0;if(!t) return;for(i=0;istrlen(s);i+=if(!(*(s+i)=0*(s+i)=9)tk+=_;_=/0 /*设置串结束标志*/strcpy(s,t);free(t);说明 2函数 reverse(char*s,int len)的功能是用递归方式逆置长度为 len 的字符串 s。例如,若串 s 的内容为“abcd”,则逆置后其内容变为“dcba”。C 函数void reverse(char*s,int len)char ch;if(_)ch=*s;*s=*(s+len-1);*(s+len-1)=ch;reverse(_);(分数:15.00)填空项
10、1:_填空项 1:_填空项 1:_填空项 1:_填空项 1:_五、试题五(总题数:1,分数:20.00)阅读以下说明和 C 代码,回答下面问题,将解答写在对应栏内。说明 1下面代码的设计意图是:将保存在文本文件 data.txt 中的一系列整数(不超过 100 个)读取出来存入数组arr,然后调用函数 sort()对数组 arr 的元素进行排序,最后在显示屏输出数组 arr 的内容。C 代码(分数:20.00)(1).以上 C 代码中有三处错误(省略部分的代码除外),请指出这些错误所在的代码行号,并在不增加和删除代码行的情况下进行修改,写出修改正确后的完整代码行。说明 2下面是用 C 语言书写
11、的函数 get_str 的两种定义方式以及两种调用方式。*(分数:10.00)_(2).若分别采用函数定义方式 1、2 和调用方式 1、2,请分析程序的运行情况,填充下面的空。若采用定义方式 1 和调用方式 1,则输出为“00000000”。若采用定义方式 1 和调用方式 2,则_。若采用定义方式 2 和调用方式 1,则_。若采用定义方式 2 和调用方式 2,则_。(分数:10.00)_六、试题六(总题数:1,分数:20.00)阅读以下说明和 C 函数,将应填入_处的语句或语句成分写在对应栏内。说明已知单链表 L 含有头节点,且节点中的元素值以递增的方式排列。下面的函数 DeleteList
12、在 L 中查找所有值大于 minK 且小于 maxK 的元素,若找到,则逐个删除,同时释放被删节点的空间。若链表中不存在满足条件的元素,则返回-1,否则返回 0。例如,某单链表如图 1 所示。若令 minK 为 20,maxK 为 50,则删除后的链表如图 2 所示。(分数:20.00)填空项 1:_填空项 1:_填空项 1:_填空项 1:_填空项 1:_程序员-C 语言程序设计(三)答案解析(总分:100.00,做题时间:90 分钟)一、试题一(总题数:1,分数:15.00)阅读以下说明和 C 函数,填充函数中的空缺。说明函数 GetDateId(DATE date)的功能是计算并返回指定合
13、法日期 date 是其所在年份的第几天。例如,date表示 2008 年 1 月 25 曰时,函数的返回值为 25,date 表示 2008 年 3 月 3 日时,函数返回值为 63。函数 Kday_Date(int theyear,int k)的功能是计算并返回指定合法年份 theyear(theyear1900)的第天(1k365)所对应的日期。例如,2008 年的第 60 天是 2008 年 2 月 29 日,2009 年的第 60 天是 2009 年3 月 1 日。函数 isLeapYear(int y)的功能是判断 y 代表的年份是否为闰年,是则返回 1,否则返回 0。DATE 类型
14、定义如下:typedef structint year,month,day;DATE;C 函数 1int GetDateId(DATE date)Const int days_month13=(0,31,28,31,30,31,30,31,31,30,31,30,31);int i,date_id=date.day;for(i=0;i_;i+)date_id+=days_monthi;if(_isLeapYear(date.year)date_id+;return date_id;C 函数 2_Kday_Date(int theyear,int k)int i;DATE date;int da
15、ys_month13=(0,31,28,31,30,31,30,31,31,30,31,30,31);assert(k=1k=365theyear=1900); /*不满足断言时程序终止*/date.year=_;if(isLeapYear(date.year)days_month2+;for(i=1;)k=k-davs_monthi+;if(k=0)(date.day=k+_;date.month=i-1;break;return date;(分数:15.00)填空项 1:_ (正确答案:date.month)解析:填空项 1:_ (正确答案:date.month2 或其等价形式)解析:填空
16、项 1:_ (正确答案:DATE)解析:填空项 1:_ (正确答案:theyear)解析:填空项 1:_ (正确答案:days_monthi-1或其等价形式)解析:本题考查的知识点是填写程序,本题的程序的功能是计算出某个日期为该年的第几天和某年的第几天是该年的几月几号。函数 1 是填写 GetDateId 这个函数,其中的 for 循环函数的功能是计算该日期是该年的第几天,所以第一空应填 date.month,但是是在普通年份下计算的,接下来的 if 条件语句是判断该年份是否为闰年,若为闰年且超过 2 月份,则需要在原来的基础上再加一天,若不是闰年或者没超过 2 月份则不用加一天,所以第二空应
17、填 date.month2。函数 2 是某年的第 k 天对应的日期,首先要定义下Kday_Date 函数,该函数符合 DATE 类型,所以用 DATE 定义该函数,第三空应填 DATE,第四空是将date.year 赋值为 theyear,所以应该填 theyear,接下来 k=k-days_monthi+是计算日期,如果k0,则 k=k-days_monthi+,若 k=0,则 date.day=days_monthi-1,故第五空应该填days_monthi-1。二、试题二(总题数:1,分数:15.00)阅读以下说明和 C 程序,填充程序中的空缺。说明埃拉托斯特尼筛法求不超过自然数 N 的
18、所有素数的做法是:先把 N 个自然数按次序排列起来,1 不是素数,也不是合数,要划去;2 是素数,取出 2(输出),然后将 2 的倍数都划去;剩下的数中最小者为 3,3 是素数,取出 3(输出),再把 3 的倍数都划去;剩下的数中最小者为 5,5 是素数(输出),再把 5 的倍数都划去。这样一直做下去,就会把不超过 N 的全部合数都筛掉,每次从序列中取出的最小数构成的序列就是不超过 N 的全部质数。下面的程序实现埃拉托斯特尼筛法求素数,其中,数组元素 sievei(i0)的下标 i 对应自然数i,sievei的值为 1/0 分别表示 i 在/不在序列中,也就是将 i 划去(去掉)时,就将 si
19、evei设置为 0。C 程序#include stdio.h#define N 10000int main()char sieveN+1=(0);int i=0,k;/*初始时 2N 都放入 sieve 数组*/for(i=2;_;i+)sievei=1;for(k=2;)/*找出剩下的数中最小者并用 K 表示*/for(;kN+1sievek=0;_);if(_) break;print(“%d/t“,k); /*输出素数*/*从 sieve 中去掉 k 及其倍数*/for(i=k;iN+1;i=_)_;return 0;/*end of main*/(分数:15.00)填空项 1:_ (正
20、确答案:iN+1 或其等价形式)解析:填空项 1:_ (正确答案:k+或+k 或其等价形式)解析:填空项 1:_ (正确答案:kN 或 k=N+1 或其等价形式)解析:填空项 1:_ (正确答案:i+k 或其等价形式)解析:填空项 1:_ (正确答案:sievei=0 或其等价形式)解析:本题要求是完成程序,该程序的功能是找到不超过自然数 N 的所有素数。首先在初始时 2N 都放入 sievre 数组中,所以 i 的取值范围为 2N,包含 N,所以第一空应该填 i 的最大取值为 N,所以(1)填iN+1 或者 i=N,并赋值 sievei=1,表示所有的数,无论是否为素数都放入数细中,接下来找
21、出剩下的数中最小者并用 K 表示,在 for 循环中,每执行一次循环就 k 值就要加 1,所以第二空应该填 k+或+k 或其等价形式,当循环执行到 kN 或 k=N+1 时,即 k 值超过了 N 值时,该循环结束用 break 跳出里面的循环语句,故第三空应该填 kN 或 k=N+1 或其等价形式,接下来输出素数,再删除素数的倍数,这也是一个循环语句,此时变量 i 是从 i 开始到 i+k 结束,所以第四空应填 i+k 或其等价形式,找到是素数的倍数后,再将该素数的倍数赋值为 0,从 sievei数组中划去,所以第五空应填 sievei=0 或其等价形式。三、试题三(总题数:1,分数:15.0
22、0)阅读以下说明和 C 程序,填充函数中的空缺。说明N 个游戏者围成一圈,从 1N 顺序编号,游戏方式如下;从第一个人开始报数(从 1 到 3 报数),凡报到3 的人退出圈子,直到剩余一个游戏者为止,该游戏者即为获胜者。下面的函数 playing(Linklist head)模拟上述游戏过程并返回获胜者的编号。其中,N 个人围成的圈用一个包含 N 个结点的单循环链表来表示,如图 1 所示,游戏者的编号放在结点的数据域中。在函数中,以删除结点来模拟游戏者退出圈子的处理。整型变量 c(初值为 1)用于计数,指针变量 p 的初始值为 head(如图 1 所示)。游戏时,从 p 所指向的结点开始计数,
23、p 沿链表中的指针方向遍历结点,c 的值随 p 的移动相应地递增。当 c 计数到 2 时,就删除 p 所指结点的下一个结点(因下一个结点就表示报数到 3 的游戏者),如图 2 所示,然后将 c 设置为 0 后继续游戏过程。(分数:15.00)填空项 1:_ (正确答案:1)解析:填空项 1:_ (正确答案:q-next 或 p-next-next)解析:填空项 1:_ (正确答案:0)解析:填空项 1:_ (正确答案:p-next)解析:填空项 1:_ (正确答案:p-code)解析:本题要求完成程序,该程序的功能是删除报号为 3 的结点,直到剩下一个结点为止。while 语句中的 n 的取值
24、范围从 1 到 N,又因为 while 语句先执行中括号里的语句在判断 n 值,所以第一空应填n1,while 语句中的 if 条件语句是判断 p 指向的下一结点是否该删除,若当 c 为 2 时,则 p 指向的当前结点报号为 2,p 指向的下个结点,即 p-next 的报号应为 3,该删除,这时应该将 p-next 的指向 c 为 3 的结点的下一个结点,即 p-next-next,再将 p-next 删除,所以第二空应该填 p-next-next,删除 p-next 之后将开始新一轮的报数,根据题意,将 c 值重新设置为 0 后继续,所以第三空对 c 重新赋值,应该填 0,此时,n 个数已经
25、删去一个数,所以 n 的值相应的要减少,if 语句执行完后,跳出 if 语句,将 p 重新赋值,即第四空 p=p-next,当从 1 到 n 都执行一遍后,会有一个人留下,即为获胜者,第五空是给获胜者编号赋值所以应该填 p-code,最后返回获胜者编号,该程序执行完毕。四、试题四(总题数:1,分数:15.00)阅读以下说明和 C 函数,将应填入_处的语句或语句成分写在对应栏内。说明 1函数 deldigit(char*s)的功能是将字符串 s 中的数字字符去掉,使剩余字符按原次序构成个新串,并保存在原串空间中。其思路是:先申请一个与 s 等长的临时字符串空间并令 t 指向它,将非数字字符按次序
26、暂存入该空间,最后再复制给 s。C 函数void deldigit(char*s)char*t=(char*)malloc(_); /*申请串空间*/int i,k=0;if(!t) return;for(i=0;istrlen(s);i+=if(!(*(s+i)=0*(s+i)=9)tk+=_;_=/0 /*设置串结束标志*/strcpy(s,t);free(t);说明 2函数 reverse(char*s,int len)的功能是用递归方式逆置长度为 len 的字符串 s。例如,若串 s 的内容为“abcd”,则逆置后其内容变为“dcba”。C 函数void reverse(char*s,
27、int len)char ch;if(_)ch=*s;*s=*(s+len-1);*(s+len-1)=ch;reverse(_);(分数:15.00)填空项 1:_ (正确答案:strlen(s))解析:填空项 1:_ (正确答案:si)解析:填空项 1:_ (正确答案:tk)解析:填空项 1:_ (正确答案:len1)解析:填空项 1:_ (正确答案:s+1,len-2)解析:函数 deldigit(char*s)的思路是先申请一个与 s 等长的临时字符串空间并令 t 指向它,则第一空完成该步骤。s 的长度用 strlen()函数求得,这个函数在题“istrlen(s)”中亦有提及。将非数
28、字字符按次序暂存入该空间,则程序的 for 循环完成该步骤。“*(s+i)=0*(s+i)=9”表示用 ASCI码逐个判断 s 中的字符是否为数字,如果是非数字,则该字符暂存入该空间 t。因此第二空中应填“si”。因为每次赋值之后,k 都自动加 1,所以,设置串尾结束符时,k 不必再加 1,直接将第三空填为“tk”。函数 reverse(char*s,int len),函数中又有 reverse 函数,说明本程序是个递归函数。那么需要判断该串是否为只含有 1 个字母的串。当长度大于 1 时,才需要继续递归,因此,第四空中应填“len1”。本函数逆置字符串的做法是将串的第一字符和最后一个字符对换
29、。然后递归剩下的字符串。因此,第五空中应填“s+1,len-2”。五、试题五(总题数:1,分数:20.00)阅读以下说明和 C 代码,回答下面问题,将解答写在对应栏内。说明 1下面代码的设计意图是:将保存在文本文件 data.txt 中的一系列整数(不超过 100 个)读取出来存入数组arr,然后调用函数 sort()对数组 arr 的元素进行排序,最后在显示屏输出数组 arr 的内容。C 代码(分数:20.00)(1).以上 C 代码中有三处错误(省略部分的代码除外),请指出这些错误所在的代码行号,并在不增加和删除代码行的情况下进行修改,写出修改正确后的完整代码行。说明 2下面是用 C 语言
30、书写的函数 get_str 的两种定义方式以及两种调用方式。*(分数:10.00)_正确答案:(14 行,应改为“FILE *fp”19 行,应改为 fscanf(fp,“%d“,arrnum+);21 行,应改为 sort(arr,num);)解析:(2).若分别采用函数定义方式 1、2 和调用方式 1、2,请分析程序的运行情况,填充下面的空。若采用定义方式 1 和调用方式 1,则输出为“00000000”。若采用定义方式 1 和调用方式 2,则_。若采用定义方式 2 和调用方式 1,则_。若采用定义方式 2 和调用方式 2,则_。(分数:10.00)_正确答案:(出错 山错 输出“test
31、ing”)解析:第一题中 fp 为文件打开后的指针,因此在定义时应定义为“FILE *fp”。14 行错误。fscanf 函数的格式为 int fscanf(FILE *strearn,char *format,address-list),因此第 19 行程序错误,fscanf 函数中第三个参数应该是个地址值。应改为“fscanf(fp,“%d“,arrnum+);”。在参数传递时,sort 函数的形参是数组地址,因此,在 main 函数中的实参应该也是数组地址 arr,21 行错误,应改为“sort(arr,num);”。第二题考查的是指针变量的定义。定义方式 1 中 p 是一个指向字符型变
32、量的指针。从而定义方式 1 中给 p赋值一个新创建的字符串,同时将“testing”复制给该字符串。即 p 指向“testing”字符串。而在定义方式 2 中,p 是一个指向字符型变量指针的指针,即 p 指向一个指针而该指针又指向一个字符型变量。*p这个指针所指内容与定义方式 1 中 p 指针所指内容一致,而 p 这个指针指向*p 这个指针。而在调用过程中,get str(ptr)传递的是指针,get_str(ptr)传递的是指针的地址。因此,只能用定义方式 1 调用调用方式 1,定义方式 2 调用调用方式 2,否则,由丁训用参数类型不匹配,出现错误。当采用定义方式 2和调用方式 2 时,参数
33、传递 ptr 指针的地址。指向 ptr 指针的指针所指内容中复制 testing 字符串,即ptr 指针单元中放的是 testing,当测试 ptr 时为空,执行 else 语句。输出 ptr 指针单元中存放的内容testing。六、试题六(总题数:1,分数:20.00)阅读以下说明和 C 函数,将应填入_处的语句或语句成分写在对应栏内。说明已知单链表 L 含有头节点,且节点中的元素值以递增的方式排列。下面的函数 DeleteList 在 L 中查找所有值大于 minK 且小于 maxK 的元素,若找到,则逐个删除,同时释放被删节点的空间。若链表中不存在满足条件的元素,则返回-1,否则返回 0
34、。例如,某单链表如图 1 所示。若令 minK 为 20,maxK 为 50,则删除后的链表如图 2 所示。(分数:20.00)填空项 1:_ (正确答案:Node*p,*q)解析:填空项 1:_ (正确答案:p-next)解析:填空项 1:_ (正确答案:p-next)解析:填空项 1:_ (正确答案:q-next)解析:填空项 1:_ (正确答案:delTag=0)解析:序的目的是删除链表中大于 20 和小丁 50 的数。首先 p,q 是首次出现,必须先定义,所以第一空中应填“Node*p,*q”。节点 p,q 中,q 指向所删节点的前驱,p 指向所删节点。如果,p 所指节点的数据大于 minK,则 p,q 点同时后移,即第二空填“p-next”。如果 p 所指节点的数据同时又小于 maxK,则删除该节点。q 直接连接 p 后面的节点,即第三空填“p-next”。当节点删除完成后,p 依然指向 q的后面节点,因此第四空填“q-next”。题中要求若链表中不存在满足条件的元素,则返回-1。delTag是时候对链表进行删除的标志。因此如果链表不存在满足条件的元素,delTag 为 0,因此,第五空中应填“delTag=0”。