【问题标题】:Infinite loop using string.substr(post,len)使用 string.substr(post,len) 的无限循环
【发布时间】:2020-12-07 02:06:22
【问题描述】:

你能弄清楚为什么它一直在控制台中无限循环吗?程序员应该列出用户插入字符串的每个字符,并在每个唯一字符旁边的括号中显示该字符在字符串中出现的次数......不知道为什么。

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

int main () {
  string input;
  cout << "input string: " , cin >> input;
  sort (input.begin() , input.end());
  while (!input.empty()) {
    int j{1}, i{0};
    while (input.at(i) == input.at(i+1)) {
      j++;
      i++;
    }
    cout << input.at(i) << " (" << j << "), ";
    input.substr(i);
  }
  return 0;
}

【问题讨论】:

  • 哦,哇,它应该是string = string.substr(post,len),谢谢它现在抛出一个 std::out of range 错误......
  • 好的,我知道了,谢谢
  • @Biaaach string::at() 执行边界检查,如果给定索引超出范围,将引发异常。当i 到达input 的最后一个字符时,input.at(i+1) 将越界。
  • @RemyLebeau 我知道,但是如何在不使用尾递归的情况下解决这个问题?

标签: c++ string while-loop


【解决方案1】:

此声明

input.substr(i);

不会更改对象input 本身。

因此,如果某些索引 i input.at(i) 不等于 input.at(i+1),您将有一个无限循环,或者您可能有一个超出范围的异常,因为 i + 1 可以等于 input.size() .

来自成员函数at的描述

如果 pos >= size(),则抛出:out_of_range。

该程序可以以不同的方式实施。比如下面这种方式

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

int main() 
{
    std::cout << "input string: ";
    std::string input;
      
    std::cin >> input;
      
    std::sort( input.begin() , input.end() );
    
    for ( size_t i = 0; i < input.size(); )
    {
        size_t j = input.find_first_not_of( input[i], i );
        
        if ( j == std::string::npos ) j = i + 1;
        
        if ( i != 0 ) std::cout << ", ";
        std::cout << input[i] << " (" << j - i << ")";

        i = j;
    }
    
    std::cout << '\n';
    
    return 0;
}

程序输出是

input string: Hello
H (1), e (1), l (2), o (1) 

或者你可以使用标准容器std::mapstd::unordered_map作为例子

#include <iostream>
#include <string>
#include <map>

int main() 
{
    std::cout << "input string: ";
    std::string input;
      
    std::cin >> input;
      
    std::map<char, size_t> m;
    
    for ( const auto &c : input )
    {
        ++m[c];
    }

    bool first = true;
    for ( const auto &p : m )
    {
        if ( !first  ) std::cout << ", ";
        std::cout << p.first << " (" << p.second << ")";
        first = false;
    }
    
    std::cout << '\n';
    
    return 0;
}

如果您希望输入字符串的字符按照它们在字符串中出现的顺序输出,那么程序可以看起来像

#include <iostream>
#include <string>
#include <map>

int main() 
{
    std::cout << "input string: ";
    std::string input;
      
    std::cin >> input;
      
    auto less = [&input]( const auto &c1, const auto &c2 )
    {
        return input.find( c1 ) < input.find( c2 );
    };
    
    std::map<char, size_t, decltype( less )> m( less );
    
    for ( const auto &c : input )
    {
        ++m[c];
    }
    
    bool first = true;
    
    for ( const auto &p : m  )
    {
        if ( !first  ) std::cout << ", ";
        std::cout << p.first << " (" << p.second << ")";
        first = false;
    }
    
    std::cout << '\n';
    
    return 0;
}

或者在不改变原始字符串且不使用额外容器的情况下,程序可以如下所示。

#include <iostream>
#include <string>

int main() 
{
    std::cout << "input string: ";
    std::string input;
      
    std::cin >> input;
      
    for ( size_t i = 0; i < input.size(); i++ )
    {
        size_t j = 0;
        
        while ( j != i && input[j] != input[i] ) j++;
        
        if ( j == i )
        {
            size_t count = 1;
            while ( ++j < input.size() )
            {
                if ( input[j] == input[i]  ) ++count;
            }
            if ( i != 0  ) std::cout << ", ";
            std::cout << input[i] << " (" << count << ")";
        }
    }
    
    std::cout << '\n';
    
    return 0;
}

程序输出可能看起来像

input string: elephant
e (2), l (1), p (1), h (1), a (1), n (1), t (1)

【讨论】:

  • 没有未定义的行为,因为input.at(i+1) 会引发异常。您可能会想到 string::operator[],在 C++11 之前,它确实对于越界索引具有未定义的行为。但是从 C++11 开始,operator[] 允许 index==size(),但 string::at() 不允许。
  • 啊,那我把这一切都想错了..必须是编写这段代码的更好方法..
  • @VladfromMoscow 这是非常确凿的感谢一堆
  • @VladfromMoscow 您使用 size_t 而不是 unsigned int 有什么特别的原因吗?
  • @Biaaach 感谢您的建议。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-23
  • 2021-12-19
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多