0
votes

I'm creating a C++ wrapper for a third-party .dll in order to use it with C# P/Invoke. To do so, I have access to a demo application that uses this .dll and as I'm no C expert, I'm heavily dependent on this code. Everything works fine, but a couple of weeks ago, I came across a bit of code that I found rather odd:

unsigned char** ppucValues = new unsigned char*[iSize];
for(int i = 0; i < iSize; i++){
    ppucValues[i] =  (unsigned char *)new int;
    *(int *)ppucValues[i] = piValues[i]; //(piValues is int*)
}

Those lines inside the for-loop puzzled me for a while but looking closely at the first line, I figured "hey, that must mean that an unsigned char is pointing to an int... right?¹"

Yeah, I'm still not so sure about that, but I've used the same concept for several different types and it works. In case anyone is wondering the reason for that, I have to store differently typed values into this unsigned char** and pass it ahead to a method in the third-party .dll that takes, obviously, this unsigned char**. That's how the manufacturer did in their demo app, so I'm just going with it.

With that out of the way, on to my problem: I have to do this same operation but now I'm taking a char** (array of strings) instead of an int* or double* or whatever. Based on what I just said, this is what I came up with:

for(int i = 0; i < iSize ; i++){
    ppucValues[i] = (unsigned char *) new char*; //type of ppucValues as unsigned char** and type of ppucValues[i] as char*???
    *(char **)ppucValues[i] = ppcValues[i]; //Hmmm... what?!
}

But it doesn't work quite as I expected (not to mention that I was just 50% confident on it). For instance, if my input (ppcValues[i]) is "test", my output (ppucValues[i]) turns out as "¨Ô4". I could risk suggesting that this is an encoding issue that has nothing to do with C++ or its pointers, but I'll leave suggestions to the kind people here at StackOverflow. Any help would be appreciated.

¹In case I'm wrong, please enlighten me!

2
new char*; means "allocate a pointer to char"; a pointer is an int; that is 4 or 8bytes (depending on 32/64bits). - Exceptyon

2 Answers

1
votes

Without more context it's hard to give a definitive solution, but if the lifetime of ppcValues is at least as long (or longer, or course) than ppucValues it is a simple as just copying the pointers, like

for(int i = 0; i < iSize ; i++){
    ppucValues[i] = reinterpret_cast<unsigned char*>(ppcValues[i]);
}

If the lifetime of ppcValues is shorter than the lifetime of ppucValues, then you need to allocate enough memory to fit all the data in ppcValues[i] and copy it:

for(int i = 0; i < iSize ; i++){
    ppucValues[i] = new unsigned char[length_of(ppcValues[i])];
    std::copy_n(reinterpret_cast<unsigned char*>(ppcValues[i]), ppucValues[i], length_of(ppcValues[i]));
}

The length_of function depends on the contents of ppcValues[i]. If it's a C-style string then you should be using strlen(ppcValues[i]) + 1.

Also note that if you allocate using new[] then you need to be freeing with delete[].

0
votes

But it doesn't work quite as I expected

That's because strings, i.e. null terminated char*s, are not the same as the fundamental types. You are passing a pointer. If the memory the pointer points to gets deallocated or overwritten by some code before it is processed by the users of ppucValues, then you are looking at undefined behavior.