我为99瓶啤酒写了一个C ++程序,但是有点混乱。有什么方法可以使它更短,更清晰,更容易阅读?

/*
 * Write a program that prints out the entire lyrics to a full rendition of "99 bottles of beer"
 */

#include <iostream>

using namespace std;

int main (void)
{
    int bottle = 99;
    while (bottle > 0)
    {
        cout << bottle << " bottles of beer on the wall, "
             << bottle << " bottles of beer." << endl;

        bottle--;

        cout << "Take one down and pass it around, " << bottle << " "
             << "bottles of beer on the wall.\n" << endl;

        if (bottle == 1)
        {
            break;
        }

    }

    cout << "1 bottle of beer on the wall, 1 bottle of beer." << endl
         << "Take one down and pass it around, no more bottles of beer on the wall.\n" << endl
         << "No more bottles of beer on the wall, no more bottles of beer." << endl
         << "Go to the store and buy some more, 99 bottles of beer on the wall.";

    return 0;
}


评论

最好将“ \ n”替换为std :: endl。

不是代码,而是语法问题:在您离开循环之前,您将打印“ ...并传递,一瓶啤酒...”;该行可能应该与其他行一起循环打印,因此它可以是单数

RE:“ \ n”与std :: endl ... @ LokiAstari提出的观点是endl强制刷新流。这对于调试信息很有用,因此您可以获取直到崩溃的输出,但否则会干扰缓冲的自然性能。 (只是要明确一点,这不是决定审美偏好的问题,因为我认为endl更具“文人化”的感觉。)

我不知道代码,但是啤酒瓶非常好...

您可以使用for循环而不是一会儿,这样可以省去手动递减(int i = 99; i> 1; i-){...}

#1 楼

一些简短的注释:

不要使用命名空间std:

出于某些原因这很糟糕,但是总之:如果您是using namespace std;,您可能会遇到大名冲突。有关更多信息:为什么使用namespaec std被认为是不好的做法?

中断条件:

在这里的外观很好: br />

这可能会更简单:

while (bottle > 0) 
{
    //print the lyrics
    if (bottle == 1) 
    {
         break;
    }
}


命名:一个柜台。将其命名为bottlebottleCount或其他名称,但不要命名为leftBottles。因为不是瓶子...

评论


\ $ \ begingroup \ $
我正在学习一本C ++书籍,作者建议使用命名空间std。感谢您指出我的错误。
\ $ \ endgroup \ $
–大会
14年8月14日在11:50

\ $ \ begingroup \ $
@Amession在教学初学者时很常见,因为它使操作更简单,但是有点像避免与孩子进行性爱,因为这很困难。
\ $ \ endgroup \ $
– Davidmh
14年8月14日在12:11

\ $ \ begingroup \ $
@面向学生的书籍通常会建议您在现实世界中不应该做的事情,以使事情变得更简单。不幸的是,在学校学习到的不良习惯不会在进入现实世界时被神奇地抹去。使用命名空间std;在C ++中,还不如在PHP中使用mysql_pwn_my_server()系列数据库函数那么糟糕;但是任何阅读技术新闻的人都会定期看到主要站点,这些站点被错误的人通过SQL Injection破坏了。
\ $ \ endgroup \ $
–丹在火光中摆弄
2014年8月14日14:51

\ $ \ begingroup \ $
@DanNeely我同意(我读了很多有关C和C ++的学生书,而且我对它完全了解了)。除了尝试和失败之外,是否还有其他用于学习适当C或C ++的良好资源?
\ $ \ endgroup \ $
–加拿大卢克
14年8月14日在18:24

\ $ \ begingroup \ $
@CanadianLuke首先要知道的是,学习C的适当资源不是学习C ++的适当资源。
\ $ \ endgroup \ $
–莫文
2014年8月15日在12:49

#2 楼

除了其他答案中的注释以外,我建议您创建一个在屏幕上打印句子的功能。

类似

while (bottles > 0)
{
    printLyrics(bottles);
    bottles--;
}


在这种情况下,只剩下一个瓶子就需要处理特殊情况。案例在正确的抽象级别上显示。

评论


\ $ \ begingroup \ $
好主意,我现在正在调整代码,谢谢!
\ $ \ endgroup \ $
–大会
14年8月14日在11:52

\ $ \ begingroup \ $
随机花絮:我知道在VB中,他们希望if块中更常见的情况首先出现。 C ++是相同的方式还是性能相同?
\ $ \ endgroup \ $
–加拿大卢克
14年8月14日在18:25

\ $ \ begingroup \ $
@CanadianLuke在几乎所有编程语言中它都是相同的,因为它可以使您免于引擎盖下的跳转/分支指令。但是在大多数情况下,您不需要这样的微观优化。如果确实需要这种微优化,那么您就不想使用此答案的建议,因为它会将不必要的分支指令放入循环中。
\ $ \ endgroup \ $
– jliv902
14年8月14日在20:37

\ $ \ begingroup \ $
@CanadianLuke据我所知,这并不是为了进行优化,而是为了提高可读性。首先放置更常见的场景,使读者先阅读该书:让读者先阅读特殊情况,可能会使他们很难理解它们,因为读者还没有看清楚大图就可以理解为什么它们是例外。也就是说,在处理琐碎的单行if实体时,我认为该规则不适用。作为一个极端的例子,我从未见过有人将ArgumentNullException等的引发异常的语句放在VB.NET的函数结尾。
\ $ \ endgroup \ $
–hvd
2014年8月16日在22:15



\ $ \ begingroup \ $
如果更改为while(瓶数> 1),则可以保存比较和分支在此答案中,尤其是如代码所示,它将打印“ 1瓶...”然后是“ 1瓶...”
\ $ \ endgroup \ $
–詹姆斯·斯内尔(James Snell)
2014-10-28 8:35

#3 楼

这似乎是模板元编程有用的地方(毕竟,我们不想在可能经常执行的程序中浪费宝贵的运行时间)。

#include <iostream>

template<int N>
struct song {
    inline static void sing() {
        std::cout << N << " bottles of beer on the wall, "
            << N << " bottles of beer.\nTake one down, pass it around, "
            << N - 1 << " bottles of beer on the wall.\n\n";
        song<N - 1>::sing();
    }
};

template<>
struct song<1> {
    inline static void sing() {
        std::cout << "1 bottle of beer on the wall, 1 bottle of beer.\n"
            << "Take it down and pass it around, no more bottles of beer on the wall.\n\n"
            << "No more bottles of beer on the wall, no more bottles of beer.\n"
            << "Go to the store and buy some more, 99 bottles of beer on the wall.\n";
    }
};

template<>
struct song<2> {
    inline static void sing() {
        std::cout << "2 bottles of beer on the wall, "
            << "2 bottles of beer.\nTake one down, pass it around, "
            << "1 bottle of beer on the wall.\n\n";
        song<1>::sing();
    }
};

int main() {
    song<99>::sing();
    return 0;
}


尽管模板的顺序(首先是通用模板,然后是1的专业化,最后是2的专业化)可能看起来很奇怪并且很随意,但实际上是有必要的。一般情况必须在进行任何专业化处理之前进行。 2的专业化使用1的专业化,因此必须遵循它。否则,2的专业化将尝试使用1的通用模板,只有在这样做之后,才能找到1的模板,从而使该模板无效。编写代码,这不会减少代码的大小。 OTOH,我相信它至少可以使语法正确。

评论


\ $ \ begingroup \ $
您在那里使用的逻辑很好。保存此程序以供将来参考。
\ $ \ endgroup \ $
–大会
14年8月15日在7:54

\ $ \ begingroup \ $
我想看看您的性能基准…和呼吸测试仪结果。
\ $ \ endgroup \ $
– 200_success
2014年8月15日在7:56



\ $ \ begingroup \ $
OP是一个自白的初学者-这会吓到他们!
\ $ \ endgroup \ $
–user3791372
2014年8月15日13:10



\ $ \ begingroup \ $
@ user3791372:我无法想象这怎么会吓到任何人。从字面上看,这是完成这项工作的最简单的程序-它的循环复杂度为1(不是其中的单个if语句或其他流控制语句)。
\ $ \ endgroup \ $
–杰里·科芬(Jerry Coffin)
2014年8月15日13:31



\ $ \ begingroup \ $
@JerryCoffin:听到有多少初学者对递归概念感到困惑,您会感到惊讶。
\ $ \ endgroup \ $
–没人远离SE
2014年8月28日上午10:42

#4 楼

不需要的代码:

您实际上可以删除此代码:

if (bottle == 1)
{
    break;
}


您处于while循环中,因此只要bottle为大于0。
所以我猜您为最后一个瓶子插入了该代码。

while (bottle > 0)


获得相同的结果。

命名:

虽然您没有太多要调用的var =>我喜欢你已经指向瓶子了。
我仍然认为bottleCount可能是一个更好的var名称。

同时循环:
没什么大的不同,但为了您自己,请使用for循环。
您不要忘了减去一个。

while (bottle > 1)


摘要:

虽然我不是c ++编码器,但它看起来很不错。
如果您真的想得分很高,可以对for循环使用递归。

评论


\ $ \ begingroup \ $
当然,现在我正在使用for循环,它可以工作。使用if是毫无意义的,我对C ++不满意,因此感谢您的信息和帮助。
\ $ \ endgroup \ $
–大会
14年8月14日在11:51

\ $ \ begingroup \ $
我刚刚编辑了for循环,因为其中有一个复制粘贴错误,我的目的是:)
\ $ \ endgroup \ $
– chillworld
14年8月14日在11:57

\ $ \ begingroup \ $
请使用--bottleCount而不是bottleCount--。应该已经将此语言命名为++ C。每次让我哭泣:-(
\ $ \ endgroup \ $
–AurélienOoms
14年8月15日在7:30

\ $ \ begingroup \ $
oke的性能问题:stackoverflow.com/a/24904/2853637
\ $ \ endgroup \ $
– chillworld
14年8月15日在8:39

#5 楼

输出错误

您有一个多元错误:


墙上有2瓶啤酒,有2瓶啤酒。
倒下一瓶并通过它周围有1瓶啤酒。


此外,通常用换行符结束程序的输出。

问题的结构和分解

单瓶经文有一种特殊情况。也许可以将其概括一下。一种可能的策略是将其视为国际化问题。

但是,将其作为C ++编程实践来进行会更有趣和更具启发性。因此,我认为知道如何正确进行复数化和大写的对象是一个好主意。

建议的解决方案

评论


\ $ \ begingroup \ $
为什么我现在找不到杰夫·阿特伍德(jeff atwoods)关于多元“虫子”的评论?
\ $ \ endgroup \ $
–Vogel612♦
14年8月14日在22:22

\ $ \ begingroup \ $
喝完98瓶啤酒后,就尝试正确地语法。
\ $ \ endgroup \ $
– CashCow
2014年8月15日上午11:13

#6 楼

Chillworld提到了该解决方案,我将做一点扩展。有效地进行操作,并且不需要if块。

如果您设置while语句以说出while (bottle > 1)并删除if代码块,它将看起来像这样。当您只剩下一个瓶子时,仍然会有瓶子的复数形式的问题,我想尽管在喝完98瓶啤酒之后,即使唱完最后一句话也要有科学奇迹。

评论


\ $ \ begingroup \ $
要修复瓶子的复数形式,唯一的解决方案是使用(bottleCount> 2)中断循环,并使用std :: cout函数在循环外部打印出来。
\ $ \ endgroup \ $
–大会
14年8月16日在7:37

\ $ \ begingroup \ $
@Amession您如何得出这个结论?
\ $ \ endgroup \ $
–马拉奇♦
16年8月29日在13:03