I recently have been working on moving from projects written in Java and C++ to C and realized that the lack of std::vector
in C makes it a bit more difficult to create multi-dimensional arrays. Also, without the std::string
in C, it's harder to store arrays of strings and keep track of their sizes. To automate the process, I created a typedef
'd struct
: varray
. varray
attempts to emulate some basic functions of std::vector
, e.g. storing sizes of the elements in an easily accessible location and allowing for allocation of multi-dimensional objects with "relative ease".
I've attached the header "varray.h" and a bit of sample code with comments to demonstrate its use. Please note that at this point, I haven't tried to dynamically expand the arrays, though I'll look into it as I practice more with the language.
If there is any feedback (syntax, memory allocation, anything), I'd greatly appreciate it - I'm still just getting started with C, C++, and Java.
varray.h
#ifndef VARRAY_H
#define VARRAY_H
#define VARRAY_DISPLAYDEBUG 0
#define VARRAY_STRSIZE(x) ((sizeof(char) * strlen(x)) + 1)
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
typedef struct {
int* getInt;
char* getChar;
double* getDbl;
char* str;
int size;
} varray;
typedef enum {
v_char = 0,
v_int = 1,
v_double = 2,
v_varray = 3,
v_tdvarray = 4
} varrayType;
void* createArray(varrayType arrayType, int arraySize);
varray varrayPush(const char* data);
varray allocateNumArray(varrayType type, const int size);
varray allocateCharArray(const int size);
varray* allocateVarray(const int size);
varray** allocateTDVarray(const int size);
inline void* createArray(varrayType arrayType, int arraySize) {
varray* target;
varray** vtarget;
varray*** tdvtarget;
if (arrayType == v_char) {
target = malloc(sizeof(varray) * arraySize);
*target = allocateCharArray(arraySize);
return target;
}
else if (arrayType == v_int || arrayType == v_double) {
target = malloc(sizeof(varray) * arraySize);
*target = allocateNumArray(arrayType, arraySize);
return target;
}
else if (arrayType == v_varray) {
vtarget = malloc(sizeof(varray*) * arraySize);
*vtarget = allocateVarray(arraySize);
return *vtarget;
}
else if (arrayType == v_tdvarray) {
tdvtarget = malloc(sizeof(varray**) * arraySize);
*tdvtarget = allocateTDVarray(arraySize);
return *tdvtarget;
}
else {
return NULL;
}
}
inline varray varrayPush(const char* data) {
varray target;
if (VARRAY_DISPLAYDEBUG) {
printf("%s%d%s%s\n", "Allocating array with size: ", (int)VARRAY_STRSIZE(data) - 1, " with contents: ", data);
}
target.str = malloc(VARRAY_STRSIZE(data));
strcpy(target.str, data);
if (VARRAY_DISPLAYDEBUG) {
printf("%s%s\n", "String created successfully. Contents reads: ", target.str);
printf("%s%d\n", "Memory address: ", (int)target.str);
}
target.size = VARRAY_STRSIZE(data);
return target;
}
inline varray allocateNumArray(varrayType type, const int size) {
int i;
varray target;
if (type == v_int) {
if (VARRAY_DISPLAYDEBUG) {
printf("%s%d\n", "Allocating array of type v_int with size ", size);
}
target.getInt = malloc(sizeof(int) * size);
for (i = 0; i < size; i++) {
target.getInt[i] = 0;
}
}
else if (type == v_double) {
if (VARRAY_DISPLAYDEBUG) {
printf("%s%d\n", "Allocating array of type v_double with size ", size);
}
target.getDbl = malloc(sizeof(double) * size);
for (i = 0; i < size; i++) {
target.getDbl[i] = 0.0;
}
}
target.size = size;
return target;
}
inline varray allocateCharArray(const int size) {
varray target;
int i;
if (VARRAY_DISPLAYDEBUG) {
printf("%s%d\n", "Allocating array of type v_char with size ", size);
}
target.getChar = malloc(sizeof(char) * size);
for (i = 0; i < size; i++) {
target.getChar[i] = 0;
}
target.size = size;
return target;
}
inline varray* allocateVarray(const int size) {
varray* target = malloc(sizeof(varray) * (size + 1));
if (VARRAY_DISPLAYDEBUG) {
printf("%s%d\n", "Allocated array of type v_varray with size ", size);
}
target[0].size = size;
return target;
}
inline varray** allocateTDVarray(const int size) {
varray** target = malloc(sizeof(varray*) * (size + 1));
if (VARRAY_DISPLAYDEBUG) {
printf("%s%d\n", "Allocated array of type v_tdvarray with size ", size);
}
target[0] = malloc(sizeof(varray));
target[0][0].size = size;
return target;
}
#endif
Example implementation
#include "varray.h"
void varrayDemo() {
varray sampleInt;
/*
* Functions as a normal array but also stores
* the size of the array at sampleInt.size.
* Accessing data elements used the syntax
* VARRAY.getInt[POSITION]
*/
varray* sampleString;
/*
* Since a C string is an array of char, creating
* an array of varray objects can easily store multiple
* strings. The size of the varray array can be accessed
* via VARRAY[0].size Individual elements can be
* accessed at VARRAY[POSITION].str with position >= 1
*/
varray** sampleContainer;
/*
* The container of varrays can store multiple data types
* at each element's position. For example, the syntax
* VARRAY[1][1].str will return the string, if stored.
* while VARRAY[2][2].getDbl[POSITION] returns the double
*/
sampleInt = *(varray*)createArray(v_int, 5);
/*
* The function createArray(TYPE, SIZE) initializes the array
* NOTE: I am not sure if there is a more "aesthetically pleasing"
* way to initialize the array, since createArray returns a void
* pointer. When initialized, all values are set to 0
*/
printf("The size of sampleInt is: %d\n", sampleInt.size);
printf("The data at position 0 is: %d\n", sampleInt.getInt[0]);
sampleString = createArray(v_varray, 2);
/*
* Each varray can contain one string. Initialize each element
* with the createArray command.
*/
printf("The size of sampleString is: %d\n", sampleString[0].size);
/*
* As noted above, the size is stored in a varray at position 0
* in the container
*/
sampleString[1] = varrayPush("This is a sample string");
sampleString[2] = varrayPush("This is also a sample string!");
/*
* To store a string within a varray, the function varrayPush is used
* with the desired string as the argument. The function initializes
* another varray object within the container.
*/
printf("The string at position 1 is: %s\n", sampleString[1].str);
printf("The size of the string stored at position 1 is: %d\n", sampleString[1].size);
printf("The char at position 5 in sampleString[1] is: %c\n", sampleString[1].str[5]);
sampleContainer = createArray(v_tdvarray, 2);
sampleContainer[1] = createArray(v_varray, 1);
sampleContainer[1][1] = *(varray*)createArray(v_double, 5);
sampleContainer[1][1].getDbl[4] = 3.14;
sampleContainer[2] = createArray(v_varray, 1);
sampleContainer[2][1] = varrayPush("yet another sample string");
/*
* As noted with the original sampleInt example, the *(varray*)
* syntax is used again.
*/
printf("sampleContainer[1][1] has size: %d with data %lf at position 4\n", sampleContainer[1][1].size, sampleContainer[1][1].getDbl[4]);
printf("sampleContainer[2][1] has size %d with string \"%s\"\n", sampleContainer[2][1].size, sampleContainer[2][1].str);
}
createArray
, changed size from typeint
tosize_t
, implementedcalloc
to zero out memory in arrays, and usedstrdup
in thevarrayPush
function. \$\endgroup\$