为什么这条线路运行两次且行为异常?

时间:2014-11-06 08:11:31

标签: c++

前言,我最近开始自学编程,因此他就像新手一样。如果您在我的代码中发现任何不良的一般编码习惯(包括与我的问题无关),请告诉我,因为我真的可能不知道更好。

问题:

我正在尝试制作一小段代码,用新字符串替换目标字符串的出现。我知道存在可以大大改进过程(即查找,替换等)的函数,为了练习的目的,我正在避免这些并限制自己使用迭代器,插入和擦除。我也知道还有许多其他地方可以改进代码,我也喜欢这些部分的输入,但我主要关注的是我发现的异常行为。我现在拥有的是:

#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行(std :: cout&lt;&lt;“Line 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

这可能是什么原因?

谢谢!

2 个答案:

答案 0 :(得分:1)

我发现一个错误:在scan() beg迭代器在每次迭代中增加两次,原因是++beg循环线for(...)beg++在循环结束时。

答案 1 :(得分:0)

提供的代码存在一些问题。主要问题在'scan(...)',你在每次循环中都会增加'beg'迭代器两次,一次在for()构造中:

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

并且在for循环结束时一次:

++iter;
++beg;

scan(...)函数中的几个小点是将'target'作为引用传递(const std :: string&amp; target),并返回false / true,而不是0/1。

我在Ubuntu 12.04上使用g ++ - 4.8进行了检查,这似乎使用了c ++ 98定义的insert,它没有返回一个interator(即函数是“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
}