我正和K.N.一起学习C. King's C:一种现代方法,存在一个问题(Ch.06 - Prog.Project#4),要求读者编写一个程序,根据交易计算经纪人的佣金,直到交易金额为0。
以下是作者的实施:
float commission, value;
printf("Enter value of trade: ");
scanf("%f", &value);
while (value != 0.0f) {
if (value < 2500.00f)
commission = 30.00f + .017f * value;
else if (value < 6250.00f)
commission = 56.00f + .0066f * value;
else if (value < 20000.00f)
commission = 76.00f + .0034f * value;
else if (value < 50000.00f)
commission = 100.00f + .0022f * value;
else if (value < 500000.00f)
commission = 155.00f + .0011f * value;
else
commission = 255.00f + .0009f * value;
if (commission < 39.00f)
commission = 39.00f;
printf("Commission: $%.2f\n\n", commission);
printf("Enter value of trade: ");
scanf("%f", &value);
}
但我想的不是两次写printf和scanf,而是使用无限for
循环,如下所示:
float value, commission;
for (;;) {
printf("Enter value of trade: ");
scanf("%f", &value);
if (value == 0)
break;
if (value < 2500)
commission = 30.00f + 0.017 * value;
else if (value < 6250)
commission = 56.00f + 0.0066 * value;
else if (value < 20000)
commission = 76.00f + 0.0034 * value;
else if (value < 50000)
commission = 100.00f + 0.0022 * value;
else if (value < 500000)
commission = 155.00f + 0.0011 * value;
else
commission = 255.00f + 0.0009 * value;
if (commission < 39.00f)
commission = 39.00f;
printf("Commission: %.2f\n", commission);
}
我的问题是,考虑到行数并避免重复是一个良好和必要的习惯,或者这在算法设计方面是不好的方法?
提前致谢!
答案 0 :(得分:6)
不要重复自己。 DRY vs. WET
考虑代码需要重新工作
// weak
printf("Enter value of trade: ");
scanf("%f", &value);
// better
printf("Enter value of trade: ");
fflush(stdout); // Insure text is printed before scanning
if (scanf("%f", &value) != 1) Handle_Error();
代码的维护者是否愿意在1或2个地方更新?
用户I / O通常可以使用辅助函数,并且可以实现清晰的非重复编码循环条件。
int read_double(const char *prompt, double *y, ) {
printf("%s", prompt);
fflush(stdout);
int count = scanf("%f", y);
return count;
}
while (read_double("Enter value of trade: ", &value) == 1) {
if (value == 0)
...
printf("Commission: %.2f\n", commission);
}
整个if()
,else if()
,...也可以使用re-work。也许struct
对于OP来说太新了,但关键在于代码的发展以及易于维护的编码是一个非常有价值的目标。
const struct {
double value;
double commission_base;
double commission_rate;
} tier[] = {
{ 2500.00, 30.00, 0.017 },
{ 6250.00, 56.00, 0.0066 },
{ 20000.00, 76.00, 0.0034 },
{ 50000.00, 100.00, 0.0022 },
{ 500000.00, 155.00, 0.0011 },
{ DBL_MAX, 255.00, 0.0009 } };
int n = sizeof tier / sizeof tier[0];
double commission = 0.0;
for (int i = 0; i < n; i++) {
if (value < tier[i].value) {
commission = tier[i].commission_base + tier[i].commission_rate * value;
break;
}
}
#define COMMISSION_MIN 39.00
if (commission < COMMISSION_MIN) {
commission = COMMISSION_MIN;
}
答案 1 :(得分:3)
一条规则是不要重复自己。与任何规则一样,可能存在例外情况,但如果您没有充分理由采取其他方式,则应该注意它。
它背后的基本原理并不是真正打字懒惰,更重要的是,如果你必须改变代码,你必须注意不要忘记重复代码的一次出现。
出于这个原因,即使在你的例子中,它与品味的关系也不远,我绝对会优先考虑代码不重复的第二个版本。这里的一个具体原因是你应该测试/*
Input: char pointers for source (s2) and destination (s1)
Output: returns the pointer to the destination (s1)
*/
char *my_strcpy(char * , const char * );
int main()
{
char src[] = "cs23!";
char dst[]="Hello hello";
char *curdst;
int len=0;
while(src[len++]);
// do the copy
curdst= my_strcpy(dst, src);
// check to see if the NULL char is copied too.
printf("dst array %s and last element %d\n", dst, atoi(&dst[len]));
return 0;
}
char *my_strcpy(char *s1, const char *s2) {
register char *d = s1;
// print the pointer variables address and their contents, and first char
printf("s2 address %p, its contents is a pointer %p to first char %c \n", (void *)&s2, (void *)s2, *s2);
printf("s1 address %p, its contents is a pointer %p to first char %c \n", (void *)&s1, (void *)s1, *s1);
while ((*d++ = *s2++));
return(s1);
}
的返回值(如果用户错误地键入了符号的alpha,该怎么办?)。如果是第二个版本,则只需修复一次问题。在第一个版本中,如果你在写完第一个版本之后那么长时间,或者更糟糕的是如果其他人必须修复它,则存在忘记一个实例的风险。
答案 2 :(得分:1)
使用无限循环来完成此任务在技术上有效。但是,建议的代码更清晰,因为跳出循环的条件是循环类型中固有的。 different loop types允许您更有效地完成不同的任务。 &#34; for&#34; loop可以增加或减少变量的值,而无需在循环中为此编写代码。 while循环只是运行一个检查,这是你正在做的事情。
答案 3 :(得分:1)
你应该听从其他响应者关于不使用浮动钱的建议。也就是说,这是一种避免使用无限循环的方法(仍然使用浮动命名法,但你应该适当地改变它):
float value = 1.0;
while ( value != 0.0f ) {
// prompt for input
// get input
if ( value > 0.0f ) {
// handle the input and output resultshere
}
}