2014-11-06 2 views
1

Для предисловия, я довольно недавно начал программирование самостоятельно, и, таким образом, я почти как новичок, как они получают. Если вы заметили какие-либо плохие общие правила кодирования в моем коде (в том числе не относящийся к моему вопросу), пожалуйста, дайте мне знать, так как я, честно говоря,, вероятно, не знаю ничего лучше.Почему эта строка работает дважды и с ненормальным поведением?

Onto вопроса:

Я пытаюсь сделать небольшой фрагмент кода, чтобы заменить вхождения искомой строки с новой строкой. Я знаю, что существуют функции, которые значительно улучшат процесс (т. Е. Находят, заменяют и т. Д.), Для целей упражнения я избегаю этих и ограничиваю себя использованием итераторов, вставкой и стиранием. Я также знаю, что есть много других мест, где код может быть улучшен, и я бы тоже хотел получить информацию об этих частях, но я в первую очередь обеспокоен тем, что я считаю аномальным поведением. То, что я прямо сейчас:

#include <iostream> 
#include <string> 

bool scan(const std::string, const std::string::iterator); 

//replaces occurrences of oldVal in s with newVal 
std::string& replace (std::string &s, const std::string &oldVal, const std::string &newVal) 
{ 
    std::string::iterator iter = s.begin(); 
    while (iter != s.end()) { //process s 
     if (scan(oldVal, iter)) { //Checks if characters match 
      iter = s.erase(iter, iter + oldVal.size()); //deletes occurrence of oldVal 
      iter = s.insert(iter, newVal.begin(), newVal.end()); //inserts newVal in oldVal's place 
      iter = iter + newVal.size(); //continues processing after inserted newVal 
     } 
     else 
      ++iter; //Move to next character in s to process 
    } 
    return s; 
} 

//This function returns 1 if the strings match and 0 if they do not 
bool scan(const std::string target, std::string::iterator iter) 
{ 
    for (auto beg = target.begin(); beg != target.end(); ++beg) { 
     std::cout << "Line 27 " << *iter << " " << *beg << std::endl; //MAIN CONCERN! This line is run twice. 
                     //(It was solely added for debugging. Verifies values being compared) 
     if (*iter != *beg) { 
      std::cout << "Condition met; " 
         << *iter << " != " << *beg << std::endl; //added for debugging. Double verifies values post-comparison 
      return 0; 
      } 
     ++iter; 
     ++beg; 
    } 
    return 1; 
} 

int main() 
{ 
    std::string mainStr, oldStr, newStr; 
    std::getline(std::cin, mainStr); //Overall it'd be better for s to be a list of strings, but my concern is with line 27 
    std::cin.clear(); 
    std::cin >> oldStr >> newStr; 
    std::cout << "Output: " << replace(mainStr, oldStr, newStr) << std::endl; //Prints post-replacement string 
} 

То, что кажется, происходит то, что строка 27 (станд :: соиЬ < < «Линия 27» ...) выполняется в два раза первый раз сканирования называется. Например, данный вход:

tho 
tho though 

Я получаю выход (// являются комментариями, я добавляю в наружной пробеге, то есть только для этого поста)

Line 27 t t //This part is run twice and does weird things 
Line 27 h o //If it was just incrementing it should read "Line 27 h h" 
Condition met; h != o //This shouldn't happen; The condition should have tested t != t 
Line 27 h t //It's seems fine from this point onwards 
Condition failed; h != t 
Line 27 o t 
Condition failed; o != t 
Output: tho 

Что может быть причиной этого?

Спасибо!

+1

Я не знаю, почему он проголосовали за закрытие. Похоже на тему. Я не пробовал запускать его, но похоже, что @tea попытался его отладить. –

ответ

0

Есть пара проблем с предоставленным кодом. Основные вопросы, в «сканирования (...)», где вы incremeneting в «BEG» итератор дважды каждый раз вокруг петли, один раз в конструкции для():

for (auto beg = target.begin(); beg != target.end(); ++beg) 

и один раз на конец для цикла:

++iter; 
++beg; 

несколько незначительных точек в функции сканирования (...) будет проходить «цель» в качестве эталона (константной зОго :: строки & цели), и вернуться ложными/true, а не 0/1.

Я проверил это на Ubuntu 12.04, используя g ++ - 4.8, и, похоже, использует определение C++ 98 для вставки, которое не возвращает интернатор (т.е. функция «void insert (iterator p, InputIterator first , InputIterator last); ") .... Вот немного модифицированный код для устранения этой проблемы:

#include <iostream> 
#include <string> 

bool scan(const std::string&, const std::string::iterator); 

//replaces occurrences of oldVal in s with newVal 
std::string& replace (std::string &s, const std::string &oldVal, const std::string &newVal) 
{ 
    std::string::iterator iter = s.begin(); 
    while (iter != s.end()) { //process s 
     if (scan(oldVal, iter)) { //Checks if characters match 
      iter = s.erase(iter, iter + oldVal.size()); //deletes occurrence of oldVal 
      // Doesn't work on g++4.8 on Ubuntu, still seems to use the c++98 "void insert (iterator p, InputIterator first, InputIterator last);" 
      //iter = s.insert(iter, newVal.begin(), newVal.end()); //inserts newVal in oldVal's place 

      // If the iter == s.end(), then pos will not be the value we need. 
      size_t pos = iter == s.end()? s.size() : std::distance(s.begin(), iter); 
      s.insert(iter, newVal.begin(), newVal.end()); //inserts newVal in oldVal's place 
      iter = s.begin() + pos; 
      iter = iter + newVal.size(); //continues processing after inserted newVal 
     } 
     else 
      ++iter; //Move to next character in s to process 
    } 
    return s; 
} 

//This function returns 1 if the strings match and 0 if they do not 
bool scan(const std::string& target, std::string::iterator iter) 
{ 
    for (auto beg = target.begin(); beg != target.end(); ++beg) { 
     std::cout << "Line 27 " << *iter << " " << *beg << std::endl; //MAIN CONCERN! This line is run twice. 
                     //(It was solely added for debugging. Verifies values being compared) 
     if (*iter != *beg) { 
      std::cout << "Condition met; " 
         << *iter << " != " << *beg << std::endl; //added for debugging. Double verifies values post-comparison 
      return false; 
      } 
     ++iter; 
    } 

    return true; 
} 

int main() 
{ 
    std::string mainStr, oldStr, newStr; 
    std::getline(std::cin, mainStr); //Overall it'd be better for s to be a list of strings, but my concern is with line 27 
    std::cin.clear(); 
    std::cin >> oldStr >> newStr; 
    std::cout << "Output: " << replace(mainStr, oldStr, newStr) << std::endl; //Prints post-replacement string 
} 
+0

Спасибо (и вам, и cudahead)! Проблема с двойным ++ была именно моей проблемой. Как правило, лучше считать bools true и false вместо 1 и 0? Если это так, есть ли для этого конкретная причина? – tea

+0

Возможно только для удобства чтения. –

1

Одна ошибка, что я нашел: В scan()beg итератора увеличивается в два раза на каждой итерации, из-за ++beg в for(...) линии контура и beg++ в конце цикла.

Смежные вопросы