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

2015-11-06 13:43:47 +08:00
 bazingaterry
目的:去掉`std::deque`中不符合条件的元素,在下面的代码中,是把大写转成小写,把其他符号去掉。

```cpp
#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

请教下一为何会漏掉某些字符?
1338 次点击
所在节点    C
17 条回复
xc77
2015-11-06 13:55:05 +08:00
string.erase(it); 迭代器失效
xujunfu
2015-11-06 13:56:00 +08:00
string.erase(it);删除操作迭代器很有可能失效的了哦
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
2015-11-06 14:56:33 +08:00
再补充下,你头文件的引用为什么不用<>
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
2015-11-06 16:29:13 +08:00
@abscon 呃,考虑到你要处理的是字符串,用 list 其实也挺奇怪的。你为何不用 std::string 或者 vector<char> 。另外一定要 **原地** 做这件事情么? 不能从原容器复制到新容器,去掉非字母字符,转换大写字母到小写?
bazingaterry
2015-11-06 16:49:18 +08:00
@abscon 谢谢回复!

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

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

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/234144

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX