mojo1mojo2
mojo1mojo2

Reputation: 1130

Passing C++ String to C libraries for memory management

I am trying to use a C Library, which requires that I pass in dynamically allocated c-strings for the functions to modify. However, I want to avoid using new/delete operators because I feel it is better practice to have memory management done under the hood by STL libraries, rather than by me.

Below, I'm trying to use std::string (and vectors) to solve this problem, and preallocating them before passing them to the C function. The examples with one string (CChar, CVoid) work, but I'm still unsure if this is the correct way, or even if it is a safe way (bug-free) to do it. Using vectors does not seem to work at all.

I have included the "C"-way of doing what I want to achieve for both strings and vectors.

#include <string>
#include <iostream>
#include <vector>

// ----------------------------------------------------
// Example C library Code
void CChar(char* data, int len)
{
    int i;
    for (i = 0; i < len; ++i)
        data[i] = 'A' + (i % 26);
}

void CVoid(void* data, int len)
{
    char* d = (char*)data;
    int i;
    for (i = 0; i < len; ++i)
        d[i] = 'Z' - (i % 26);
}

void CStrings(char** strings, int count, int lengths)
{
    int i, j; 
    for (i = 0; i < count; ++i)
        for (j = 0; j < lengths; ++j)
            strings[i][j] = 'A' + ((i * j + i) % 26);
}
// ----------------------------------------------------

// C++ code
int main()
{
    // Traditional way, using new/delete.
    char* c = new char[11];
    CChar(c, 10);
    c[10] = '\0';
    std::cout << c << std::endl; // ABCDEFGHIJ
    delete [] c;

    std::string s(10, '\0');
    CChar(&s[0], 10);

    std::cout << s << std::endl; // ABCDEFGHIJ
    CVoid(&s[0], 10);

    std::cout << s << std::endl; // ZYXWVUTSRQ
    std::vector<std::string> v(5, std::string(10, '\0'));

    // Traditional way with arrays of arrays.
    char** cc = new char*[5];
    for (int i = 0; i < 5; ++i)
    {
        cc[i] = new char[11];
        cc[i][10] = '\0';
    }
    CStrings(cc, 5, 10);
    for (int i = 0; i < 5; ++i)
    {
        std::cout << cc[i] << std::endl; // AAAAAAAAAA, BCDEFGHIJK, CEGIKMOQSU, DGJMPSVYBE, EIMQUYCGKO
        delete [] cc[i];
    }
    delete [] cc;      

    // Doesn't compile
    // CStrings(&v[0], 5, 10);

    // for (int i = 0; i < 5; ++i)
    //     std::cout << v[i] << std::endl;

    return 0;
}

Summary: Is there a good way to use C++'s STL libraries so that I don't need to do my own resource management when trying to use C libraries.

edit: Error cleaning up array of arrays

Upvotes: 1

Views: 219

Answers (2)

mojo1mojo2
mojo1mojo2

Reputation: 1130

For arrays of arrays, can store a vector<char*> which refers to the starts of the already dynamically allocated std::vector<std::string>.

int main()
{
    std::vector<std::string> v(5, std::string(10, '\0'));
    std::vector<char*> vc(5);
    for (int i = 0; i < 5; ++i)
        vc[i] = &(v[i])[0];

    CStrings(&vc[0], 5, 10);

    for (int i = 0; i < 5; ++i)
        std::cout << v[i] << std::endl;

    return 0;
}

Upvotes: 0

PlinyTheElder
PlinyTheElder

Reputation: 1494

Sure, you can just use std::vector<char> is you don't want to think about allocation. Here's how you do it:

#include <vector>

int main()
{
    std::vector<char> str(100, 0); //Allocate an array of 100 chars and initialize them to 0

    SomeFunction(&str[0], str.size()); //Pass the address to the array and its size

    return 0;
}

Upvotes: 2

Related Questions