打印 3、5 和两者的倍数的 C 程序,专业风格建议

C Program that prints Multiples of 3, 5 and both, professional style suggestion

我写了我的第一个简单的 C 程序,它打印 3 、 5 以及 3 和 5 的倍数而不是数字,从 1 到 100。它有效。

我知道这个程序可以用数百万种不同的方式编写。专业的 C 程序员将如何实施最佳实践?作为一个完美主义者,我正在努力实现最高的最佳标准,主要是指针和专业的函数实现和预处理器。

#include <stdio.h>

void findMultiples(int n);


int main() {
    
    findMultiples(100);
    
    return 0;
}

void findMultiples(int n){
    for (int i = 1; i <= n; i++)
        if (i % 15 == 0){
            printf("Multiple of 3 and 5\n");
        }
        else if (i % 5 == 0){
            printf("Multiple of 5\n");
        }
        else if (i % 3 == 0){
            printf("Multiple of 3\n");
        }
        else{
            printf("%d\n", i);
        }
}

这基本上是 Fizzbuzz 如果它可以被 5 和 3 整除,你应该打印 FizzBu​​zz,如果它可以被 5 整除但不能被 3 整除,你应该打印 Fizz,如果它可以被 3 整除但不能被 5 整除,你应该打印 Buzz。

TL;DR

没有“正确”的方法来做到这一点。不管你怎么做,你都会打破一些最佳实践。

详细解释

Note!

I'm the kind of programmer who prefers a flexible approach to best practices and code standards. This is not right or wrong, but the whole following text is colored by my personality. I pretty much view this test as "can you understand when to skip best practices" while other people would view it like "can you figure out how to follow best practices even in tricky cases". None is more right that the other.

这个问题的目的是非常容易理解,但要做到“很好”却很棘手。在此示例中,您经常会遇到的一件事是重复代码。您可以很容易地构建它,但通常会以可读性为代价。

如果我设计的代码可以满足您的要求,我会对您提供的解决方案非常满意,然后继续处理下一个问题。真的不值得花很多时间在上面。这也是雇主在给你做这个测试时要看的东西。您是否花费数小时和数天时间来确保您的代码遵循所有“最佳实践”,即使收益微乎其微,还是您创建了有效且可读的代码,并在它足够好时立即继续?

我看到的一些例子是为了避免首先检查它是否可以被两个数字整除然后分别检查它们是连接字符串。像这样的伪:

string str = ""
if n % 5 = 0: str += "Fizz"
if n % 3 = 0: str += "Buzz"
print str

看起来不错,对吧?好吧把它翻译成真正的 C,其中字符串处理非常混乱。

char str[9] = "";
if(n%5 == 0) strcat(str, "Fizz");
if(n%3 == 0) strcat(str, "Buzz");
puts(str);

虽然看起来还不错。但这真的值得吗?如果您想将“Fizz”和“Buzz”更改为更长的时间怎么办?然后你需要确保 str 有更多 space,这很容易忘记并且会导致难以追踪的错误。我并不是说这段代码非常危险,但这里的底线是你的推理方式。这种风险真的值得为避免一些代码重复而付出努力吗?

有些人将条件重构为函数,例如 bool dividable_by_15(int n),因为“在单独的函数中分解功能很好”。有些人甚至会走到这一步:

bool dividable_by(int n, int d) { return (n%d) == 0; }
bool dividable_by_3(int n) { return dividable_by(n, 3); }
bool dividable_by_5(int n) { return dividable_by(n, 5); }
bool dividable_by_15(int n) { return dividable_by_3(n) && dividable_by_5(n); }

但在这种情况下真的需要吗?我不这么认为,但我不会说选择是 100% 显而易见的,它还取决于您使用的语言。但在大多数情况下,我会说这是一个非常明显的过度工程案例。

这个测试的重点不是看你是否可以遵循所有最佳实践。这更像是一种性格测试。一些雇主希望您做各种事情,而另一些雇主则希望您可以在代码按其应有的情况下保持原样。

关于您的代码,我实际上只有一个异议,那就是您省略了 for 循环的大括号。我永远不会那样做,除非 body 是一个简单的行。但是,我会省略 if 语句的大括号。有些人会同意最后一个,有些人则不会。那些赞成即使对单个语句也始终使用大括号的人经常使用这样的论点,即如果您需要在 body 中添加额外的语句,它会降低出现错误的风险。另一个论点是一致性,你总是应该努力在任何地方做同样的事情。在我看来,这些因素不值得额外的线条,但是嘿,这就是我。你做你。

for (int i = 1; i <= n; i++) {
    if (i % 15 == 0)
         printf("Multiple of 3 and 5\n");
    else if (i % 5 == 0)
        printf("Multiple of 5\n");
    else if (i % 3 == 0)
        printf("Multiple of 3\n");
    else
        printf("%d\n", i);
}

我觉得这看起来好多了。我什至会考虑将 if 作为一个衬里:

    if      (i % 15 == 0) printf("Multiple of 3 and 5\n");
    else if (i % 5 == 0)  printf("Multiple of 5\n");
    else if (i % 3 == 0)  printf("Multiple of 3\n");
    else                  printf("%d\n", i);

我也会考虑提取换行符,像这样:

    if      (i % 15 == 0) printf("Multiple of 3 and 5");
    else if (i % 5 == 0)  printf("Multiple of 5");
    else if (i % 3 == 0)  printf("Multiple of 3");
    else                  printf("%d", i);
    printf("\n");

因为这只是一个新行,您可以将 printf("\n") 更改为 puts("").

但是 - 事情是这样的 - 在我看来,我已经在这个问题上花费了很多精力。 :)

As a perfectionist, I'm trying to implement highest best standards

我读到一句话完美地回答了这个问题:“盲目遵循最佳实践不是最佳实践”

“最佳实践”旨在提供一种非常简单的方法来实现某些目标。如果您的代码在不遵循最佳实践的情况下实现了该目的,为什么要更改它?特别是如果它能更好地实现这个目的。

您假设人类正在阅读输出。此外,该程序并不像您所说那样做。它打印3和5的倍数,它忽略它们。

一般来说,我会先看问什么,然后确定程序将如何使用,然后编写程序。 在你的情况下,这将是这样的:

#include <stdio.h>

void findMultiples(int n)
{
    for (int i = 1; i <= n; i++)
        if ((i % 3 == 0) || (i % 5 == 0)) {
            printf("%d\n", i);
        }
    }
}

int main()
{   
    findMultiples(100);

    return 0;
}

编码风格没那么重要。

现在我为什么要从关于人类的评论开始。好吧,小程序通常被设计成链式逻辑。为什么 non-human 会对您打印的文本感兴趣?

我不认为这个答案是您最初的想法,但我希望它能帮助您以稍微不同的方式思考您的程序。

您的实施是可能的最佳实施。

对于很多程序员来说,两次检查取模条件感觉不尽如人意,并且案例的实现感觉它们非常相似以至于它们可以折叠在一起。因此,我们中的许多人都会尝试以某种方式消除明显的冗余。

然而,这些技巧无一例外地增加了代码的复杂性。事实上,正如您所写的那样,这四个案例非常容易理解。您可以尝试消除明显冗余的任何技巧都不会使其变得更简单。

归根结底,简单胜过聪明。我们知道这是 KISS 原则:保持简单,愚蠢。优质的软件并不力求聪明,它力求简单。这使得它更容易维护、更容易扩展和更容易使用。 要优化的最重要变量是代码的简单性。最聪明的程序员会严格控制自己的智慧,只在需要时才释放它。


也就是说,作为纯粹的文体评论,通常不建议省略复杂循环或 if 主体周围的大括号。我会将您的代码格式化为:

void findMultiples(int n) {
    for (int i = 1; i <= n; i++) {
        if (i % 15 == 0) {
            printf("Multiple of 3 and 5\n");
        }
        else if (i % 5 == 0) {
            printf("Multiple of 5\n");
        }
        else if (i % 3 == 0) {
            printf("Multiple of 3\n");
        }
        else {
            printf("%d\n", i);
        }
    }
}

否则,您总是 运行 有搞乱属于 loop/if 和不属于

的风险。

另外,函数的命名不是最理想的。我想,我会称之为 printDivisibilityList()。因为该函数不会“找到倍数”,所以它会打印所有数字并用 35.

的整除性对它们进行注释