Using array indexing to store data has its utility in a C style API. With a single header include, you can use the functionality of a compiled library though its C bindings. Let's see an example...
First declare the API with the functions we need. This api always has a constructor and cleanup/dispose method.
// ClassName_API.h
#ifndef ClassName_API_H_Include
#define ClassName_API_H_Include
#ifdef WIN32 // declared when compiling with windows (if not, declare it)
#ifdef API_EXPORT // must be declared in Preprocessor Definitions
#define API __declspec(dllexport)
#else
#define API __declspec(dllimport)
#endif
#else
#define API
#endif
extern "C" {
// Constructor... Could also be written void ClassName_ctor(void** ptr)
API void* ClassName_ctor();
API void ClassName_Dispose(void* ptr);
// Create an array (specific to the ClassName object)
API void ClassName_CreateArray(void* ptr, unsigned char** arr);
// Write out the array created by the ClassName object
API void ClassName_WriteArray(void* ptr, unsigned char* arr);
}
#endif
Now we need to define the class that does the heavy lifting.
// ClassName.hpp
#ifndef ClassName_HPP_Include
#define ClassName_HPP_Include
#include <iostream>
class ClassName {
public:
ClassName(){}
unsigned char* CreateArray(){
unsigned char* ptr = (unsigned char*)malloc(sizeof(unsigned char)*26);
for (int n = 0; n < 26; n++){
ptr[n] = 65+n;
}
return ptr;
}
void WriteArray(unsigned char* arr){
unsigned char* ptr = arr;
for (int n = 0; n < 26; n++){
cout << "arr[" << n <<"] = " << *ptr << "\n";
ptr++;
}
}
~ClassName(){};
};
#endif
Next, wrap the class in the API method definitions.
// ClassName_API.c
#ifndef ClassName_API_C_Include
#define ClassName_API_C_Include
#include "ClassName_API.h"
#include "ClassName.hpp"
void* ClassName_ctor(){
return new ClassName();
}
void ClassName_Dispose(void* ptr){
if (ptr== NULL){return;}
delete ((ClassName*)ptr);
ptr = NULL;
}
void ClassName_CreateArray(void* ptr, unsigned char** arr){
*arr = ((ClassName*)ptr)->CreateArray();
}
void ClassName_WriteArray(void* ptr, unsigned char* arr){
((ClassName*)ptr)->WriteArray(arr);
}
#endif
Finally, we can write a main program to demonstrate the functionality.
// main.cpp
#include <iostream>
#include "ClassName_API.h"
int main()
{
void* ptr = ClassName_ctor();
unsigned char* arr = NULL;
ClassName_CreateArray(ptr, &arr);
ClassName_WriteArray(ptr, arr);
ClassName_Dispose(ptr);
free(arr);
return 0;
}
Let's see the output...
arr[0] = A arr[1] = B arr[2] = C ... arr[23] = X arr[24] = Y arr[25] = Z
Okay, the array indexing demonstration is complete. You can see the full results if you run this online.
While a string is one of the most common examples, its elements are not very complicated. Take a RGB pixel, for example. It has three components.
struct RBG {
unsigned char R;
unsigned char G;
unsigned char B;
};
I have seen this type of code written:
void set_buffer_grey(unsigned char* buffer, int nPixels){
int p = 0;
unsigned char* position = buffer;
while (p < nPixels){
*position++ = 64; // set Red
*position++ = 64; // set Green
*position++ = 64; // set Blue
p++;
}
}
If you are off by just one index, the entire code will produce an incorrect result.
It seems much safer and easier to use a structure, and move through memory based on the structure's size... This seems easier to me:
void set_buffer_grey(unsigned char* buffer, int nPixels){
int p = 0;
RBG* position = (RBG*)buffer;
while (p < nPixels){
position->R = 64; // set Red
position->G = 64; // set Green
position->B = 64; // set Blue
position++;
p++;
}
}
Let's try a non-greyscale image and show it in an entire program, this time displaying results:
#include <stdio.h>
// Define a struct for RGB color
struct RBG {
unsigned char R;
unsigned char G;
unsigned char B;
};
int main()
{
// unsigned char* arr = new unsigned char[6]{1, 2, 3, 4, 5, 6};
unsigned char* buffer = new unsigned char[6];
RBG* rgb = (RBG*)buffer;
// setting all the values
for (int i = 1; i <=6; i++){
// same as *buffer = i; buffer = buffer + 1;
// same as buffer[0] = i; buffer++;
*buffer++ = i;
}
printf("rgb[0] = {%d, %d, %d}\n", (*rgb).R, (*rgb).G, (*rgb).B);
rgb++; // same as rgb = rgb + 1;
printf("rgb[1] = {%d, %d, %d}\n", (*rgb).R, (*rgb).G, (*rgb).B);
printf("There you have it!");
return 0;
}
The value of each element in the array displays correctly.
rgb[0] = {1, 2, 3}
rgb[1] = {4, 5, 6}
There you have it!