Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Convert QStringList to QVector<const char*>



  • I'm trying convert QStringList to const char**. I decide make copy to QVector<const char*> and next invoke data() member func. But somthing went wrong :)
    Can you explain next behavior:

    1. At code snippet 1 I'm get output ENDING, ENDING, ENDING, ENDING, but in 2 as expected - wordFirst , Second, 123456789 , ENDING???

      QStringList qtStrings{};
      qtStrings << "wordFirst" << "Second"<< "123456789" << "ENDING";
      vector<std::string> stlStrings { "wordFirst" , "Second", "123456789" , "ENDING"};
      
      // 1
      QVector<const char*> v4;
      for(const auto& qtSt : qtStrings) {
          v4.push_back(qtSt.toStdString().c_str());
      }
      for(int i(0); i < v4.size() ; ++i) {
          cout << " "  << v4.at(i) << endl;
      }
      
      //2
      QVector<const char*> v6;
      for(const auto& stlSt: stlStrings) {
          v6.push_back(stlSt.c_str());
      }
      for(int i(0); i < v6.size() ; ++i) {
          cout << " " << v6.at(i) << endl;
      }
      
    2. What is the gaps after elements in vector in next code?

    qt.png

        QVector<const char*> v6;
        for(const auto& stlSt : stlStrings) {
            v6.push_back(stlSt.c_str());
        }
        for(int i(0); i < v6.size() ; ++i) {
            cout << " " << v6.at(i) << endl;
        }
    
    1. And, what is correct way convert QStringList to const char**?

    Thanks.



  • c strings are null terminated. This is represented by the character int value 0.

    In 1. you are copying only the pointer to a location in memory and not the string itself. If you want to copy the memory you will to create a structure that can hold that memory. Then copy the string into that memory. Later you will have to delete that memory as well.

    c_str() is returning a pointer that on last call is pointing to ENDING. Apparently the temporary buffer it is using is the same for the pointers you get.

    new char[str_length+1] // need the +1 for the null termination
    std::memcpy to copy data into that location

    Later you will need to delete that memory you allocated.



  • But why vector does not allocate memory for const char* by themselves? Why I need stoop to C-style? I think memory allocation by hands breaks down adjacent memory locations.

    My implementation for 3

       const auto stringCount { qtStrings.size() };
       std::size_t size {
           std::accumulate(qtStrings.begin(), qtStrings.end(), 0,
               [](std::size_t sz, const QString& str) {
                   return std::plus<std::size_t>()(sz, str.size());
               })
           + static_cast<std::size_t>(stringCount) //for '\0'
       };
    
       QScopedArrayPointer<char> array { new char[size] };
       std::memset(array.data(), '\0', size);
       char* index { array.data() };
       char* resultArray[stringCount];
       quint16 k{0};
       std::for_each(qtStrings.begin(), qtStrings.end(), [&resultArray, &k, &index] (const QString& str) {
           resultArray[k++] = index;
           const auto strSz { str.size() };
           std::memcpy(index, qUtf8Printable(str), strSz);
           index += strSz + 1;
       });
    

  • Lifetime Qt Champion

    Hi @magrif,

    I'm trying convert QStringList to const char**.

    Maybe you should start explaining us why you want to do this resp. what you want to achive.

    I guess you already know that QStringListis a QList<QString> and QString is an array of QChar, which is not compatible to char.

    I decide make copy to QVector<const char*>

    So far so good.

    and next invoke data() member func. But somthing went wrong :)

    Yeah, because you used the data from an temporary object, which is destroyed and therefore the memory your pointer points to is no longer valid.

    As @fcarney already said, when working with pointers you have to take care of the memory yourself.

    Regards



  • @aha_1980
    Thanks for reply.
    I'm doing simple wrapper around one C interface. And one func take in const char** . Code above works fine.
    But in process of work and this topic discussion was appeared some questions:
    When we push const char* (or som pointer) to QVector it creates deep copy of data or not? In particular, when push null-terminated char*.
    If not, how is achieved sequential memory locations when we push pointers to various sections of dynamically allocated memory?
    Thanks!


  • Lifetime Qt Champion

    Hi,

    You have a QVector of pointers to chars. There's no reason for QVector to do any deep copy of the data stored behind these pointers.

    Beside the fact that you are responsible for the data handling, you should also take into account that QString is not a wrapper around a char*. It stores strings in utf-16.



  • Since qtSt.toStdString() is returning a temporary why not just turn QStringList into a std::vector<string> and maintain for the lifetime or your pointers. That way the pointer returned by c_str remains valid. Probably better than managing the memory with new/delete.


Log in to reply