1

I've used https://stackoverflow.com/a/38769851 and adapted for C++ as follows:

    jsize num_bytes = env->GetArrayLength(message);
    char *buffer = new char(num_bytes + 1);

    if (!buffer) {
        // handle allocation failure ...
        //throw error?
        return 1;
    }

    // obtain the array elements
    jbyte* elements = env->GetByteArrayElements(message, NULL);

    if (!elements) {
        // handle JNI error ...
        //throw error?
        return 2;
    }

    // copy the array elements into the buffer, and append a terminator
    memcpy(buffer, elements, num_bytes);
    buffer[num_bytes] = 0;

    std::string m(buffer, num_bytes + 1);

    // Do not forget to release the element array provided by JNI:
    env->ReleaseByteArrayElements(message, elements, JNI_ABORT);

I had to change char *buffer = malloc(num_bytes + 1); to char *buffer = new char(num_bytes + 1); because of C++ errors. Why it won't work in C++ by the way?

Well, so with this code I get a crash. I think it's probably related to this change I made, because env->ReleaseByteArrayElements(message, elements, JNI_ABORT); might be releasing it as if it were allocated by malloc.

How should this code in C++ work?

Guerlando OCs
  • 1,886
  • 9
  • 61
  • 150

3 Answers3

1

Notice the brackets (round vs. square) you've chosen.

char *buffer = new char(num_bytes + 1);

... creates one char that has a value of num_bytes + 1.

char *buffer = new char[num_bytes + 1];

... creates an array with num_bytes + 1 number of chars. That should be it.


Related:

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
akuzminykh
  • 4,522
  • 4
  • 15
  • 36
1

new char(N) allocates a single char with a value of N. You want an array of N characters, so use new char[N] instead.

That being said, you don’t actually need the char[] array at all. You can construct the std::string using the Java byte array elements as-is, eg:

jsize num_bytes = env->GetArrayLength(message);

// obtain the array elements
jbyte* elements = env->GetByteArrayElements(message, NULL);
if (!elements) {
    // handle JNI error ...
    //throw error?
    return 1;
}

// copy the array elements into the string
std::string m(reinterpret_cast<char*>(elements), num_bytes);

// Do not forget to release the element array provided by JNI
env->ReleaseByteArrayElements(message, elements, JNI_ABORT);

Or, at the very least, you can presize the std::string and then copy the byte array elements into the string’s own memory buffer, eg:

jsize num_bytes = env->GetArrayLength(message);

// obtain the array elements
jbyte* elements = env->GetByteArrayElements(message, NULL);
if (!elements) {
    // handle JNI error ...
    // throw error?
    return 1;
}

// copy the array elements into the string
std::string m(num_bytes, ‘\0’);
std::copy_n(elements, num_bytes, m.begin());

// Do not forget to release the element array provided by JNI
env->ReleaseByteArrayElements(message, elements, JNI_ABORT);
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
0

Specifically cast the malloc to char*:

char *buffer = (char *) malloc(num_bytes + 1);

C won't need this, but C++ would.

Your linked example uses C, and that's whats causing the subtle difference here.

The C++ compiler assumes that malloc() returns an int, leading to inconsistencies in type sizing for the destination pointer type (char<-int)

aran
  • 10,978
  • 5
  • 39
  • 69