试图传递二维数组的字符,但得到垃圾

时间:2017-03-16 23:17:59

标签: c++ arrays

我正在尝试解析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

2 个答案:

答案 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());        
}

Live Example

基本上,我们将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());