请批评我的任务 [英] Critique my assignment please

查看:55
本文介绍了请批评我的任务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我的讲师给了我们一个任务。他有一个非常成熟的

教学的方式是,他不关心人们是否出现,他们是否执行任务,或者他们是否复制其他人的工作。

此外,他甚至没有标记作业,而是在学生的工作中给出

提示等等。虽然为了州考试和资格考试学生'

的能力,但实际上他和我们一起坐在电脑前看着我们写代码。


我们昨天获得了一项任务。我尝试了

分配,并重新生成了以下代码。我很感激,如果你能给我一些关于代码的建议,建议等等。再一次,我必须强调你不会只是为我做功课。


这里是讲师的任务给了我们:


[开始报价]

写一个程序来检查一个序列号的有效性

欧元钞票。该程序必须完全便携,并符合C89标准的
。该程序应尽可能利用标准库

。在各种平台上,该程序还应该在资源消耗和执行速度方面有效地执行

。该程序应该很好 -

评论并尽可能容易理解。调试模式设施

,例如assert应该被利用,无论他们添加多少冗余

,但是发布模式可执行文件的效率不应该由调试模式功能负担。学生必须自行查找

如何检查欧元纸币的有效性

序列号。该程序不应因用户输入不良而导致故障。祝你好运。

[结束语]


在开始之前,这里有一段来自维基百科的摘录,讨论了

检查序列号的有效性:


[开始摘录]

用字母表中的位置替换首字母(即L

是12,M是13,......,Z是26)。

将这个数字和序列号的每个数字相加。例如:

U08217383936是21 + 0 + 8 + 2 + 1 + 7 + 3 + 8 + 3 + 9 + 3 + 6 = 71

加起来所有这个新数字的数字,重做次数需要

,直到你获得一位数的数字。或者计算机

程序员可能会发现熟悉的MOD 9功能更容易实现。

这给出了相同的结果。

结果数字必须是8 - 在上面的例子中,7 + 1 = 8或71

MOD 9 = 8,所以它是正确的。

[end excerpt]


现在这里是我的代码。你可能会因此而杀了我,但是我没有编译器可以交给你,所以,即使我已经检查了

代码,我不能100%确定它会编译。


#include< assert.h / * For assert * /

#include< ctype.h / *对于像isupper这样的东西* /

#include< stdlib.h / *对于EXIT_FAILURE * /

#include< stdio。 h / *对于puts和gets * /

int const serial_len = 12; / *序列号=一个字母后跟

十一位数* /

/ *功能:DigitFromChar


转换''0 ''到0,'5''到5,''3'到3等等。


利用C89功能0到9 '必须是连续的。


发布模式:UNSAFE因为输入是未定义的行为

无效

调试模式:SAFE因为如果输入无效,则断言失败


* /


unsigned DigitFromChar(char const x)

{

断言(x> =''0''&& x< =''9'');


返回x - ''0 '';

}

/ *功能:NumberFromUpperLetter


将''A''转换为1,''B' '到2','C''到3 ......依此类推。


使用简单的开关语句。


发布模式:UNSAFE,因为输入是

无效时行为未定义

调试模式:SAFE,因为如果输入无效,断言失败


* /


unsigned NumberFromUpperLetter(char const x)

{

断言(isupper(x));


开关(x)

{

case''A'':返回1;案例''B'':返回2; case''C'':返回3;

case''D'':返回4;案例''E'':返回5;案例''F'':返回6;

案例''G'':返回7;案件''H'':返回8; case''我'':返回9;

case''J'':返回10;案例''K'':返回11;案例''L'':返回12;

案例''M'':返回13;案例''N':返回14;案例''O'':返回15;

案例''P'':返回16;案例''Q'':返回17; case''R'':返回18;

case''S'':返回19;案例''T'':返回20; case''U'':返回21;

case''V'':返回22;案例''W'':返回23; case''X'':返回24;

case''Y'':返回25;案例''Z'':返回26;

}

}

/ *功能:IsValidEuroSerial


如果序列无效,则返回false,否则返回true。

遍历字符,每次迭代求和。


发布模式: UNSAFE,因为输入是未定义的行为

无效

调试模式:SAFE因为输入无效时断言失败

* /


int IsValidEuroSerial(char const * p)

{

int const assert_dummy = assert(p);


char const * const pend = p + serial_len;


unsigned sum = NumberFromUpperLetter(* p ++);


do

{

断言(isnum(* p));

sum + = DigitFromChar(* p ++);

} while(pend!= p);


返回8 ==总和%9;

}

int main(void)

{

char输入[serial_len + 1],

* p =输入+ 1,

const * const pnull =输入+( sizeof input / sizeof * input -

1);


puts(输入欧元钞票序列号:);


获取(输入);


if(!isupper(* input))goto Bad; / *检查第一个字符是上面

字母* /


如果(!isnum(* p ++))goto Bad; / *检查每个字符是一个数字* /

而(pnull!= p);


puts(IsValidEuroSerial(输入)?" \ n \ nValid \\\
":" \ n\\\
INVALID \ n");

返回0;


错误:

puts(\ n \ nnInvalid Input。输入必须包含大写的

字母后跟11位数字。\ nn;)

返回EXIT_FAILURE;

}


到目前为止我能看到的缺点是:


1) char数组循环两次,一次在main中,一次在

IsValidEuroSerial中。我应该考虑写一个

" IsValidEuroSerial_Safe"功能,以便它可以减少到一个

循环。

2)我相信你们都会跳到我的喉咙里获取,但请

只是给出合适的替代品。


非常感谢您的时间,


Martin


My lecturer gave us an assignment. He has a very "mature" way of
teaching in that he doesn''t care whether people show up, whether they
do the assignments, or whether they copy other people''s work.
Furthermore, he doesn''t even mark the assignments, but rather gives
tips and so forth when going over students'' work. To test students''
capabilities for the purpose of state exams and qualifications though,
he actually sits down with us at a computer and watches us write code.

We were issued with an assignment a yesterday. I have attempted the
assignment, and have re-produced the code below. I''d appreciate if
you''d give me advice, suggestions, etc. on the code. Again, I must
stress that you won''t simply be "doing my homework for me".

Here''s the assignment the lecturer gave us:

[begin quote]
Write a program to check the validity of a serial number found on a
Euro bank note. The program must be fully portable and compliant with
the C89 Standard. The program should exploit the standard library
where possible. The program should also be expected to perform
efficiently, both in terms of resource consumption and execution
speed, on a wide variety of platforms. The program should be well-
commented and easily understood where possible. Debug-mode facilities
such as "assert" should be exploited no matter how much redundancy
they add -- however the efficiency of the release-mode executable
should not be burdened by debug-mode features. The student must find
out for themselves how to check the validity of a Euro bank note
serial number. The program should not malfunction on account of bad
user input. Best of luck.
[end quote]

Before I begin, here''s an excerpt from Wikipedia which discusses how
to check the validity of the serial number:

[begin excerpt]
Replace the initial letter by its position in the alphabet (that is L
is 12, M is 13,..., Z is 26).
Add up this number and every digit of the serial number. For example:
U08217383936 is 21 + 0 + 8 + 2 + 1 + 7 + 3 + 8 + 3 + 9 + 3 + 6 = 71
Add up all the digits of this new number, redo as many times as
necessary until you obtain a one-digit number. Alternatively computer
programmers may find the familiar MOD 9 function easier to implement.
This gives the same result.
The resulting number must be 8 - in the example above, 7 + 1 = 8 or 71
MOD 9 = 8, so it''s correct.
[end excerpt]

Now here''s my code. You''re probably gonna kill me for this, but I
don''t have a compiler to hand, so, even though I''ve checked over the
code, I can''t say with 100% certainty that it will compile.

#include <assert.h/* For assert */
#include <ctype.h/* For stuff like isupper */
#include <stdlib.h/* For EXIT_FAILURE */
#include <stdio.h/* For puts and gets */
int const serial_len = 12; /* Serial number = one letter followed
by eleven digits */
/* Function: DigitFromChar

Converts ''0'' to 0, ''5'' to 5, ''3'' to 3, etc..

Exploits C89 feature that ''0'' through ''9'' must be consecutive.

Release Mode: UNSAFE because behaviour is undefined if input is
invalid
Debug Mode: SAFE because assertion fails if input is invalid

*/

unsigned DigitFromChar(char const x)
{
assert( x >= ''0'' && x <= ''9'' );

return x - ''0'';
}
/* Function: NumberFromUpperLetter

Converts ''A'' to 1, ''B'' to 2, ''C'' to 3... and so on.

Uses a simple switch statement.

Release Mode: UNSAFE because behaviour is undefined if input is
invalid
Debug Mode: SAFE because assertion fails if input is invalid

*/

unsigned NumberFromUpperLetter(char const x)
{
assert(isupper(x));

switch (x)
{
case ''A'': return 1; case ''B'': return 2; case ''C'': return 3;
case ''D'': return 4; case ''E'': return 5; case ''F'': return 6;
case ''G'': return 7; case ''H'': return 8; case ''I'': return 9;
case ''J'': return 10; case ''K'': return 11; case ''L'': return 12;
case ''M'': return 13; case ''N'': return 14; case ''O'': return 15;
case ''P'': return 16; case ''Q'': return 17; case ''R'': return 18;
case ''S'': return 19; case ''T'': return 20; case ''U'': return 21;
case ''V'': return 22; case ''W'': return 23; case ''X'': return 24;
case ''Y'': return 25; case ''Z'': return 26;
}
}
/* Function: IsValidEuroSerial

Returns false if serial is invalid, otherwise true.

Loops through the characters, summing with each iteration.

Release Mode: UNSAFE because behaviour is undefined if input is
invalid
Debug Mode: SAFE because assertion fails if input is invalid
*/

int IsValidEuroSerial(char const *p)
{
int const assert_dummy = assert(p);

char const *const pend = p + serial_len;

unsigned sum = NumberFromUpperLetter(*p++);

do
{
assert(isnum(*p));
sum += DigitFromChar(*p++);
} while (pend != p);

return 8 == sum%9;
}
int main(void)
{
char input[serial_len + 1],
*p = input + 1,
const *const pnull = input + (sizeof input / sizeof *input -
1);

puts("Enter Euro banknote serial number: ");

gets(input);

if (!isupper(*input)) goto Bad; /* Check first char is upper
letter */

do if (!isnum(*p++)) goto Bad; /* Check each char is a digit */
while (pnull != p);

puts(IsValidEuroSerial(input) ? "\n\nValid\n" : "\n\nINVALID\n");
return 0;

Bad:
puts("\n\nInvalid Input. Input must consist of an uppercase
letter followed by eleven digits only.\n");
return EXIT_FAILURE;
}

The shortcomings I can see so far are:

1) The char array is looped through twice, once in main and once in
"IsValidEuroSerial". I should consider writing an
"IsValidEuroSerial_Safe" function so that it can be reduced to one
loop.
2) I''m sure you will all jump down my throat about "gets", but please
just give suitable alternatives.

Thanks a lot for your time,

Martin

推荐答案

8月23日下午4:12,战争... @ eircom.net写道:

[snip]
On Aug 23, 4:12 pm, war...@eircom.net wrote:
[snip]

int const assert_dummy = assert(p);
int const assert_dummy = assert(p);



如果这个编译,那么你的编译器就坏了。

If this compiles, then your compiler is broken.


8月23日,4 :12点,战争...... @ eircom.net写道:

[snip]
On Aug 23, 4:12 pm, war...@eircom.net wrote:
[snip]

do if(!isnum(* p ++) )转到坏; / *检查每个字符是数字* /
do if (!isnum(*p++)) goto Bad; /* Check each char is a digit */



[snip]


我猜你的意思是isdigit()而不是isnum()


PS

当然我们要把你烤到()。

在这种情况下:

fgets(输入,sizeof输入,标准输入);

完全没问题,没有可怕的后果。

[snip]

I guess you mean isdigit() instead of isnum()

P.S.
Of course we''re going to roast you over gets().
In this context:
fgets(input, sizeof input, stdin);
would be perfectly fine and not have dire consequences.


您的代码无法使用-ansi -pedantic在我的GCC上编译。


8月23日下午6:12,战争... @ eircom.net写道:

[snip]
Your code fails to compile on my GCC with -ansi -pedantic.

On Aug 23, 6:12 pm, war...@eircom.net wrote:
[snip]

unsigned NumberFromUpperLetter(char const x)

{

断言(isupper(x));


开关(x)

{

case''A'':返回1;案例''B'':返回2; case''C'':返回3;

case''D'':返回4;案例''E'':返回5;案例''F'':返回6;

案例''G'':返回7;案件''H'':返回8; case''我'':返回9;

case''J'':返回10;案例''K'':返回11;案例''L'':返回12;

案例''M'':返回13;案例''N':返回14;案例''O'':返回15;

案例''P'':返回16;案例''Q'':返回17; case''R'':返回18;

case''S'':返回19;案例''T'':返回20; case''U'':返回21;

case''V'':返回22;案例''W'':返回23; case''X'':返回24;

case''Y'':返回25;案例''Z'':返回26;

}


}
unsigned NumberFromUpperLetter(char const x)
{
assert(isupper(x));

switch (x)
{
case ''A'': return 1; case ''B'': return 2; case ''C'': return 3;
case ''D'': return 4; case ''E'': return 5; case ''F'': return 6;
case ''G'': return 7; case ''H'': return 8; case ''I'': return 9;
case ''J'': return 10; case ''K'': return 11; case ''L'': return 12;
case ''M'': return 13; case ''N'': return 14; case ''O'': return 15;
case ''P'': return 16; case ''Q'': return 17; case ''R'': return 18;
case ''S'': return 19; case ''T'': return 20; case ''U'': return 21;
case ''V'': return 22; case ''W'': return 23; case ''X'': return 24;
case ''Y'': return 25; case ''Z'': return 26;
}

}



可能小点:在

案例中没有执行返回语句,x不是''A'' - ''Z''之一。


[snip]

A possibly minor point: there is no return statement executed in the
case that x is not one of ''A''-''Z''.

[snip]


int IsValidEuroSerial(char const * p)

{

int const assert_dummy = assert( p);
int IsValidEuroSerial(char const *p)
{
int const assert_dummy = assert(p);



这是语法错误,因为assert扩展为void表达式。

This is a syntax error since assert expands to a void expression.


>

char const * const pend = p + serial_len;


unsigned sum = NumberFromUpperLetter(* p ++);


do

{

断言(isnum(* p));
>
char const *const pend = p + serial_len;

unsigned sum = NumberFromUpperLetter(*p++);

do
{
assert(isnum(*p));



isnum不是标准C库中的函数。我想你正在寻找

for thedigit。

isnum is not a function in standard C library. I think you''re looking
for isdigit.


sum + = DigitFromChar(* p ++);

} while(pend!= p);


返回8 ==总和%9;


}

int main(无效)

{

char输入[serial_len + 1],
sum += DigitFromChar(*p++);
} while (pend != p);

return 8 == sum%9;

}

int main(void)
{
char input[serial_len + 1],



C89中不允许使用可变长度数组。虽然你已经使用const限定符声明了serial_len,但这并没有使得

" serial_len"一个常量表达式。

Variable-length arrays are not permitted in C89. Although you''ve
declared serial_len with the const qualifier, this does not make
"serial_len" a constant expression.


* p =输入+ 1,

const * const pnull =输入+(sizeof input / sizeof * input -

1);
*p = input + 1,
const *const pnull = input + (sizeof input / sizeof *input -
1);



这是语法错误。领先的const必须直接分组

和char。在这里你有一个逗号在

声明者列表中,这是非法的。

This is a syntax error. The leading "const" must be grouped directly
with "char". Here you have it following a comma in a list of
declarators, which is illegal.


>

puts(输入欧元钞票序列号:);


得到(输入);
>
puts("Enter Euro banknote serial number: ");

gets(input);



人们普遍认为使用fgets比使用获取更好。

It is widely accepted that using fgets is much better than using gets.


>

if(!isupper(* input))goto Bad; / *检查第一个字符是上面

字母* /


如果(!isnum(* p ++))goto Bad; / *检查每个字符是一个数字* /
>
if (!isupper(*input)) goto Bad; /* Check first char is upper
letter */

do if (!isnum(*p++)) goto Bad; /* Check each char is a digit */



再次,你可能想在这里使用isdigit。

Again, you probably want isdigit here.


while(pnull!= p);


puts(IsValidEuroSerial(输入)?" \ n\\\
Valid\\\
":\ n \ nnINVALID \ n");

返回0;


错误:

put(&\\; \ n \ n无效输入。输入必须包含一个大写的

字母,后跟十一位数字。\ n");

返回EXIT_FAILURE;


}
while (pnull != p);

puts(IsValidEuroSerial(input) ? "\n\nValid\n" : "\n\nINVALID\n");
return 0;

Bad:
puts("\n\nInvalid Input. Input must consist of an uppercase
letter followed by eleven digits only.\n");
return EXIT_FAILURE;

}



[snip]

[snip]


这篇关于请批评我的任务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆