【问题标题】:Wrong Output : counting the string错误输出:计算字符串
【发布时间】:2014-03-08 17:56:56
【问题描述】:
#include <iostream>
#include <cstring>
using namespace std;

int main() {
    char a[10001],b[10001];
    int tot,s1,s2;
    cin>>tot;
    while(tot!=0) {
        gets(a);
        gets(b);
        s1= strlen(a);
        s2= strlen(b);
        cout<<s1<<s2<<endl;
        tot--;
        s1=0;
        s2=0;
    }
}

这是一个查找两个字符串长度的程序,还输入了大小写 输入:

4
abcd
xyz
abcd
bcda
aabc
acaa
Codechef
elfedcc

预期输出

43
44
44
87

但输出是

04
34
44
48

为什么?

【问题讨论】:

  • 编译器正在惩罚你使用gets(否则在cin&gt;&gt;tot;之后的输入缓冲区中仍然有一个换行符)。
  • 请注意gets 即将被删除(libc++ 已经在其 C++1y 支持中这样做了)。
  • 提示:使用std::string,不需要1001大小的数组,另外,它有一个size()成员!

标签: c++ string-length


【解决方案1】:

如评论中所述,编译器正在惩罚您使用gets1。我不打算写一个实际的答案,但你得到的答案似乎试图掩盖代码的问题,而不是实际修复任何东西。

首先:从不使用gets。根本没有办法安全地使用它,甚至没有任何尝试的借口。这只是一个设计糟糕的功能,如果它从未存在过,我们都会过得更好。

其次,在 C++ 中,几乎从来都不是使用 char 数组作为字符串的好理由。 strlen 几乎是一样的。这些并不像gets 那样危险或可怕,但在 C++ 中使用它们的真正原因(除了极其有限的嵌入式系统之外)非常罕见,除非你知道自己在做什么以及为什么,否则最好忘记他们甚至也存在。

当您使用它时,在这种情况下使用while 循环(倒计时,不少于)只会混淆代码,而不会获得任何回报。就此而言,使用像 tot 这样的变量名而不是(例如)total 或(更好的)pair_count 也有点愚蠢。

那么,在对你不应该做的事情夸大其词之后,我会建议什么?首先,如果您要使用stream &gt;&gt; var 类型输入,请尝试始终如一地使用它。如果您要改为阅读行,请尝试始终如一地这样做。在这种情况下,您可以使用其中任何一个,但是将两者混合会导致您现在遇到的那种问题。因此,如果可以(而且几乎总是可以),最好避开整个区域。

为此,我将始终使用&gt;&gt;,使用std::string 保存字符串,并使用for 循环执行固定次数的迭代:

int word_count;
std::cin >> pair_count;

for (int i=0; i<pair_count; i++) {
    std::string a, b;
    std::cin >> a >> b;
    std::cout << a.size() << b.size() << '\n';
}

与您得到的其他建议不同,这是类型安全的(scanf 和 company 甚至都不会尝试这样做),可以避免缓冲区溢出(gets 永远不会,而 scanf 和 company 可以,当使用其他答案推荐时,它们不是)。它也更短更简单,无需添加大部分无法解释的补丁来掩盖代码中的真正问题。

如果前面的内容听起来很刺耳,我对此深表歉意。不幸的是,有时这对于理解这一点几乎是必要的,至少在我看来,这似乎是其中之一。


1. 第零诫:你不能使用gets。如果你这样做了,你肯定会死(但不会像每个维护你的代码的人都希望你那样死)。

【讨论】:

  • :) 当您编写这篇博文时,我正在编写相同的代码!只有在缓冲的上下文中,使用endl 而不是换行符可能会更好。
  • @xtofl:是的,我看到你的答案在我发布我的咆哮后立即弹出。也许如果你早一点发帖,全世界都不会看到我如此挑衅,但我想这就是生活。
  • 我不得不承认,看到 gets 和数组字面量,我什至没有花时间扫描 OP 错误...
  • 你为什么使用 for 而不是 while ? xtofl 也使用过
  • @SanchitBansal:如果您要为特定次数的迭代执行循环,for 更符合更多的习惯。 while 循环最好保留用于不适合 for 循环的情况。
【解决方案2】:

你真的应该尝试使用标准模板库来处理字符串:

std::string a, b;
int numberToAsk = 0;
cin >> numberToAsk;

while(numberToAsk!=0) {
    cin >> a >> b;
    cout << a.size() << ", " << b.size() << endl;
    --numberToAsk;
}

(还要确保使用std::vector 而不是普通数组!)

此外,您只需检查标准输入是否仍然正常,就可以避免需要预先询问条目数;您的程序将在您结束输入流后立即结束(例如 ctrl+z 或 Windows 上的 F6ctrl kbd>+d 在 Linux 上):

while(cin >> a >> b) {
   cout << a.size() << ", " << b.size() << endl;
}

【讨论】:

  • 您的原始答案很好,但您的编辑......不太好。你不想要while (cin.good())。你想要while (cin &gt;&gt; a &gt;&gt; b)
  • @JerryCoffin:很棒的提示;过去一段时间我开始使用good();因为我不记得为什么了,所以我更新了帖子。
【解决方案3】:
cin>>tot;

此代码不使用 '\n' 字符。所以第一个调用读取“4”和“\n”之间的行。要查看它,您可以尝试输入

4abcd
xyz
abcd
bcda
aabc
acaa
Codechef
elfedcc

【讨论】:

    【解决方案4】:

    将cin改为scanf作品

    #include <iostream>
    #include <cstring>
    #include <stdio.h>
    using namespace std;
    
    int main() {
        char a[10001],b[10001];
        int tot,s1,s2;
        scanf("%d\n",&tot);
        while(tot!=0) {
            gets(a);
            gets(b);
            s1= strlen(a);
            s2= strlen(b);
            cout<<s1<<s2<<endl;
            tot--;
            s1=0;
            s2=0;
        }
    }
    

    【讨论】:

      【解决方案5】:

      这样做

      scanf("%d ",%t);
      

      因为没有。的输入。该空格避免了您在输入第一个字符串所采用的数字输入后输入的 '\n' 字符。您的其余代码可以按原样完成。

      您需要包含 cstdio 标头。 #include&lt;cstdio&gt;

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-02-26
        • 2022-06-13
        • 1970-01-01
        相关资源
        最近更新 更多