当c ++期望一种数据类型并获得另一种数据类型时会发生什么?

时间:2018-09-20 16:31:59

标签: c++ c++11 types

我不熟悉c ++,正在用c ++ 11编写一个程序,该程序使用冒泡排序算法对整数列表进行排序。在执行此操作时,我发现了一些奇怪的东西。这是我的代码:

#include <iostream>
void bubbleSort(int x) {
  bool done;
  int list[x] {0};
  std::cout << "List:\n";
  for (int i=0;i<x;i++) {
    std::cout<<i<<':';
    std::cin>>list[i];
  }
  do {
    done = true;
    for (int i=0;i<x-1;i++) {
      if (list[i]>list[i+1]) {
        list[i] = list[i]+list[i+1];
        list[i+1] = list[i]-list[i+1];
        list[i] = list[i]-list[i+1];
        done = false;
        }
    }
  } while (not done);
  for (int i:list) {
    std::cout<<i<<' ';
  }
  std::cout<<std::endl;
}
int main() {
  int n;
  std::cout<<"Length of list: ";
  std::cin>>n;
  bubbleSort(n);
} 

如果我输入的是char而不是int,则程序会输出前导至列表长度的数字,然后是一串等于列表长度的零。

例如:如果我输入5,然后在输入中输入“ k”:

1:2:3:4:0 0 0 0 0 

我的问题是,为什么会产生此特定输出?如果数据类型错误,我会期望一个错误。抱歉,我的问题令人困惑。提前致谢。

1 个答案:

答案 0 :(得分:3)

如果在输入期望数字时输入k。然后流将进入错误状态。

问题是您没有检查状态:

  std::cin>>n;
  // There could be an error in the line above.
  // But you did not check for the error.

也在这里:

  std::cin>>list[i];
  // There could be an error in the line above.
  // But you did not check for the error.

尝试一下:

if (std::cin >> n) {
    std::cout << "It worked I got the number: " << n << "\n";
}
else
{
    std::cout << "Failed to read a number.\n";
}

以上内容如何工作。

operator>>的结果是对流的引用。因此它从流中读取一个值到n中,但返回对该流的引用。这使您可以执行以下操作:

std::cin >> n >> x >> y;

在每个operator>>之后,您将获得对流的引用以应用于下一个operator>>,以便可以将读取链接在一起。

当您在布尔上下文中使用流(如if或while之类的测试)时,它将根据其内部状态将其自身转换为布尔值。如果内部状态为std::cin.good(),那么它将返回true,否则返回false。

因此,在完成operator>>后,然后将其自身转换为if statement的布尔值。如果它处于良好状态,则说明读取有效。如果读取失败,它将设置内部失败状态,并且good()返回false。

那么您的代码中发生了什么。

读取失败,并且流的状态设置为失败。当读取失败时,首选的行为是被读取的对象保持不变(这是POD(标准)类型,用户定义的类型的情况,可能会更加随意)。

因此n的值保持不变。

当您声明n

int n;

您没有定义初始值,因此它具有不确定的值。这意味着尝试读取该值为UB。 UB不好。这意味着代码可以执行任何操作(已完成)。实际上(对于大多数系统),这意味着该变量具有未知值,并且是使用该变量的最后一个变量留在该内存位置的任何值。

针对您的具体情况:

因此,您首先输入了5,然后输入了k

因此,您的初读std::cin >> n;有效。 下次读取的std::cin>>list[i];失败。

这将流的状态设置为坏。随后的任何读取均不执行任何操作(直到将流状态重置为良好)。因此,您应该检测并修复流状态。

由于流处于错误状态,因此在循环的每个后续时间std::cin >> list[i]都不会执行任何操作。这意味着它将保留其原始值(在这种情况下,其定义为零0)。

再次执行正确的操作是读取并检查流的状态。如果失败,请采取纠正措施:

if (std::cin >> list[i]) {
    // Worked
}
else {
    std::cerr << "Bad input. Try again\n";
    // reset the state of the stream
    // before trying to read again.
    std::cin.clear();
    if (std::cin >> list[i]) {
        std::cerr << "You got it correct this time\n";
    }
    else {
        std::cerr << "User not bright enough to use the app aborting\n";
        throw std::runtime_error("Failed Bad User");
    }
}

附加说明

此流的行为非常适合读取用户输入。因为它允许自然的流程来检测和编写代码以供用户解决问题。对于具有相同模式的所有现代语言,该设计几乎是相同的。

但是当您有机器输入时,这并不是一个很好的流程(即,预期输入中没有任何错误,如果有错误,则无法纠正它)。

对于阅读机输入,您可以将流设置为引发错误。这样一来,您就可以编写清晰易读的代码,以防万一发生错误(当不应该发生错误时)并引发异常,从而导致应用程序正确终止(否则可能会捕获到异常)。

std::cin.exceptions(std::ios::badbit); // Fail and Bad