【问题标题】:Answer difference between two compiler回答两个编译器的区别
【发布时间】:2016-02-01 15:58:10
【问题描述】:

我编译了以下代码,但我遇到了一个严重的问题。 当我在 Visual Studio 2015 中编译此代码时,它运行良好。 但是,当我在 Dev C++ 中编译此代码时,我认为它不会打印“是”作为答案。

例如,当我输入类似的字词时,

  1. 哈哈
  2. 我看到的是汽车还是猫?
  3. abcdefghiihgfedcba

这些输入必须返回 yes,但在 dev c++ 中返回 no。

为什么会出现这个问题?

#include <iostream>
#include <string>
using namespace std;

bool is_palindrome(char input[], int numOfSlots);

int main(void) {

   char text[256], fixed[256];
   cin.getline(text, sizeof(text), '\n');

   for (int i = 0; i < sizeof(text); i++) {
      text[i] = toupper(text[i]);
   }

   int j = 0;
   for (int i = 0; i < sizeof(text); i++) {
      if ((text[i] >= '0' && text[i] <= '9') || (text[i] >= 'A' && text[i] <= 'Z')) {
         fixed[j] = text[i];
         j++;
      }
   }
   fixed[j] = '\0';
   string s_fixed = fixed;

   if (is_palindrome(fixed, s_fixed.length()) == true) {
      cout << "Yes";
   }
   else {
      cout << "No";
   }
   return 0;
}

bool is_palindrome(char input[], int numOfSlots) {
   int i = 0;
   while (i < numOfSlots / 2)
   {
      if (input[i] != input[(numOfSlots - 1) - i])
         return false;
      i++;
   }
   return true;
}

【问题讨论】:

  • 您可以简单地添加一些诊断输出以查看正在发生的比较以及他们的答案是什么。这比发布您的程序并希望其他人愿意为您执行此操作要高效得多。
  • 听起来您可能需要学习如何使用调试器来单步调试您的代码。使用好的调试器,您可以逐行执行您的程序,并查看它与您期望的偏差在哪里。如果您要进行任何编程,这是必不可少的工具。进一步阅读:How to debug small programs
  • 如果你被允许使用std::string,你为什么在那里使用char[]?

标签: c++ compiler-errors


【解决方案1】:

您的程序表现出未定义的行为,因为您使用的是未初始化的数据。

你有:

char text[256], fixed[256];

这是未初始化的数组。然后你去访问他们使用:

for (int i = 0; i < sizeof(text); i++) {
   text[i] = toupper(text[i]); // Accessing uninitialized array
}

您可以通过以下几种方式修复它:

  1. 初始化数组。

    char text[256] = {0}, fixed[256] = {0};
    
  2. 仅访问在对getline 的调用中填写的元素。

    size_t size = strlen(text);
    for (int i = 0; i < size; i++) {
    

但是,更好的解决方法是始终使用第二种方法。这样,您就不会处理不必要的数据。

【讨论】:

  • sizeof(text) 应该是 256。你可能会想到strlen(text),此时确实是 UB。是的,他可能不应该遍历整个数组,但我不认为他当时正在做的是 UB。
  • @mah,访问text[i] 超出getline 填充的内容会导致未定义行为。
  • 初始化数组不会修复编程错误 - 使用 sizeof() 而不是 strlen()
  • 我已经删除了我的 cmets;查看聊天日志以了解我的启示,但代码的真正 UB 问题是循环将数据从 text 复制到 fixed,而在 text 为 NULL 时不会停止。
  • 最好还是使用std::string
【解决方案2】:

使用std::string 代替strlen() 是相当奇怪的,当你可以更好地使用它时:

bool is_palindrome( const std::string &input );

int main(void) {

   std::string text;
   getline(cin,text);

   for (size_t i = 0; i < text.length(); i++) {
      text[i] = toupper(text[i]);
   }

   std::string fixed;
   for (size_t i = 0; i < text.length(); i++) {
      if ((text[i] >= '0' && text[i] <= '9') || (text[i] >= 'A' && text[i] <= 'Z')) {
         fixed += text[i];
      }
   }

   if (is_palindrome(fixed)) {
      cout << "Yes";
   }
   else {
      cout << "No";
   }
   return 0;
}

bool is_palindrome(const std::string &input) {
   size_t numOfSlots = input.length();
   int i = 0;
   while (i < numOfSlots / 2)
   {
      if (input[i] != input[(numOfSlots - 1) - i])
         return false;
      i++;
   }
   return true;
}

当然你的程序可以简化,但我尽量让它接近原始程序,以说明为什么在 C++ 中使用 std::string 而不是旧式 char[] 更好

这里使用std::string 和标准库中的其他算法的简化版本:

#include <iostream>
#include <string>
#include <algorithm>

bool is_palindrome( std::string str )
{
   if( str.empty() ) return false;
   std::transform( str.begin(), str.end(), str.begin(), []( char c ) { return std::toupper( c ); } );
   str.erase( std::remove_if( str.begin(), str.end(), []( char c ) { return !std::isalnum( c ); } ), str.end() );
   auto len = str.length() / 2 + 1;
   return std::string( str.begin(), std::next( str.begin(), len ) ) ==
          std::string( str.rbegin(), std::next( str.rbegin(), len ) );
}


int main()
{
   std::string text;
   std::getline( std::cin, text );

   std::cout << ( is_palindrome( text ) ? "yes" : "no" ) << std::endl;

   return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-09
    • 2017-01-02
    相关资源
    最近更新 更多