V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
bazingaterry
V2EX  ›  C

[提问] C++使用 STL 遇到的问题

  •  
  •   bazingaterry · 2015-11-06 13:43:47 +08:00 · 1365 次点击
    这是一个创建于 3338 天前的主题,其中的信息可能已经有所发展或是发生改变。

    目的:去掉std::deque中不符合条件的元素,在下面的代码中,是把大写转成小写,把其他符号去掉。

    #include "iostream"
    #include "deque"
    using namespace std;
    
    int main ()
    {
        deque<char> string;
        char ch;
        while((ch = getchar()) != EOF)
            string.push_back(ch);
    
        for (deque<char>::iterator it = string.begin(); it != string.end(); ++it)
        {
            if ('a' <= *it && *it <= 'z')
                continue;
            else if ('A' <= *it && *it <= 'Z')
                *it = tolower(*it);
            else
                string.erase(it);
        }
    
        while (!string.empty())
        {
            cout << string.front();
            string.pop_front();
        }
    }
    

    输入:

    das ;ds;a ;das; d;as
    d;as ;das; ;das

    输出:

    dasdsadasdasdas;das das

    请教下一为何会漏掉某些字符?

    第 1 条附言  ·  2015-11-07 00:55:50 +08:00

    查手册找到两句话

    All iterators and references are invalidated, unless the erased elements are at the end or the beginning of the container, in which case only the iterators and references to the erased elements are invalidated.

    Iterator following the last removed element. If the iterator pos refers to the last element, the end() iterator is returned.

    问题基本解决了,谢谢大家。

    17 条回复    2015-11-07 10:59:54 +08:00
    xc77
        1
    xc77  
       2015-11-06 13:55:05 +08:00
    string.erase(it); 迭代器失效
    xujunfu
        2
    xujunfu  
       2015-11-06 13:56:00 +08:00
    string.erase(it);删除操作迭代器很有可能失效的了哦
    womaomao
        3
    womaomao  
       2015-11-06 13:58:00 +08:00
    erase 的时候,迭代器已经指向下一个迭代位置了,你这个循环还是会++it ,所以跳过一个。下面应该可以了
    for (deque<char>::iterator it = string.begin(); it != string.end(); )
    {
    if ('a' <= *it && *it <= 'z')
    {
    ++it;
    continue;
    }
    else if ('A' <= *it && *it <= 'Z')
    {
    *it = tolower(*it);
    ++it;
    }
    else
    string.erase(it);
    }
    firemiles
        4
    firemiles  
       2015-11-06 14:56:33 +08:00
    再补充下,你头文件的引用为什么不用<>
    abscon
        5
    abscon  
       2015-11-06 16:22:18 +08:00
    为何选用 deque 而不是 list 。我觉得你的“目的”(去掉 std::deque 中不符合条件的元素)好别扭。

    几点建议:
    包含标准头文件时请使用尖括号而不是引号
    可以用 auto 来代替 deque<char>::iterator
    可以使用 islower 和 isupper 来判断大小写 #include <cctype>
    getchar 在 <cstdio> 里。而且你输入用 getchar ,输出用 cout ,感觉是西装配短裤。
    deque<char> string 这个变量名取得相当糟糕,与 std::string 重名了
    abscon
        6
    abscon  
       2015-11-06 16:29:13 +08:00
    @abscon 呃,考虑到你要处理的是字符串,用 list 其实也挺奇怪的。你为何不用 std::string 或者 vector<char> 。另外一定要 **原地** 做这件事情么? 不能从原容器复制到新容器,去掉非字母字符,转换大写字母到小写?
    bazingaterry
        7
    bazingaterry  
    OP
       2015-11-06 16:49:18 +08:00
    @abscon 谢谢回复!

    1. 只是昨晚 Coding 遇到这样的问题,我举个例子说出来,实际上并不是处理字符。
    2. 代码是临时打的,新手可能不规范,望包涵, Sublime Text 默认是用""而不是<>我没改过来。
    bazingaterry
        8
    bazingaterry  
    OP
       2015-11-06 16:51:07 +08:00
    @abscon auto 我也很喜欢在平时学校的项目中使用,但是我学校 OJ 不支持 C++11 ,所以平时基本不能用。
    bazingaterry
        9
    bazingaterry  
    OP
       2015-11-06 16:53:20 +08:00
    @xc77
    @xujunfu
    @womaomao

    感谢回复,大概知道问题所在。
    但想深入了解一下,为何前面输入的被删除了,后面同样情况却没删除?
    迭代器失效是随机的吗?
    bazingaterry
        10
    bazingaterry  
    OP
       2015-11-06 16:56:31 +08:00
    @abscon
    至于为何选用 deque 而不是 list ,是因为删除之后还有大量的随机访问操作。
    谢谢指教,我应该把数据从原容器复制到新容器。
    xc77
        11
    xc77  
       2015-11-06 17:23:07 +08:00
    @bazingaterry erase 后会指向 deque 的下一个位置, 所以你需要 it = string.erase(it),来保存新的位置
    前面成功,可能是因为在处理到后面是内存进行了重新分配
    bazingaterry
        12
    bazingaterry  
    OP
       2015-11-06 17:41:50 +08:00
    @xc77 明白了!!谢谢!!
    colatin
        13
    colatin  
       2015-11-06 17:43:47 +08:00
    改成 erase(it++)试试看
    hqs123
        14
    hqs123  
       2015-11-06 23:33:13 +08:00
    C++不熟,我也来学习下 多谢分享。
    yhylord
        15
    yhylord  
       2015-11-07 09:11:09 +08:00
    是强制需要用 std::deque 么?我觉得读入,判断,输出就已经足够了,不需要中间储存的一步。
    yhylord
        16
    yhylord  
       2015-11-07 09:17:14 +08:00
    @yhylord 哦你还有大量的随机操作么……当我没说……
    kxcd
        17
    kxcd  
       2015-11-07 10:59:54 +08:00
    iterator erase (iterator position);
    iterator erase (iterator first, iterator last);

    erase 返回值为 iterator , it = string.erase(it);

    ps: string 变量命名,噗...
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3272 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 11:40 · PVG 19:40 · LAX 03:40 · JFK 06:40
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.