拆分函数引发错误
Split function throws error
我正在尝试创建一个函数来将字符串"Split At Spaces"拆分为包含"Split"At"Spaces"的向量。 到目前为止,这是我得到的代码。
#include <iostream>
#include <utility>
#include <algorithm>
using namespace std;
std::vector<std::string> split(std::string * s, char * tosplit)
{
size_t i = 0;
int count = 0;
size_t contain;
std::vector<std::string> split;
std::cout << "Start" << std::endl;
std::cout << *s << std::endl;
std::cout << *tosplit << std::endl;
while((contain = s->find(*tosplit,i)) != std::string::npos)
{
count++;
i = contain + 1;
}
std::cout << "Contains " << count << std::endl;
if (count == 0)
{
std::cout << "Equals 0" << std::endl;
split = std::vector<std::string>(1);
split.at(0) = s->c_str();
return split;
}
split = std::vector<std::string>(count + 1);
split.begin();
int lasti;
i = s->find_first_of(*tosplit);
split.at(0) = s->substr(0, i);
lasti = i;
int runs = 1;
while (runs <= count)
{
i = s->find(*tosplit, lasti + 1);
std::cout << i << " " << lasti << std::endl;
split.at(runs) = s->substr(lasti, --i);
runs++;
lasti = i;
}
split.at(runs) = s->substr(lasti, s->size());
std::cout << "done, result is" << std::endl;
i = 0;
while (i < split.capacity())
{
std::cout << split.at(i) << std::endl;
i++;
}
return split;
}
它会引发out_of_range异常。 您能提供的任何帮助将不胜感激。 这就像我在函数中使用指针的第一部分,所以我在这里有点猜测。
谢谢!
请不要建议使用 x 或 y 方法,我想写我自己的方法,因为我是为了体验而这样做。
以下是我发现的一些问题:
- 在检查 NULL 指针之前取消引用
s
。 - 在检查 NULL 之前取消引用
tosplit
。 - 而不是计算字符串的数量,然后拆分字符串(需要 2 次搜索),按搜索计数。
- 当您通过它时,
i = contain + 1
的位置可能超出范围到while
循环中的表达式。 - 尝试使用方法
std::vector::push_back
而不是分配在一个特定的,也许是未分配的位置。 - 语句
return split
返回字符串数组的副本。你真的要返回一个大型数据结构吗? - 语句
split.begin()
将迭代器返回到开头的载体;你不使用的。 - 使用
split.size()
而不是split.capacity
。 它们是两个不同的概念。
这实际上很容易做到,例如 std::istringstream
和std::copy
,以及标准迭代器库的一些帮助。
对于那些想要查看工作代码的人,可以在这里找到它。
对于链接中的代码,整个程序是 18 行,其中实际拆分是三行,但那是因为我拆分它以使其更具可读性(它实际上是单个函数调用)。
对于更通用的解决方案,如果可以使用C++ 11 个正则表达式(或 Boost 正则表达式或其他一些正则表达式库可用)。
单个分隔符:
你写了太多的代码来做到这一点。你可以用几行字来完成。你变得过于复杂了。而且没有理由为此真正使用指针做任何事情。
vector<string> Split(string s, char delim)
{
vector<string> strings;
for(istringstream ss(s); getline(ss, s, delim); strings.push_back(move(s)));
return strings;
}
多个分隔符:
使用多个分隔符的解决方案更为复杂。你不能再利用getline
,这意味着你基本上是在自己编写getline
功能的一部分。但是,它仍然可能很短。
vector<string> Split(const string& s, const char* delims)
{
vector<string> strings;
for(string::size_type start = 0, end; end != string::npos && start < s.size(); start = end+1)
{
end = s.find_first_of(delims, start);
strings.push_back(s.substr(start, end-start));
}
return strings;
}
当分隔符彼此相邻时,这将添加空白字符串。如果这不是相邻分隔符的所需行为,则可以通过使用 if(start != end)
保护push_back
来轻松避免这种情况。
结论:
当你开始编写这样的低级算法时,用广义的术语来伪编码它,然后在编写任何代码之前检查C++标准库可以提供什么来削减部分或全部工作。你最终会得到更小、更不容易出错、更易于理解的代码。例如,没有人希望看到find_first_of
的手动滚动实现。阅读单词find_first_of
要清楚得多.很明显该函数将要做什么,并且它没有错误(希望如此)。
与其尝试为向量预先分配空间,只需使用 push_back 在找到零件时附加它们。
对不起,我不禁认为你的函数过于复杂。如果你想自己编写逻辑来学习,而不是使用一些预先打包的功能,那很好,但这并不意味着你不应该保持逻辑简单。
我相信你的算法应该看起来更像这个:
// Note that the delimiter can be a string as well, not just a char
vector<string> split(string const& s, string const& delimiter)
{
vector<string> result;
string::size_type startPos = 0;
string::size_typepos = s.find(delimiter);
while (pos != string::npos)
{
// Extract token and save it...
string token = s.substr(startPos, pos - startPos);
result.push_back(token);
// Step to next token...
startPos = pos + 1;
pos = s.find(delimiter, pos + 1);
}
// Parse last token (in case the string is not terminated
// by the delimiter).
if (startPos < s.length())
{
string lastToken = s.substr(startPos);
result.push_back(lastToken);
}
return result;
}
- 链接器错误:函数的多个定义
- 编译器错误:函数调用在常量表达式中必须有一个常量值
- 错误:函数声明符之后的预期函数体
- C 错误 - 函数不能超载
- 如何修复传递参数时调用错误函数的主函数?(C++)
- 错误:函数调用中有两个参数
- 错误:函数不是“类”的静态数据成员 - C++
- C ,G 编译错误函数
- CMake 解析错误函数缺少结尾")"。而是找到带有文本的未终止字符串")
- C++ 错误 函数 2 的多重定义
- 错误:函数调用中从int到int(*)[4]的转换无效
- C++14 自动扣除错误:函数返回一个数组
- 视觉C++错误:函数必须返回一个值
- 错误:函数声明中的两种或多种数据类型
- 错误:函数未在作用域中声明
- rtw_android.c错误:函数“strnicmp”的隐式声明[-Weror=隐式函数声明]
- 错误:函数中的return语句没有值,返回“void*”[-fpermission]
- 简单程序中的链接器错误:函数的多重定义
- 错误:函数参数太多
- 错误:函数__tmaincrtstartup中引用的未解析的外部符号_main