Непредсказуемый бесконечный для l oop в c ++ - PullRequest
0 голосов
/ 23 апреля 2020

Я пишу программу, которая возвращает первое вхождение символа и частоту этого символа в строке. Для l oop в функции выполняется бесконечное число раз, и если условие и блок не выполняются ни разу.

В чем проблема?

string::size_type find_ch(string &str,char ch,int& i_r)
{
    string::size_type first=0;
    for(auto i=str.size()-1;i>=0;i--)
    {
        cout<<"\nInside a for loop."<<endl;
        if(str[i]==ch)
        {
            cout<<"Inside if."<<endl;
            first=i+1;
            i_r++;
        }
    }
    return first;
}

Ответы [ 3 ]

2 голосов
/ 23 апреля 2020

Этот l oop:

for(auto i = str.size() - 1; i>=0; i--)

выйдет только тогда, когда i меньше 0. Но это недопустимое значение для unsigned int. Значение будет перенесено на максимум unsigned int, и вы получите бесконечное значение l oop.

Обратите внимание, что .size() для std::string возвращает size_t, что в основном равно unsigned int type.

Один из способов исправить это - привести тип возвращаемого значения .size() к int, например:

for(auto i = static_cast<int>(str.size()) - 1; i>=0; i--)

Обратите внимание, что важно выполнить приведение до вычитая 1, иначе вы получите неправильный ответ, когда str пусто.

В C ++ 20 вы можете полностью избежать этой проблемы, вызвав функцию std::ssize() free, который возвращает подписанную версию размера.

0 голосов
/ 24 апреля 2020

Вот ответ, аналогичный @Vlad From Moscow, но с использованием строковых функций и алгоритма std :: count .

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

std::pair<int,int> find_ch(const std::string &str, char ch)
{
    std::pair<int, int> ret;
    auto pos = str.find_first_of(ch);
    if ( pos == std::string::npos )
       return {-1,0};  // not found
    return { pos, std::count(str.begin() + pos, str.end(), ch) };
}

int main()
{
   auto pr = find_ch("abccabc", 'b');
   std::cout << "character b is at position " <<  pr.first << ".  Character count is  " << pr.second << "\n";
   pr = find_ch("abccabc", 'c');
   std::cout << "character c is at position " <<  pr.first << ".  Character count is  " << pr.second;
}

Вывод:

character b is at position 1.  Character count is  2
character c is at position 2.  Character count is  3

Каждая строка функции в основном описывает, что делается:

find_first_of символ в строке. Если найдено, верните эту позицию и std::count этого символа, начиная с первого вхождения.

Обратите внимание на краткость и самодокументированный способ написания функции. Программист C ++ может посмотреть на этот код и сразу узнать, что он делает, благодаря именам вызываемых функций.

Записывая циклы, идущие назад (как вы изначально это делали) с переменными, увеличенными здесь и там, программист должен сесть и go просмотреть код, чтобы выяснить, что он делает, и какова цель функция есть.

0 голосов
/ 23 апреля 2020

Определение функции в целом неверно.

Например, если данный символ не найден, то почему функция возвращает 0, которое является допустимой позицией?

Возвращает значение first=i+1; будет только сбивать с толку пользователей функции. Функция должна возвращать std::string::npos, если данный символ не найден.

Также совершенно неясно, почему l oop начинается с конца строки, а вам нужно вернуть первую позицию символа .

Что касается бесконечного l oop, то в l oop используется переменная i с целым типом без знака std::string::size_type, значение которого никогда не может быть отрицательным.

for(auto i=str.size()-1;i>=0;i--)
    ^^^^^^^^^^^^^^^^^^^

Это условие i >= 0 всегда верно по определению.

Функция должна быть определена следующим образом

std::pair<std::string::size_type, std::string::size_type> find_ch( const std::string &str, char ch )
{
    auto n = str.find( ch );

    std::pair<std::string::size_type, std::string::size_type> p( n, 0 );

    if ( n != std::string::npos )
    {
        ++p.second;
        while ( ( n = str.find( ch, n + 1 ) ) != std::string::npos ) ++p.second;
    } 

    return p;
}

Вот демонстрационная программа.

#include <iostream>
#include <string>
#include <utility>

std::pair<std::string::size_type, std::string::size_type> find_ch( const std::string &str, char ch )
{
    auto n = str.find( ch );

    std::pair<std::string::size_type, std::string::size_type> p( n, 0 );

    if ( n != std::string::npos )
    {
        ++p.second;
        while ( ( n = str.find( ch, n + 1 ) ) != std::string::npos ) ++p.second;
    } 

    return p;
}

int main() 
{
    std::string s( "C++ is not the same as C" );

    auto p = find_ch( s, 'C' );

    if ( p.first != std::string::npos )
    {
        std::cout << p.first << ": " << p.second << '\n';
    }

    return 0;
}

Вывод программы:

0: 2

Если вам не разрешено использовать методы класса std :: string, тогда просто подставьте вызовы метода find из функции выше в while петли, как показано ниже.

#include <iostream>
#include <string>
#include <utility>

std::pair<std::string::size_type, std::string::size_type> find_ch( const std::string &str, char ch )
{
    std::pair<std::string::size_type, std::string::size_type> p( std::string::npos, 0 );

    std::string::size_type n = 0;

    while ( n < str.size() && str[n] != ch ) ++n;

    if ( n != str.size() )
    {
        p.first = n;
        ++p.second;
        while ( ++n != str.size() )
        {
            if( str[n] == ch ) ++p.second;
        }           
    } 

    return p;
}

int main() 
{
    std::string s( "C++ is not the same as C" );

    auto p = find_ch( s, 'C' );

    if ( p.first != std::string::npos )
    {
        std::cout << p.first << ": " << p.second << '\n';
    }

    return 0;
}
...