Mapping primitive, structure, array, NIO buffer, class and object types with Java Native Access (JNA)

in #utopian-io7 years ago (edited)

Repository

https://github.com/java-native-access/jna

Overview

In this tutorial we will learn primitive, structure, array, NIO buffer, class and object types mapping between Java and C++ using Java Native Access(JNA) library.

For more information on Java Native Access(JNA) library please see previous tutorials series

Requirements

  • Android Studio 3.0 or higher
  • Android NDK

Tutorial covers

  • Creating Android Studio project
  • Configuring JNA AAR library
  • Loading C++ shared library in Java
  • String type mapping
  • Integer type mapping
  • Decimal type mapping
  • Boolean type mapping
  • Class type mapping
  • Object type mapping
  • Structure type mapping
  • Array type mapping
  • NIO buffer type mapping

Difficulty

  • Intermediate

Guide

1. Creating Android Studio project

Create new android project and change Application name you can also change Company domain and Package name according to requirements, select Include C++ support and click next

p1.png

Select minimum SDK version and click next

p2.png

Select Empty Activity and click next

p3.png

Change Activity Name and Layout Name according to requirements and click Next

p4.png

Select C++ Standard as Toolchain Default and click Finish to create project

p5.png

If you get NDK not configured error in Messages window then click on File menu and select Project Structure and set Android NDK location.

p6.png

2. Configuring JNA AAR library

Download jna.aar and create New Module and select Import JAR/AAR Package and click Next

p7.png

Select jna.aar file from file system and click Finish

p8.png

jna module added to project, open build.gradle file and add jna module under dependencies

dependencies {
    implementation project(':jna')
    ....
    ....
}

p9.png

3. Loading C++ shared library in Java

static {
    Native.register(MainActivity.class, "native-lib");
}

In static block of a class we load our shared library, first argument to Native.register() method is the class in which we defined our native methods and 2nd argument is the name of native shared library. Name of shared library is native-lib we can change this default name in CMakeLists.txt file which is available in app folder. Loading should be done in static block which will load shared library during class loading time.

Note: C++ methods we want to export are marked with extern "C" to avoid name mangling.

4. String type mapping

In this example we will send string from java to C++ and log it in C++. Note if you are not familiar with logging in C++ please read previous tutorial T4 in this series.
This example contains simple C++ method that accept one string argument and logs it. Here is complete C++ code

#include <jni.h>
#include <android/log.h>

extern "C"
void stringMapping(jstring msg) {
    __android_log_print(ANDROID_LOG_DEBUG , "System.out", "%s", msg);
}

Mapping this C++ method in java is similar, we need to add native keyword which tells compiler that method is implemented in native code

public native void stringMapping(String msg);

Calling native methods in java is same as calling other java methods here is Java code for calling stringMapping()

stringMapping("Hello");

Here is complete Java code for this example

public class MainActivity extends AppCompatActivity {
    static {
        Native.register(MainActivity.class, "native-lib");
    }

    public native void stringMapping(String msg);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        stringMapping("Hello");
    }
}
Output

Output of C++ log statement is in logcat window

p10.png

5. Integer type mapping

By value

In this example we will pass integer types from Java to C++ by value, which means copies of original values will be passed to C++ and any changes to those copies will not change the original ones

#include <jni.h>
#include <android/log.h>

extern "C"
void integerMappingByValue(jshort a, jint b, jlong c) {
    __android_log_print(ANDROID_LOG_DEBUG , 
                       "System.out", "Before: %hu, %d, %ld", a, b, c);
    a = (jshort) (a + 1);
    b = (jint) (b + 1);
    c = (jlong) (c + 1);
}

Mapping this C++ method in java is similar, we need to add native keyword which tells compiler that method is implemented in native code

public native void integerMappingByValue(short a, int b, long c);

Calling native method in java is same as calling other java methods, for calling native method we will pass three integer types to native method and after native call we are printing those values to see changes made in native method affect original values or not

short a1 = 10; int b1 = 20; long c1 = 30L;
integerMappingByValue(a1, b1, c1);
println("After: " + a1 + ", " + b1 + ", " + c1);

Here is complete Java code for this example

public class MainActivity extends AppCompatActivity {
    static {
        Native.register(MainActivity.class, "native-lib");
    }

    public native void integerMappingByValue(short a, int b, long c);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        short a1 = 10; int b1 = 20; long c1 = 30L;
        integerMappingByValue(a1, b1, c1);
        System.out.println("After: " + a1 + ", " + b1 + ", " + c1);
    }
}
Output

Output of log statements is in logcat window, since we are sending integers by value, original values didn't change

p12.png

By reference

In this example we will pass integer types from Java to C++ by reference, which means references of original values will be passed to C++ and any changes to those references will also change the original ones. For reference type we will use pointers in C++

extern "C"
void integerMappingByRef(jshort *a, jint *b, jlong *c) {
    __android_log_print(ANDROID_LOG_DEBUG ,
                        "System.out", "Before: %hu, %d, %ld", *a, *b, *c);
    *a = (jshort) (*a + 1);
    *b = (jint) (*b + 1);
    *c = (jlong) (*c + 1);
}

To map this C++ method in java we need to add native keyword which tells compiler that method is implemented in native code. Since we will pass values by references so we used Integer references types in method arguments

public native void integerMappingByRef(ShortByReference a, IntByReference b, LongByReference c);

Calling native methods in java is same as calling other java methods we created integer reference types and passed to native C++ method and then after native method call we logs the values to see those original values got changed or not

ShortByReference a = new ShortByReference((short) 10);
IntByReference b = new IntByReference(20);
LongByReference c = new LongByReference(30L);
integerMappingByRef(a, b, c);
println("After: " + a.getValue() + ", " + b.getValue() + ", " + c.getValue());

Here is complete Java code for this example

public class MainActivity extends AppCompatActivity {
    static {
        Native.register(MainActivity.class, "native-lib");
    }

    public native void integerMappingByRef(ShortByReference a, IntByReference b, LongByReference c);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ShortByReference a = new ShortByReference((short) 10);
        IntByReference b = new IntByReference(20);
        LongByReference c = new LongByReference(30L);
        integerMappingByRef(a, b, c);
        System.out.println("After: " + a.getValue() + ", " + b.getValue() + ", " + c.getValue());
    }
}
Output

Output of log statements is in logcat window, since we are passing integers by references, original values also got changed

p13.png

6. Decimal type mapping

By value

In this example we will pass decimal types from Java to C++ by value, what that means copies of original values will be passed to C++ and any changes to those copies will not change the original ones

#include <jni.h>
#include <android/log.h>

extern "C"
void decimalMappingByValue(jfloat a, jdouble b) {
    __android_log_print(ANDROID_LOG_DEBUG ,
                        "System.out", "Before: %ff, %fd", a, b);
    a = (jfloat) (a + 1);
    b = (jdouble) (b + 1);
}

To map this C++ method in java we need to add native keyword which tells compiler that method is implemented in native code

public native void decimalMappingByValue(float a, double b);

Calling native method in java is same as calling other java methods, for calling native method we will pass three decimal types to native method and after native call we are printing those values to see changes made in native method affect original values or not

float a = 20.0f;
double b = 30.0d;
decimalMappingByValue(a, b);
System.out.println("After: " + a + "f, " + b + "d");

Here is complete Java code for this example

public class MainActivity extends AppCompatActivity {
    static {
        Native.register(MainActivity.class, "native-lib");
    }

    public native void decimalMappingByValue(float a, double b);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        float a = 20.0f;
        double b = 30.0d;
        decimalMappingByValue(a, b);
        System.out.println("After: " + a + "f, " + b + "d");
    }
}
Output

Output of log statements is in logcat window, since we are sending decimals by value, original values didn't change

p14.png

By reference

In this example we will pass decimal types from Java to C++ by reference, what that means references of original values will be passed to C++ and any changes to those references will also change the original ones. For reference type we will use pointers in C++

#include <jni.h>
#include <android/log.h>

extern "C"
void decimalMappingByRef(jfloat *a, jdouble *b) {
    __android_log_print(ANDROID_LOG_DEBUG ,
                        "System.out", "Before: %ff, %fd", *a, *b);
    *a = (jfloat) (*a + 1);
    *b = (jdouble) (*b + 1);
}

To map C++ method in Java we need to add native keyword which tells compiler that method is implemented in native code. Since we will pass values by references so we used decimal references types in method arguments

public native void decimalMappingByRef(FloatByReference a, DoubleByReference b);

Calling native methods in java is same as calling other java methods we created decimal reference types and passed to native C++ method and then after native method call we logs the values to see those original values got changed or not

FloatByReference a = new FloatByReference(20.0f);
DoubleByReference b = new DoubleByReference(30.0d);
decimalMappingByRef(a, b);
println("After: " + a.getValue() + "f, " + a.getValue() + "d");

Here is complete Java code for this example

public class MainActivity extends AppCompatActivity {
    static {
        Native.register(MainActivity.class, "native-lib");
    }

    public native void decimalMappingByRef(FloatByReference a, DoubleByReference b);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        FloatByReference a = new FloatByReference(20.0f);
        DoubleByReference b = new DoubleByReference(30.0d);
        decimalMappingByRef(a, b);
        System.out.println("After: " + a.getValue() + "f, " + a.getValue() + "d");
    }
}
Output

Output of log statements is in logcat window, since we are passing decimals by references, original values also got changed

p15.png

7. Boolean type mapping

By value

In this example we will pass boolean type from Java to C++ by value, what that means copy of original value will be passed to C++ and any changes to this copy will not change the original one

#include <jni.h>
#include <android/log.h>

extern "C"
void booleanMappingByValue(jboolean a) {
    __android_log_print(ANDROID_LOG_DEBUG,
                        "System.out",
                        "Before: a: %s", a ? "true" : "false");
    a = (jboolean) !a;
}

Mapping this C++ method in java is similar, we need to add native keyword which tells compiler that method is implemented in native code

public native void booleanMappingByValue(boolean a);

Calling native method in java is same as calling other java methods, for calling native method we will pass boolean type to native method and after native call we are printing this boolean value to see changes made in native method affect original value or not

boolean a = false;
booleanMappingByValue(a);
System.out.println("After: a:" + a);

Here is complete Java code for this example

public class MainActivity extends AppCompatActivity {
    static {
        Native.register(MainActivity.class, "native-lib");
    }

    public native void booleanMappingByValue(boolean a);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        boolean a = false;
        booleanMappingByValue(a);
        System.out.println("After: a:" + a);
    }
}
Output

Output of log statements is in logcat window, since we are sending boolean by value, original boolean value didn't change

p16.png

By reference

In this example we will pass boolean type from Java to C++ by reference, what that means reference of original boolean value will be passed to C++ and any changes to this boolean references will also change the original one. For reference type we will use pointers in C++

#include <jni.h>
#include <android/log.h>

extern "C"
void booleanMappingByRef(jboolean *a) {
    __android_log_print(ANDROID_LOG_DEBUG,
                        "System.out",
                        "Before: a: %s", *a ? "true" : "false");
    *a = (jboolean) !*a;
}

We need to add native keyword which tells compiler that method is implemented in native code. There is no boolean reference type in Java, we will use IntByReference() as a replacement for boolean. integer 0 means false and 1 means true

public native void booleanMappingByRef(IntByReference a);

Calling native methods in java is same as calling other java methods we created integer reference type and passed to native C++ method and then after native method call we logs the values to see those original values got changed or not

IntByReference a = new IntByReference(0);
booleanMappingByRef(a);
System.out.println("After: a: " + (a.getValue() == 1 ? "true" : "false"));

Here is complete Java code for this example

public class MainActivity extends AppCompatActivity {
    static {
        Native.register(MainActivity.class, "native-lib");
    }

    public native void booleanMappingByRef(IntByReference a);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        IntByReference a = new IntByReference(0);
        booleanMappingByRef(a);
        System.out.println("After: a: " + (a.getValue()==1 ? "true" : "false"));
    }
}
Output

Output of log statements is in logcat window, since we are passing integer by reference, original integer reference value also got changed

p17.png

8. Class type mapping

In this example we will pass class type from Java to C++. Having class type in C++ we will call static method and access static property of that class type. We will pass two arguments to C++ one is pointer to JNIEnv, using this pointer we can access java types, properties, creates new types etc, other argument is class type

#include <jni.h>
#include <android/log.h>

extern "C"
void classMapping(JNIEnv *env, jclass clazz) {
    
     //get static field of java class and prints it
    jfieldID fieldID = env->GetStaticFieldID(clazz, "name", "Ljava/lang/String;");
    jstring nameString = (jstring) env->GetStaticObjectField(clazz, fieldID);
    __android_log_print(ANDROID_LOG_DEBUG, 
                        "System.out", 
                        "%s", env->GetStringUTFChars(nameString, 0));
    
    //call to static method of java class
    jmethodID updateMethod = env->GetStaticMethodID(clazz, "update", "(I)V");
    env->CallStaticVoidMethod(clazz, updateMethod, 100);
}

To map this C++ method in java we need to add native keyword which tells compiler that method is implemented in native code. We will pass JNIEnv along with class type

public native int classMapping(JNIEnv env, Class<?> clazz);

Calling native method in java is same as calling other java methods, for calling native method we will pass JNIEnv and MainActivity class. MainActivity class contains static property and static method which we will call from C++

classMapping(JNIEnv.CURRENT, MainActivity.class);

Here is complete Java code for this example

public class MainActivity extends AppCompatActivity {
    static {
        Map<String, Boolean> options = Collections.singletonMap(Library.OPTION_ALLOW_OBJECTS, Boolean.TRUE);
        Native.register(MainActivity.class, NativeLibrary.getInstance("native-lib", options));
    }

    public static String name = "FaoB";

    public static void update(int res) {
        System.out.println("update " + res);
    }

    public native void classMapping(JNIEnv env, Class<?> clazz);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        classMapping(JNIEnv.CURRENT, MainActivity.class);
    }
}
Output

Output of log statements is in logcat window, Logs shows printing of java static property in C++ and call to java static method from C++

p18.png

9. Object type mapping

In this example we will pass object type from Java to C++. Having object type in C++ we will call non static method and access non static property of that object type. We will pass two arguments to C++ one is pointer to JNIEnv, using this pointer we can access java types, properties, creates new types etc, other argument is object type

#include <jni.h>
#include <android/log.h>

extern "C"
void objectMapping(JNIEnv *env, jobject obj) {
    
     //get non static field of java object and prints it
    jclass clazz = env->GetObjectClass(obj);
    jfieldID fieldID = env->GetFieldID(clazz, "phone", "Ljava/lang/String;");
    jstring phoneString = (jstring) env->GetObjectField(obj, fieldID);
    __android_log_print(ANDROID_LOG_DEBUG,
                        "System.out",
                        "%s", env->GetStringUTFChars(phoneString, 0));
    
     //call to non static method of java object
    jmethodID method = env->GetMethodID(clazz, "update", "(I)V");
    env->CallVoidMethod(obj, method, 200);
}

To map this C++ method in java we need to add native keyword which tells compiler that method is implemented in native code. We will pass JNIEnv along with object type

public native void objectMapping(JNIEnv env, MainActivity object);

Calling native method in java is same as calling other java methods, for calling native method we will pass JNIEnv and MainActivity object reference. MainActivity class contains non static property and non static method which we will call from C++

objectMapping(JNIEnv.CURRENT, this);

Here is complete Java code for this example

public class MainActivity extends AppCompatActivity {
    static {
        Map<String, Boolean> options = Collections.singletonMap(Library.OPTION_ALLOW_OBJECTS, Boolean.TRUE);
        Native.register(MainActivity.class, NativeLibrary.getInstance("native-lib", options));
    }

    public String phone = "12345678";

    public void update(int res) {
        System.out.println("update " + res);
    }

    public native int objectMapping(JNIEnv env, MainActivity object);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        objectMapping(JNIEnv.CURRENT, this);
    }
}
Output

Output of log statements is in logcat window, Logs shows printing of java non static property in C++ and call to java non static method from C++

p19.png

10. Structure type mapping

By value

In this example we will pass structure type from Java to C++ by value, which means if we make changes to structure in C++ it will will not change structure value on java side. In this example we create simple structure with double value, we are passing structure as method argument. In method body we are making changes to structure value

#include <android/log.h>

struct TestStructure {
    double value;
};
 
extern "C"
void structureByValue(TestStructure str) {
    __android_log_print(ANDROID_LOG_DEBUG,
                        "System.out",
                        "Before: value = %f", str.value);

    str.value = 23.34;
}

To map C++ structure in Java we need to extend from Structure class and we can add variables in our case we added double value to match C++ type. We need to create inner static class ByValue to pass structure by value

class TestStructure extends Structure {
    double value;
    static class ByValue extends TestStructure implements Structure.ByValue{}

    @Override
    protected List<String> getFieldOrder() {
        return Arrays.asList("value");
    }
}

To map this C++ method in java we need to add native keyword which tells compiler that method is implemented in native code. We will pass structure to native method

public native void structureByValue(TestStructure.ByValue str);

We first created structure by value and set its double value, then we pass that structure to native method and then prints the log statement to see its value got changed or not

TestStructure.ByValue struct = new TestStructure.ByValue();
struct.value = 55.6;
structureByValue(struct);
System.out.println("After: value = " + struct.value);

Here is complete Java code for this example

public class MainActivity extends AppCompatActivity {
    static {
        Native.register(MainActivity.class, "native-lib");
    }

    public native void structureByValue(TestStructure.ByValue str);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TestStructure.ByValue struct = new TestStructure.ByValue();
        struct.value = 55.6;
        structureByValue(struct);
        System.out.println("After: value = " + struct.value);
    }
}

class TestStructure extends Structure {
    double value;
    static class ByValue extends TestStructure implements Structure.ByValue {}

    @Override
    protected List<String> getFieldOrder() {
        return Arrays.asList("value");
    }
}
Output

Output of log statements is in logcat window, Logs shows original structure contents on java side didn't change when we make changes in C++

p20.png

By reference

In this example we will pass structure type from Java to C++ by reference, which means if we make changes to structure in C++ it will also changes structure value on java side. In this example we create simple structure with double value, we are passing pointer to that structure as method argument. In method body we are making changes to structure value

#include <android/log.h>

struct TestStructure {
    double value;
};

extern "C"
void structureByRef(TestStructure *str) {
    __android_log_print(ANDROID_LOG_DEBUG,
                        "System.out",
                        "Before: value = %f", str->value);

    str->value = 23.34;
}

To map C++ structure in Java we need to extend from Structure class and we can add variables in our case we added double value to match C++ type. We need to create inner static class ByReference to pass structure by reference

class TestStructure extends Structure {
    double value;
    static class ByReference extends TestStructure implements Structure.ByReference {}
    
    @Override
    protected List<String> getFieldOrder() {
        return Arrays.asList("value");
    }
}

To map this C++ method in java we need to add native keyword which tells compiler that method is implemented in native code. We will pass structure to native method

public native void structureByRef(TestStructure.ByReference str);

We first created structure by reference and set its double value, then we pass that structure to native method and then prints the log statement to see its double value got changed or not

TestStructure.ByReference struct = new TestStructure.ByReference();
struct.value = 55.6;
structureByRef(struct);
System.out.println("After: value = " + struct.value);

Here is complete Java code for this example

public class MainActivity extends AppCompatActivity {
    static {
        Native.register(MainActivity.class, "native-lib");
    }

    public native void structureByRef(TestStructure.ByReference str);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TestStructure.ByReference struct = new TestStructure.ByReference();
        struct.value = 55.6;
        structureByRef(struct);
        System.out.println("After: value = " + struct.value);
    }
}

class TestStructure extends Structure {
    double value;

    static class ByReference extends TestStructure implements Structure.ByReference {}

    @Override
    protected List<String> getFieldOrder() {
        return Arrays.asList("value");
    }
}
Output

Output of log statements is in logcat window, Logs shows original structure contents on java side also got changed when we make changes in C++

p21.png

11. Array type mapping

In this example we will pass array type from Java to C++. Arrays can only be passed as reference so changes made in C++ will also changes original array. In this example we are passing pointer to int array and array length as arguments, and in method body we are multiplying each element of array with 2. We can also pass other integer and decimal type arrays in similar manner

extern "C"
void arrayMapping(int *array, int len) {
    for (int i = 0; i < len; i++) {
        array[i] = array[i] * 2;
    }
}

To map this C++ method in java we need to add native keyword which tells compiler that method is implemented in native code. We will pass array along with array length

public native void arrayMapping(int array[], int len);

Calling native method in java is same as calling other java methods, for calling native method we first initializes the array and passed to native method and then prints it to see its contents got changed or not

int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
arrayMapping(array, array.length);

for (int i : array) {
    System.out.println(i);
}

Here is complete Java code for this example

public class MainActivity extends AppCompatActivity {
    static {
        Native.register(MainActivity.class, "native-lib");
    }

    public native void arrayMapping(int array[], int len);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        arrayMapping(array, array.length);

        for (int i : array) {
            System.out.println(i);
        }
    }
}
Output

Output of log statements is in logcat window, Logs shows original array contents also got changed when we make changes in C++

p22.png

12. NIO buffer type mapping

In this example we will pass NIO buffer type from Java to C++. NIO buffers can only be passed as reference so changes made in C++ will also changes original buffer. In this example we are passing pointer to int buffer and buffer length as arguments, and in method body we are multiplying each element of buffer with 2. We can also pass other integer and decimal NIO buffer types in similar manner

extern "C"
void bufferMapping(int *buffer, int len) {
    for (int i = 1; i <= len; i++) {
        buffer[i] = buffer[i] * 2;
    }
}

To map this C++ method in java we need to add native keyword which tells compiler that method is implemented in native code. We will pass NIO int buffer along with buffer length

public native void bufferMapping(IntBuffer buffer, int len);

Calling native method in java is same as calling other java methods, for calling native method we first initializes the buffer and passed to native method and then prints it to see its contents got changed or not

IntBuffer intBuffer = IntBuffer.allocate(10);
for (int i = 1; i <= 10; i++) {
    intBuffer.put(i);
}
intBuffer.flip();

bufferMapping(intBuffer, intBuffer.capacity());
while (intBuffer.hasRemaining()) {
    System.out.println(intBuffer.get());
}

Here is complete Java code for this example

public class MainActivity extends AppCompatActivity {
    static {
        Native.register(MainActivity.class, "native-lib");
    }

    public native void bufferMapping(IntBuffer buffer, int len);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        IntBuffer intBuffer = IntBuffer.allocate(10);
        for (int i = 1; i <= 10; i++) {
            intBuffer.put(i);
        }
        intBuffer.flip();

        bufferMapping(intBuffer, intBuffer.capacity());
        while (intBuffer.hasRemaining()) {
            System.out.println(intBuffer.get());
        }
    }
}
Output

Output of log statements is in logcat window, Logs shows original buffer contents also got changed when we make changes in C++

p23.png

Github

Complete project available on github. Clone repo and open project name T5.

Sort:  

Congratulations @kabooom! You have completed some achievement on Steemit and have been rewarded with new badge(s) :

Award for the number of posts published

Click on any badge to view your own Board of Honor on SteemitBoard.

To support your work, I also upvoted your post!
For more information about SteemitBoard, click here

If you no longer want to receive notifications, reply to this comment with the word STOP

Upvote this notification to help all Steemit users. Learn why here!

Thank you for your contribution.
While I liked the content of your contribution, I would still like to extend few advices for your upcoming contributions:

  • In the images where you have code, put the most visible code. In your images it's difficult to see the code.
  • Work on improving your post for English mistakes and incorrectly written words and sentences, as those could lead your author to lose track of your purpose.

Looking forward to your upcoming tutorials.


Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]

Hi thanks for response i added images to show the output of example not the code. the complete code for each example is included above Output section. I will improve my english skills

Hey @kabooom
Thanks for contributing on Utopian.
We're already looking forward to your next contribution!

Contributing on Utopian
Learn how to contribute on our website or by watching this tutorial on Youtube.

Want to chat? Join us on Discord https://discord.gg/h52nFrV.

Vote for Utopian Witness!