我正在尝试解析std::string
,将其拆分,然后将其存储在2D char数组中。此数组的第一行将包含总行数。
我在getC_strings()
函数内动态分配数组,当我打印它时,我得到了预期的结果。但是,当我再次从main()
打印时,我会得到垃圾,排0,2。我做错了什么?
#include <iostream>
#include <string>
#include <vector>
#include <boost/algorithm/string/classification.hpp> // Include boost::for is_any_of
#include <boost/algorithm/string/split.hpp> // Include for boost::split
using namespace std;
/**
*
* @param input a string separated by spaces
* @param numArgs_ an int
* @param cargs a const char ** something. Pass it by its address aka &something.
*/
static inline void getC_strings(const std::string & input, int & numArgs_, const char *** cargs) {
std::vector<std::string> args;
boost::split(args, input, boost::is_any_of(" "), boost::token_compress_on);
numArgs_ = int(args.size());
*cargs = new const char* [numArgs_ + 1];
// store the number of rows at the first row
(*cargs)[0] = new char[to_string(numArgs_).size()];
(*cargs)[0] = to_string(numArgs_).c_str();
// write the characters from the vector per row
int ind = 0;
for(auto const &v:args) {
ind++;
(*cargs)[ind] = new char [int(v.size())];
if((*cargs)[ind] == NULL) std::cout << "OUT OF MEMORY! " << std::endl;
(*cargs)[ind] = const_cast<char*>(v.c_str());
}
for(int i = 0; i < numArgs_; ++i) {
std::cout << i << " " << (*cargs)[i] << std::endl;
}
}
int main () {
string arg = "test ./MyDirectoryName/OPQ_Arksoatn.txt 1 SOMETHING 1 2 3 4 5 6 7";
int numCargs = 0;
const char ** cargs;
getC_strings(arg, numCargs, &cargs);
cout << " ==============================================" << endl;
for(int i = 0; i < numCargs; ++i) {
std::cout << i << " " << cargs[i] << std::endl;
}
return 0;
}
输出:
0 11
1 test
2 ./MyDirectoryName/OPQ_Arksoatn.txt
3 1
4 SOMETHING
5 1
6 2
7 3
8 4
9 5
10 6
==============================================
0 ��`
1 test
2 `��
3 1
4 SOMETHING
5 1
6 2
7 3
8 4
9 5
10 6
答案 0 :(得分:2)
您可以尝试这种不会泄漏内存的方法。它是从解决方案found here精心设计的。
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <boost/algorithm/string/classification.hpp> // Include boost::for is_any_of
#include <boost/algorithm/string/split.hpp> // Include for boost::split
using namespace std;
class CharStarWrapper
{
private:
typedef std::vector<char> CharArray;
typedef std::list<CharArray> StringList;
typedef std::vector<const char *> ArgList;
const char** m_Args;
StringList m_sList;
ArgList m_cStrings;
public:
CharStarWrapper(const std::string & input) : m_Args(nullptr)
{
std::vector<std::string> args;
boost::split(args, input, boost::is_any_of(" "), boost::token_compress_on);
for (auto const &v : args)
{
// create an array of char and place on list
m_sList.push_back(CharArray(v.begin(), v.end()));
// null terminate this entry
m_sList.back().push_back(0);
// add the pointer to this entry to the vector of const char *.
m_cStrings.push_back(&m_sList.back()[0]);
}
m_Args = m_cStrings.data();
}
const char** getArgs() { return m_Args; }
int getArgCount() const { return static_cast<int>(m_cStrings.size()); }
};
void fake_main(int argc, const char **argv)
{
std::cout << "The number of arguments is " << argc << "\n";
for (int i = 0; i < argc; ++i)
std::cout << argv[i] << "\n";
}
int main() {
string arg = "test ./MyDirectoryName/OPQ_Arksoatn.txt 1 SOMETHING 1 2 3 4 5 6 7";
CharStarWrapper wrapper(arg);
fake_main(wrapper.getArgCount(), wrapper.getArgs());
}
基本上,我们将const char**
包装在一个类中。此类维护动态字符串数组,仅提供public
成员函数以返回const char**
以及参数数量。打电话给假冒&#34; main()
函数演示了用法。
没有调用new[]
,delete[]
,strdup
等要求调用释放例程以避免内存泄漏的调用。当包装器超出范围时,所有内存都会自动清理。
请注意,此解决方案依赖于包装器对象在您使用const char **
值的生命周期内不会超出范围。原因是CharStarWrapper
维护基础设施,并且在使用基础设施时销毁基础设施将是不正确的。
答案 1 :(得分:1)
在以下几个地方:
// store the number of rows at the first row
(*cargs)[0] = new char[to_string(numArgs_).size()];
(*cargs)[0] = to_string(numArgs_).c_str();
和
// Similar code that allocates then ignores some space
(*cargs)[ind] = const_cast<char*>(v.c_str());
您正在执行指向std :: string内部部分的指针。您需要将其复制到数组中,以便在char数组结构中使用它。 (见strdup)。
替换为:
(*cargs)[0] = strdup(to_string(numArgs_).c_str());
和
(*cargs)[ind] = strdup(v.c_str());