不断擦除字符串会导致无限循环

时间:2015-07-23 14:52:41

标签: c++ linux stdstring

我要做的是先走一条路径,然后按目录不断擦除路径目录,检查它是否是任何一点的符号链接。这就是我所拥有的:

static bool isLinkDirInSymLink (std::string linkPath)
    {
    DIR *baseDir;
    struct dirent *currentDir;

    do
        {
        baseDir = opendir(linkPath.c_str());
        if (baseDir)
            {
            currentDir = readdir(baseDir);
            if (currentDir->d_type == DT_LNK)
                return true;
            }
        linkPath.erase (linkPath.find_last_of("/") + 1, linkPath.find_first_of("\0"));
        } while (strcmp(linkPath.c_str(), "") != 0);

    return false;
    }

这会陷入无限循环。当我在gdb中运行该程序时,我发送了linkPath /home/user/test/linktest/out/mDirs/testDir1/test的{​​{1}},当成功删除并且我留下的是/home/user/test/linktest/out/mDirs/testDir1时,这就是无限循环开始。即使它与进入erase的第一条路径的格式相同,也没有任何反应。我尝试了erase linkPath.append('\0')的许多不同版本,但似乎都没有。我也试过char realPath[MAX_FILELENGTH]; do { if (realpath (linkPath.c_str(), realPath) != NULL) if (strcmp(linkPath.c_str(), realPath) != 0) return true; size_t eraseFrom = linkPath.rfind('/'); if (std::string::npos != eraseFrom) linkPath.erase(eraseFrom); } while ( !linkPath.empty() ); return false; ,因为我觉得这可能是最后一个空字符的问题。

谢谢大家,这就是我最终的目标:

<button data-key="some value" name="" id="">click me</button>

5 个答案:

答案 0 :(得分:3)

linkPath.find_last_of("/") + 1

应该是;

linkPath.find_last_of("/")

第一次擦除会留下尾随/,因此下一次擦除会尝试从字符串末尾擦除到结尾,因此循环。擦除应包括目录分隔符/

不需要linkPath.find_first_of("\0"),您可以使用npos删除字符串的末尾。使用find_first_of会给出尺寸类型结果,因此使用以下形式的擦除basic_string& erase( size_type index = 0, size_type count = npos );

答案 1 :(得分:3)

由于您在擦除呼叫中+ 1,您正在删除从/之后到字符串结尾之前的字符,删除以下字符:

/home/user/test/linktest/out/mDirs/testDir1/test\0
                                            ^^^^

循环的第一次迭代将删除test,留下/home/user/test/linktest/out/mDirs/testDir1/。对erase的所有后续调用都不会执行任何操作,因为/\0之间的字符数为零。

您应该从擦除调用中移除+ 1 linkPath.find_last_of("/") + 1,以便删除尾部斜杠。

此外,erase(size_t, size_t)重载实际上将部件的 length 擦除为第二个参数 - find_first_of返回找到的字符的索引,而不是迭代器它。您的代码只能偶然使用。使用std::string::npos,它将删除所有内容,直到结尾,而不是\0字符的位置(如果您尚未调用c_str(),则可能不会出现在字符串中)。

答案 2 :(得分:1)

我猜你在查看调试器时错过了斜杠。这可能更好:

linkPath.erase (linkPath.begin()+linkPath.find_last_of("/"), linkPath.end());

另一个问题是std::string::erase的错误重载被调用:this list中的#1(“pos + len”),而你可能想要#3(“范围”)。这是因为std::string::find_last_of返回size_t,而不是迭代器。或者,为了节省输入,您可以使用:

linkPath.resize(linkPath.find_last_of("/"));

答案 3 :(得分:0)

我认为你的意思如下:

#include <iostream>
#include <string>

int main()
{
    std::string linkPath( "http://stackoverflow.com/questions/31590945/"
                          "continually-erasing-string-leads-to-infinite-loop" );

    do
    {
        std::cout << linkPath << std::endl;

        auto n = linkPath.rfind( '/' );
        n = n == std::string::npos ? 0 : n;

        linkPath.erase( n );
    } while ( !linkPath.empty() );        
}    

程序输出

http://stackoverflow.com/questions/31590945/continually-erasing-string-leads-to-infinite-loop
http://stackoverflow.com/questions/31590945
http://stackoverflow.com/questions
http://stackoverflow.com
http:/
http:

当然,您可以根据需要修改代码。它演示了完成任务的方法。

至于你的代码然后这个电话

linkPath.find_first_of("\0")

将始终返回std::string::npos。所以它不是男性意识。 并使用此表达式

linkPath.find_last_of("/") + 1

将始终保留第一个找到的字符&#39; /&#39;在字符串中。

答案 4 :(得分:0)

更正确和简化的实施

static bool isLinkDirInSymLink(std::string linkPath) {
    DIR * baseDir;
    struct dirent * currentDir;
    do {
        baseDir = opendir(linkPath.c_str());
        if (baseDir) {
            currentDir = readdir(baseDir);
            if (currentDir->d_type == DT_LNK) return true;
        }
        std::string::size_type it = linkPath.rfind('/');
        if (it != std::string::npos) linkPath.erase(it);
    } while (!linkPath.empty());
    return false;
}