马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
一、选填部分
第一题:
下面四个选项中,均是不正当的用户标识符的选项是( )
A. A P_0 do
B. float la0 _A
C. b-a sizeof int
D. b_a temp _123
思绪提示:题中所问的是"不正当"的"用户标识符",要记得,C语言中的关键字是不能作为用户标识符的~
答案:C
解析:根据C语言种标识符的规定来看:A选项中的P_0是正当的,do是关键字,非法。B选项种laO,_A是正当的,float是关键字,非法。C中b-a非法,因“-”不是标识符中的有效字符,sizeof和int均是关键字,非法。D中123、temp是正当的,int是关键字非法。故只有C全错,所以选择C。
第二题:
假如x=2014,下面函数的返回值是( )
- int fun(unsigned int x)
- {
- int n = 0;
- while (x + 1)
- {
- n++;
- x = x | (x + 1);
- }
- return n;
- }
复制代码 思绪提示:此题的考点是位操纵符的知识点,题中的" | "符号是"或"操纵符,它的作用是:两个数字的二进制形式上各位对比,只要有1就为1。而while循环中的 x = x | (x + 1) 所代表的是什么意思?各人要仔细思索一下~
答案:23。
解析:对于解题的关键,我们需要知道 x = x | (x + 1) 所代表的意思,让我们将此函数fun里带入2014,让我们观察一下2014在fun中的各种变化是什么样的:
我们可以看出,x从第二次往后都是以2的某次方减一的形式输出,而造成此等变化的内部缘故原由,让我们转换成二进制来看一看。
- x -> 00000000 00000000 00000111 11011110 (2014)
- x+1 -> 00000000 00000000 00000111 11011111
- x | (x + 1) = 00000000 00000000 00000111 11011111 (2015)
- x -> 00000000 00000000 00000111 11011111
- x+1 -> 00000000 00000000 00000111 11100000
- x | (x + 1) = 00000000 00000000 00000111 11111111 (2047)
-
- ......
复制代码 由此过程我们可以看出,x = x | (x + 1) 的作用是将数字的二进制形式从右往左第一个0变成1,而while的循环条件为(x + 1),也就是说当x的二进制位数全部为1,也就是x=-1时,才能跳出循环,而最开始x=2014,有9个1,(32 - 9) = 23次转换,n = 23。
第三题:
下面步伐执行后输出结果为( )
- #include<stdio.h>
- int main()
- {
- int i, j, m = 6, n = 4, * p = &n, * q = &m;
- i = p == &m;
- j = (-*p) / (*q) + 7;
- printf("i=%d,j=%d\n", i, j);
- return 0;
- }
复制代码 思绪提示:此题重点考察运算符优先级,解题的关键在于知道 i = p == &m 的运算顺序。知道了运算顺序天然就能轻松解题。
答案:i=0,j=7。
解析:i = p == &m;
从后结合,先计算 p==&m,p 显然是n,前后两者不相称,返回结果为了false,便是0,所以i=0;
j=(-*p)/(*q)+7;
j=(-n)/m+7,先计算除法,(-n)/m=0,j=0+7=7:所以i即是0,i即是7。
第四题:
在C语言中,以下代码执行之后,*p的值为( )
- void func(int* p) {
- static int num = 4;
- p = #
- (*p)--;
- }
- int main()
- {
- int i = 5;
- int* p = &i;
- func(p);
- printf("%d", *p);
- return 0;
- }
复制代码 思绪提示:注意观察,思索一下形参指针和实参指针之间值的关联,并且需要注意,在一些情况下函数中的值在退出函数后会被烧毁的。
答案:5
解析:当调用函数的时间,形参指针p会指向实参指针p所指向的地址空间。而其实修改形参p所指向的地址空间并不会影响实参指针p和i。这是因为:最开始形参指针p指向实参指针p所指向的地址空间,但在标题的 func 函数中,形参指针p 指向了新的地址空间num,如下图:
故修改形参p所指向的地址空间的值并不会影响实参指针p和i的值。
第五题:
下面代码的输出为( )
- #define MAX(a,b)((a)>(b)?a:b)
- int main()
- {
- int a = 5, b = 0;
- int c = MAX(++a, b);
- int d = MAX(++a, b + 10);
- printf("%d %d %d %d\n", a, b, c, d);
- return 0;
- }
复制代码 思绪提示:注意观察define界说MAX后,调用MAX(++a,b)时,在函数MAX中的自增与赋值的先后顺序是什么?
答案:8 0 7 10
解析:第一次调用MAX时,++a先执行了一次,此时a为6,由于满足宏界说中(a)>(b)的条件所以执行a,这个a就对应++a,所以a又自增了一次,变为7,由此得出c为7。第二个MAX时a又自增了一次,此时为8,由于不满足条件,所以执行的是宏界说中的b,没有执行++a,所以a最终为8所以答案是8 0 7 10。注意 ++a) > b ? (++a) : b (++a先自增,后赋值)。
二、编程题部分
第一题:币值转换
输入一个整数(位数不超过9位)代表一个人民币值(单位为元),如23108元,转换后变成“贰万叁仟壹百零捌”元。a-j代表数字0-9,S、B、Q、W、Y代表拾、百、仟、万、亿。
- 输入样例:
- 813227345
- 输出样例:
- iYbQdBcScWhQdBeSf
- 输入样例:
- 6900
- 输出样例:
- gQjB
复制代码 思绪提示:这道题各人读完后大概以为文思泉涌,想着只要判断了位数,每位输出对应大写字母,数组输出对应小写字母就好了嘛~但实则此题并没有看起来这么简朴,对于许多的细节方面照旧需要多多思索推测的。
① 我们在读数字的时间,需要从高位往低位读,假如用整形变量来吸收数字的话,那么%10/10的操纵只能从后往前取各位数,访问的时间注意需要逆向访问,还需要界说一个变量储存数字的位数。假如想使用数组来吸收数字的话,那么整型数组无法做到将输入的一个数字,一位一位的存在每个元素,所以还需要使用字符型数组来接受,在后续操纵中需要 - '0' (或者再创建一个整型数组,将每一个字符型 - '0'并存入,能简朴一点儿)。(但反正就是咋做咋麻烦...)
② 有时我们需要读零,但有时间不能够读零,比如6901,读出来是六千九百零一,打印gQjBab,这种情况需要读零,但是6900,读出来就是六千九百,打印gQjB。
③ 正常的位数应该是十,百,千,万,十万,百万,千万,亿。而此中十万,百万,千万需要使用两个大写字母来体现。注意!并不是这三个位数都要加W的,而是停止到哪位,哪位后面才加W,比如11115000,读出来是一千一百一十一万五千,打印出来就是bQbBbSbWfQ,但假如是11005000,读出来就是一千一百万零五千,输出W的位数也要往前挪一位,打印出来就是bQbBWafQ。
答案:
- int main()
- {
- int i;
- int j;
- char str1[11] = "abcdefghij";
- char str2[10] = "0SBQWSBQY";
- int num = 0;
- scanf("%d", &num);
- int N1 = num;//用来算长度的 就用了一次 不重要
- int N2 = num;//用来把数字传进数组的 就用了一次 不重要
- int sum = 0;//此数字的长度
- do
- {
- sum++;
- N1 /= 10;
- } while (N1);
- int arr[sum];//用于存储数字的每一位数
- int numd = 0;//记录"万"以上位数的数字个数
- int num4 = 0;//记录是否输出过"W"
- for (i = 0; i < sum; i++)
- {
- arr[i] = N2 % 10;
- if (sum - i <= 6 && arr[i] != 0)//最大位数 - i <= 6 代表是"万"以上位数的数字
- numd++;
- N2 /= 10;
- }
- for (i = sum - 1; i >= 0; i--)
- {
- if (sum == 1 && arr[i] == 0)//应对只输入0
- printf("a");
- else if (arr[i] != 0)
- {
- printf("%c", str1[arr[i]]);
- if (str2[arr[i]] != '0' && i != 0)
- {
- printf("%c", str2[i]);
- if (str2[i] == 'W')//题中只输出一次'W',若输出过了则记录,后续不再输出
- num4++;//(因为正常来说 i=4 时 才输出'W',但有时arr[4]=0 就不会输出W)
- if (i >= 3)//(但是例如10001000这类数字,虽然arr[4]=0,但输出需要有W)
- numd--;//(所以我们记录是否输出了W,若遍历到i=4时仍未输出,则输出W)
- }
- }
- else if (arr[i] == 0)
- {
- if (arr[i - 1] != 0 && i != 0)
- printf("%c", str1[arr[i]]);
- if (numd <= 0 && num4 == 0)
- {
- printf("%c", str2[4]);
- num4++;
- }
- }
- }
- return 0;
- }
复制代码 解析:读完上面提示出的三个注意点,我们顺着这几条思绪对代码进行功能编译。
① 我们先界说一个整形变量num来吸收数字,再然后创建N1,N2,用来分别计算数字长度和将数字传进整型数组中。我们存进的数字恰好是从低位到高位的逆序,而我们界说的存储位数大写字母的字符串str2是"0SBQWSBQY",在进行打印的时间也是逆序打印的,两者访问顺序一致,则用for循环的逆序遍历操纵即可(在遍历时顺便记录大于万的位数中,非零的个数)。
② 我们在后续要打印结果字符串的时间,可以对0的后一位进行判断,就比如60001,读作六万零一,而60000读作六万,也就是说在0后一位也是0的时间,此0不读,但假如0后一位非零,那么此0需要读,条件也就是if (arr[i - 1] != 0 && i != 0)。
③ 在进行打印的时间,W位是一个比较特别的位,他不像其他位数,只看对应数字是否为零就能决定输出与否,在输入的数字大于10000时,此数字的输出就必须带W,正常来说 i=4 时,就会输出'W',但有时arr[4]=0,就不会输出W,所以为了稳定的输出W,我们需要界说一个变量来记录W是否输出,假如在i = 4时W还没有输出,那么就自行输出W~
第二题:阅览室
编写一个简朴的图书借阅统计步伐,借书时输入S键,步伐开始计时。还书时输入E键,步伐竣事计时。书号的范围必须是[1,1000],当以0作为书号输入时体现一天的工作竣事。请你编写的步伐能够输出当天的读者借书次数和匀称阅读时间。
- 输入样例:
- 3
- 1 S 08:10
- 2 S 08:35
- 1 E 10:00
- 2 E 13:16
- 0 S 17:00
- 0 S 17:00
- 3 E 08:10
- 1 S 08:20
- 2 S 09:00
- 1 E 09:20
- 0 E 17:00
- 输出样例:
- 2 196
- 0 0
- 1 60
复制代码 思绪提示:此题照旧稍微复杂的(仅代表本编程小白的个人观点...),而对于这类需要统计多种数据,并且每种数据痛痒相干的题,最好的方法是使用数组去做。而此题中变量过多,我们需要按照书号存储图书,并且记录书是否借出,是否归还,以及借书的时间长短!!!并且还不是一天,而是随着输入[1,10]来按照规定天数的管理阅览室,所以我的发起是使用二维数组来解题,否则需要界说许多种判断与储存变量,而且需要多重判断,过于麻烦。
此题看似复杂,实则也并不简朴...有以下几个易错点需要注意。
① 当我们做完一天的工作后,需要记得将一天的数据清空。
② 此题中会出现(未借书就还书)和(未还书就借书)的情况,在编写代码的过程中我们不能忽略,需要对应的情况做出判断,跳过相应不存在的情况(假如光借书不还书,或光还书不借书,这种情况是不算在一天的借书者中的)。
③ 注意打印结果时,需要按照题中给定的形式打印,必须是(以分钟为单位,正确到个位的整数时间),故当借书次数不为0时,我们需要将打印的结果强制转换成浮点型(小数转整数)。
答案:
- int main()
- {
- int num = 0;
- int books[1005] = { 0 };//存储书号
- int h;
- int m;
- scanf("%d", &num);
- int N = num;//用于后续打印结果
- int Sum[11] = { 0 };//储存每天借书的总时间
- int Jie[11] = { 0 };//储存每天借书的总人数
- int jj[11][1015] = { 0 };//通过储存数据的方法来判断此书是否被借走
- while (num)
- {
- int n;
- char s;
- scanf("%d %c %d:%d", &n, &s, &h, &m);
- if (n == 0)
- {
- num--;//进入下一天
- continue;
- }
- if (s == 'S')
- {
- books[n] = h * 60 + m;//存入借书时间
- jj[num][n]++;
- }
- else if (s == 'E' && jj[num][n] != 0)//判断此书是否被借走,若没被借走则无视还书操作
- {
- Sum[num] += (h * 60 + m) - books[n];//将(还书时间-借书时间)加给总时间
- books[n] = 0;//数据置零
- jj[num][n] = 0;//数据置零
- Jie[num]++;//有借有还啦,统计的借书者+1
- }
- }
- while (N)
- {
- if (Jie[N] != 0)//若借书者不为0
- {
- //以分钟为单位的精确到个位的整数时间
- printf("%d %.0lf\n", Jie[N], (double)Sum[N] / Jie[N]);
- }
- else if (Jie[N] == 0)
- printf("%d %d\n", Jie[N], Sum[N]);
- //printf("0 0\n");其实也可以,反正借书者都是0啦,理所应当其他也都是0.
- N--;//下一天
- }
- return 0;
- }
复制代码 解析:就如我们上面提到的解题思绪一样,我们接纳创建二维数组的方式来进行解题。首先我们已知题中的变量分别有:书号,借书总时间,借书总人数,以及我们还需要判断书的借还情况(轻易被忽略)。我们分别界说三个一维数组来分别储存(书号)(借书总时间)(借书总人数),而书的借还情况需要与书号相干联,所以我们用二维数组来记录书的借还情况~
随后我们创建一个while循环布局作为最外层的循环,此循环代表天数,随后我们只需要在while循环中编写完成一天的阅览室工作就好啦~每一天开始的第一件事我们需要先判断,图书管理员输入的书号是否为0,假如刚开始就输入0那么代表这一天已经过去了,之后的任何事情都不需要处理。而后再分别对输入的操纵是'S'照旧'E'进行判断,假如是'S'的话代表读者借书,我们需要将时间存入事先创建好的(借书时间)中,并且标记此书已经被借走。
- if (s == 'S')
- {
- books[n] = h * 60 + m;//存入借书时间
- jj[num][n]++;
- }
复制代码 对于'E'的处理代表读者还书,首先我们需要判断,只有此书在现在被借走了才能被还,否则此次不进行操纵。然后我们将总借书时间记录下来,借书总人数+1,并且将各种数据置零。
- else if (s == 'E' && jj[num][n] != 0)//判断此书是否被借走,若没被借走则无视还书操作
- {
- Sum[num] += (h * 60 + m) - books[n];//将(还书时间-借书时间)加给总时间
- books[n] = 0;//数据置零
- jj[num][n] = 0;//数据置零
- Jie[num]++;//有借有还啦,统计的借书者+1
- }
复制代码 末了只需要在打印的时间判断借书总人数是否为零,再将非零时刻需要打印的数据转换成浮点型就ok啦~
- if (Jie[N] != 0)//若借书者不为0
- {
- //以分钟为单位的精确到个位的整数时间
- printf("%d %.0lf\n", Jie[N], (double)Sum[N] / Jie[N]);
- }
复制代码 (需要注意的是,printf("%.0lf",(double)Sum[N] / Jie[N]);的这种操纵,会使得小数位进一,比如题中给出的测试集的第二天,总阅读时间撤除总人数2,得到的结果其实是391.几的数字,按理来说391<392,假如使用%d打印,得到的结果应该是195,而我们要得到的是196,这就体现出了我们使用(%.0lf)以及将Sum[N]强制转换成浮点型的作用了~)
- int main()
- {
- int a;
- int num;
- printf("请输入一个分子:\n");
- scanf("%d", &a);
- printf("请输入一个分母:\n");
- scanf("%d", &num);
- printf("化为浮点型的输出:%.0lf\n", (double)a / num);
- printf("不化为浮点型的输出:%d\n", a / num);
- return 0;
- }
复制代码 让我们来看这段代码~让我们用这段代码更加直观的观察一下转化为浮点型和不转化为浮点型,两者的主要差异~那么到这里这题也竣事啦~
第三题:整除光棍
光棍指的是全部由1组成的数字,如11,111,1111等。任何一个光棍都能被不以5末端的奇数整除,比如111111就能被13整除。你的步伐要读入一个整数x,这个整数一定是奇数并且不以5末端。然后,经过计算,输出两个数字:第一个数字s,体现x乘以s是一个光棍,第二个数字n是这个光棍的位数。如许的解固然不是唯一的,标题要求你输出最小的解。
- 输入一个不以5结尾的正奇数x(< 1000)
- 输入样例:31
- 输出样例:3584229390681 15
复制代码 思绪提示:此题看起来大概没有那么难,但我们要注意,题中仅仅输入31,就输出了如许长的一个数字,而输入的数字范围是[1,1000),由此可见...我们使用整形变量来存储标题中需要用到的数据是存不下的。其实我们可以尝试使用前两期中讲到的"大数加法"和"大数乘法"来模拟出一个"大数除法"进行解题。
既然是除法运算,那就让我们将思绪转换到正常的数学除法。当我们运算时假如无法除尽,我们会采取"将余数提下来,并且乘以10让它能够继承运算"的方法。而对于这题我们也可以采取这种思绪来进行运算。既然无法用变量存储数据,而用数组存储也显得过于繁琐,不妨我们尝试对每一位数字分别除以除数,若余数不为0则取余数后继承进行下一位运算,运算的同时记得将此位数字输出.
(因为我们要求的是,与num相乘能得到"光棍"的数,取余操纵后再加1)
比如我们用13来举例~
① 我们先求出大于13的最小"光棍",也就是111。
② 然后用111除以13,输出商,然后取余数。
③ 处理余数,将余数乘以十再加一,而后循环往复,直到余数为0。
答案:
- #include<stdio.h>
- int main()
- {
- int num;
- scanf("%d", &num);
- int n = 1;//记录大于num的最小"光棍",后续计算每一位
- int i = 0;//记录1的个数
- while (n < num)
- {
- n = n * 10 + 1;//n后续再加一个1
- i++;
- }
- while (1)
- {
- i++;
- printf("%d", n / num);//输出n/num的商
- n %= num;//记录n/num的余数(正常除法运算的思路)
- if (n % num == 0)//余数为0则除尽了
- break;//退出循环
- else
- n = n * 10 + 1;//在余数后加一个1,继续计算下一位
- }
- printf(" %d", i);//输出1的个数
- return 0;
- }
复制代码 解析:明确了刚刚的思绪提示的话,其实代码已经在脑筋里呼之欲出了吧~此题只要按照通常除法运算步骤进行编写就好了,需要注意的是对于数据处理的一些细节:在寻找大于num的最小"光棍"时,while内部也要使i++,在得商取余的while循环中需要先输出商和计算余数,再用新的余数取判断是否除尽,颠倒顺序的话会导致步伐比正常竣事要晚。
第四题:有理数均值
本题要求编写步伐,计算N个有理数的匀称值。
输入格式:先输入一个正整数(<=100);第二行按照a1/b1 a2/b2...的格式给出N个分数形式的有理数,(分子分母必须都是整型范围的整数,假如使负数则负号一定出现在最前面)。
输出格式:N个有理数的匀称值,必须是最简形式。
- 输入样例:
- 4
- 1/2 1/6 3/6 -5/10
- 输出样例:
- 1/6
复制代码 思绪提示:按照常理来说,只需要以此将所有的有理数进行相加减,得到末了的结果后再求出最大公约数,再同时除一遍就好了。但需要注意的是,此题和上一题都是算法题,并且都要计算较多的数据,正常的求分子和分母相加减的步骤应是如下:
- a1/b1 + a2/b2
- fz = a1 * b2 + a2 * b1
- fm = b1 * b2
- 如:1/4 + 3/8
- fz = 1 * 8 + 3 * 4 = 20
- fm = 4 * 8 = 32
- 结果:20/32 -> 5/8
复制代码 而此题中我们需要进行运算的有理数最多能有100个!!!进行100次分子分母相乘相加的运算会导致int型甚至long long型变量都无法存储得下,所以我们的"化简"操纵就不能只在末了才操纵一次,而是需要每进行一次有理数相加,就需要同时进行一次化简,如许才能防止无法存放。
既然需要多次使用"化简"操纵,那么我们可以构建一个函数来实现化简操纵,如允许以简化主函数的代码,并且看起来更加美观,思绪更加连贯。
求最大公约数 方法一:辗转相除法
- int NUM(int num1, int num2)
- {
- int n = num2;
- while (num1 % num2)
- {
- n = num1 % num2;
- num1 = num2;
- num2 = n;
- }
- return n;
- }
复制代码 原理就是通过两个数相除厥后回互换,末了完全除尽时返回的就是两个数的最大公约数,举例运算:
- fz = 172 fm = 128
- n = fz(172) % fm(128) = 44
- fz = fm(128)
- fm = n(44)
-
- fz = 128 fm = 44
- n = fz(128) % fm(44) = 40
- fz = fm(44)
- fm = n(40)
-
- fz = 44 fm = 40
- n = fz(44) % fm(40) = 4
- fz = fm(40)
- fm = n(4)
-
- fz = 40 fm = 4
- n = fz(40) % fm(4) = 0;
- return n(4)
复制代码 方法二:枚举法
我们先求出两者的最小值,然后使用for循环查找能够同时被二者整除的数字,使用整形变量N存储最大的公约数,末了返回N
- int NUM(int num1, int num2)
- {
- int min = num1 < num2 ? num1 : num2;
- int N = 0;
- for (int i = 2; i <= min; i++)
- {
- if (num1 % i == 0 && num2 % i == 0)
- {
- N = i;
- }
- }
- return N;
- }
复制代码 方法三:递归法
只是使用了递归的方法,详细思绪和辗转相除法是相似的。
- int NUM(int num1, int num2)
- {
- if (num2 == 0)
- return num1;
- else
- return NUM(num2, num1 % num2);
- }
复制代码 (注:递归算法题解虽然简洁,但运行服从较低,而且递归调用深度过大时大概会导致栈溢出和步伐崩溃。)
答案:
- int NUM(int num1, int num2)
- {
- int n = num2;
- while (num1 % num2)
- {
- n = num1 % num2;
- num1 = num2;
- num2 = n;
- }
- return n;
- }int main(){ int a = 0; scanf("%d", &a); int A = a; a--; int n, m, fz, fm, N;//因为计算新分子和新分母需要两个有理数运算 scanf("%d/%d", &n, &m);//所以先输入第一个有理数,方便第一次的运算操纵 fz = n; fm = m; while (a) { scanf("%d/%d", &n, &m); fz = fz * m + n * fm; fm *= m; N = NUM(fz, fm); if (N != 0)//未求出公约数则不操纵 { fz /= N; fm /= N; } a--; } fm *= A; N = NUM(fz, fm); if (N != 0) { fz /= N; fm /= N; } if (fm == 1)//分母即是一时只输出分子即可 printf("%d", fz); else printf("%d/%d", fz, fm); return 0;}
复制代码 解析:重新理清一下思绪,其实这道题并不算难,只要掌握了此中分子分母运算的思绪,并且记得必须要每一次运算后都实时进行分子分母的化简,然后掌握了如何多种方法求解最大公约数,那么这题就能够轻松的解出来啦~
怎么样,读到这里有没有一些收获呢?不要发急~学习就是日积月累,循规蹈矩的!!让我们把握好美好的现在,一天进步一小步的,走向遥远的将来吧~那么今天的刷题日记就分享到这里啦~假如有写的不清楚的地方,或者代码有需要改进的地方,还请各人多多指出哦~我也会客气学习的!那么我们下期再见~
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |