Search code examples
javaandroidc++cjava-native-interface

how to properly convert byte array in java to char pointer in jni


I am new to C/C++, so I don't know how to properly convert a byte array in Java to a char array in JNI.

For example, I have an inputString containing "Hello world!", I use this to get the byte array:

byte[] data = inputString.getBytes();

Then in the JNI layer, I use:

jbyte *array = (*env)->GetByteArrayElements(env, data, &isCopy);
argv[1] = (char *)array;

Then when I print the argv[1], it is "Hello world!ZE".

Why is there extra characters "ZE" here?

Would anyone explain this, and provide me the right solution to convert byte[] to char* pointer? I need the char* pointer because the interface I am given is char* pointer for me.


Solution

  • Your byte[] array is not null-terminated (does not end with a 0x00 byte), but you are clearly treating it as if it were. When printing the bytes, the "extra" characters are random values coming from surrounding memory when the print accesses beyond the bounds of the array, which is undefined behavior.

    Use (*env)->GetArrayLength() to find out how many bytes are actually in the array, and then don't access more bytes than that, eg:

    jint len = (*env)->GetArrayLength(env, data);
    jbyte *array = (*env)->GetByteArrayElements(env, data, &isCopy);
    argv[1] = (char*) array;
    ...
    printf("%.*s", len, argv[1]);
    ...
    (*env)->ReleaseByteArrayElements(env, data, array, JNI_ABORT);
    

    If you really need a null-terminated string (or just need to hold on to the data longer than the Java byte[] array will exist), you will have to allocate your own char[] buffer with extra room for a terminator, and then copy the byte[] array data into that buffer, eg:

    jint len = (*env)->GetArrayLength(env, data);
    
    jbyte *array = malloc(len + 1);
    if (array) {
        (*env)->GetByteArrayRegion(env, data, 0, len, array);
        array[len] = 0x00;
    }
    
    argv[1] = (char*) array;
    ...
    printf("%s", argv[1]);
    ...
    free(argv[1]);