C ++如果不能按预期工作? (真的很奇怪的bug)

时间:2014-03-02 14:41:11

标签: c++ if-statement

我可以使用一些帮助,因为我现在非常绝望。在这里,看一下我的代码,然后查看输出。是什么导致了这个错误?我该怎么办呢? 谢谢你的帮助!
代码:

while (1)
{
    while (1)
    {
     cout << "Choose your username: ";
     cin >> username;
     std::strcpy (username1, username.c_str());
     if (isdigit(username1[0]) || isdigit(username1[1]) || isdigit(username1[2]))
     {
      cout << "The first 3 characters HAVE to contain only letters!\n\a";
     }
          else if (username1[3] < 0)    // I don't actually know why, but this works as intended o.O
          {
              cout << "Your username HAS to contain atleast 3 letters!\n\a";
          }
               else if (username1[10] > 0)                      // Works - dunno why o.0
               {
                  cout << "Your username CAN ONLY contain maximum 10 characters!\n\a";
               }
                    else
                        break;
    }

输出:

Choose your username: ko
Your username HAS to contain atleast 3 letters!
Choose your username: k
Your username HAS to contain atleast 3 letters!
Choose your username: kokokokokoo    // Now that's > 10
Your username CAN ONLY contain maximum 10 characters!   // Now this is okay BUT...
Choose your username: ko
Your username CAN ONLY contain maximum 10 characters!  // Wrong error!
Choose your username: kok            // This should be accepted!
Your username CAN ONLY contain maximum 10 characters!  // Well, it is not... there should not be an error at all!

注意我在输出中添加的注释,以便您知道出了什么问题。 谢谢你的所有答案!

4 个答案:

答案 0 :(得分:2)

方括号中的内容并没有按照您的想法进行。

当你使用username1[10]代码时,你实际上说的是“让我在字符串中的第11位获取字符(请记住,索引从零开始)。

以下代码行......

...
else if (username1[3] < 0)
...

字面意思是“字符串中第4位的字符是否小于零?”,这显然是无稽之谈(ascii字符不能为负)。

您可能想说的是“username1的长度是否少于三个字符?”,在这种情况下,您应该使用::strlen方法,如下所示:

else if (::strlen(username1) < 3)

然而,另一个答案提到,如果您使用的是纯C ++,则可能根本不需要使用username1,您只需在原始username变量上调用std::string::size()即可。像这样:

else if (username.size() < 3)

您的代码以意想不到的方式工作的原因是因为您正在尝试查找字符串中不存在的字符。

想象一下:

username1: [ k | o | k | o | \0 | 4 | f | 6 | 7 | a | 3  | 3 ]
  indexes:   0   1   2   3    4   5   6   7   9   9   10   11

以上是一些原始内存的基本映像,如您所见,在零位置,您有字符串"koko",然后是空终止符,然后是许多未初始化的无关垃圾。当你说username1[10]时,你将超过输入字符串的末尾并进入与你的字符串变量无关的垃圾内存。所以if语句失败了!

然而,因为位置5-11中的字符未初始化,有时10位的字符可能为零,或者它可能是其他字符,或者它甚至可能导致程序崩溃!这就是所谓的未定义行为,您应该不惜一切代价避免它!

答案 1 :(得分:1)

将字符串“kokokokokoo”放入其中后,没有任何设置username1[10]回零。

如果您使用strncpy而不是strcpy,那么(a)您可以安全地避免缓冲区溢出,并且(b)strncpy将目标置零,这样您的程序就能像你一样工作希望的。

但实际上,正如其他评论所说,你应该在复制或使用之前检查字符串的长度。

答案 2 :(得分:1)

输入

kokokokokoo

然后ebtered

ko

字符数组username1包含以下内容

[k] [o] ['\0'] [o] [k] [o] [k] [o] [k] [o] [o] ['\0']
 0   1     2    3   4   5   6   7   8   9   10   11

if语句中的这个条件

if (isdigit(username1[0]) || isdigit(username1[1]) || isdigit(username1[2]))

是假的,因为三个字符[k] [o] ['\ 0']都不是数字。

这个条件

else if (username1[3] < 0)

也是假的,因为username1 [3]等于'o',大于零。

这个条件

else if (username1[10] > 0)

为真,因为username1 [10]等于'o'大于零。

输入字符串文字后

kok

username1变为

[k] [o] [k] ['\0'] [k] [o] [k] [o] [k] [o] [o] ['\0']
 0   1   2    3     4   5   6   7   8   9   10   11

事实上,相对于条件没有任何改变。由于username1 [10]等于大于零的“o”,因此您会得到消息

Your username CAN ONLY contain maximum 10 characters!

还不清楚为什么要将std :: string username类型的对象复制到字符数组username1中。

您可以使用username而不是username1进行所有检查,之后如果需要,您可以将用户名复制到username1。例如

if ( username.size() < 3)
{
    cout << "Your username HAS to contain atleast 3 letters!\n\a";
}
else if ( username.size() > 10)
{
    cout << "Your username CAN ONLY contain maximum 10 characters!\n\a";
}
else if ( isdigit( username[0] ) || isdigit( username[1] ) || isdigit( username[2] ) )
{
    cout << "The first 3 characters HAVE to contain only letters!\n\a";
}
//...

答案 3 :(得分:0)

您不知道工作原因的部分不起作用。你很可能根本不需要username1;你应该做的是用username.length()检查输入长度:

if (username.length() < 3) {
    // "too short" error
else if (username.length() > 10) {
    // "too long" error

您正在做的是检查字符串索引3和10处的(可能是不确定的垃圾)字符。 strcpy在将较短的内容复制到字符串中时不会擦除索引10。