I'm doing the exercises from the third edition of "Programming in Lua" book by Roberto Ierusalimschy. I have a problem with a bug in my solution to exercise 32.1. The statement is provided as comment in the code.
/*
Exercise 32.1:
Write a library that allows a script to limit the total amount of memory
used by its Lua state. It may offer a single function, setlimit, to set that
limit.
The library should set its own allocation funciton. This function, before
calling the original allocator, checks the total memory in use and returns
NULL if the requested memory exeeds the limit.
(Hint: the library can use lua_gc to initialize its byte count when it
starts. It also can use the user data of the allocation function to keep its
state: the byte count, the current memory limit, etc.; remember to use the
original user data when calling the original allocation function.)
*/
#ifdef WIN32
#define LUA_EXPORT __declspec(dllexport)
#else
#define LUA_EXPORT
#endif
#include <lauxlib.h>
typedef struct MemLimitUData
{
size_t mem_limit;
size_t currently_used;
lua_Alloc original_alloc;
void *original_ud;
}
MemLimitUData;
static int l_setlimit(lua_State *L)
{
MemLimitUData *ud;
size_t mem_limit = luaL_checkinteger(L, 1);
lua_getallocf(L, &ud);
ud->mem_limit = mem_limit;
return 0;
}
static int l_getlimit(lua_State *L)
{
MemLimitUData *ud;
lua_getallocf(L, &ud);
lua_pushnumber(L, ud->mem_limit);
return 1;
}
static void *l_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
{
MemLimitUData *udata = (MemLimitUData*)ud;
if (udata->mem_limit != 0 &&
udata->mem_limit < udata->currently_used - osize + nsize)
{
return NULL;
}
udata->currently_used += nsize - osize;
return udata->original_alloc(udata->original_ud, ptr, osize, nsize);
}
static const luaL_Reg memlimit[] =
{
{ "setlimit", l_setlimit },
{ "getlimit", l_getlimit },
{ NULL, NULL }
};
int LUA_EXPORT luaopen_memlimit(lua_State *L)
{
MemLimitUData *ud =
(MemLimitUData*)lua_newuserdata(L, sizeof(MemLimitUData));
ud->mem_limit = 0;
ud->currently_used =
lua_gc(L, LUA_GCCOUNT, 0) * 1024 + lua_gc(L, LUA_GCCOUNTB, 0);
ud->original_alloc = lua_getallocf(L, &ud->original_ud);
lua_setallocf(L, l_alloc, ud);
luaL_newlib(L, memlimit);
return 1;
}
When I build the source as memlimit.dll and use it from Lua script,
local memlimit = require"memlimit" the program crashes when the script ends. When I use debugger to look for the problem, the problematic statement seems to be in Lua internals. The file is lmem.c line 84:
newblock = (*g->frealloc)(g->ud, block, osize, nsize);
The used version of Lua is 5.2.3.
What wrong I do to break the Lua memory management ?
I haven't tried your code but here is what caught my attention when I read it:
The ud in luaopen_memlimit is created as userdata but is not anchored in Lua. Passing it to lua_getallocf does not count as anchoring. ud is probably being collected when the program ends via lua_close when it tries to free all data using your l_alloc. You should probably use plain malloc or the original allocf to create ud.
I have developed my own hybrid stream cipher and for the GUI i am using Qt. Initially i wrote it on a single thread but it being a stream cipher was making GUI dysfunctional when operating on large files. So i shifted the encryption/decryption to a separate Qthread. Also to show the progress i included a standard QProgressbar onto the GUI. But when I run the File I/O the encryption/decryption works perfectly but the progress bar doesn't update properly. After the whole operation completes, the progress bar suddenly goes from 0% to 100% showing that it didn't get the chance to update during the operation. For the code, I emitted the completed percentage from the FileCrypto to the main GUI thread onto the QProgressbar's setValue(int) slot. Since it didn't work I also tried to sent a int poitner over to the FileCrypto thread whilst updating the pointer with the percentage and using a QTimer on the GUI thread to check the value of the int value locally and update the progress bar but still I got the exact same result.
Here is my code:
The FileCrypto class:
#include <QThread>
#include <QFile>
#include <PolyVernam.h> //my algo header
class FileCrypto : public QThread
{
Q_OBJECT
public:
FileCrypto(QString, QString, int);
bool stopIt;
protected:
void run();
signals:
void completed(int);
void msg(QString);
void pathMsg1(QString);
void pathMsg2(QString);
void keyMsg(QString);
private:
QFile src, dest;
QString tag;
int mode;
qint64 length;
PolyVernam pv;
};
The Code:
#include <FileCrypto.h>
FileCrypto::FileCrypto(QString input, QString keyFile, int mode)
{
stopIt = false;
this->mode = mode;
src.setFileName(input);
if(mode == 1)
{
emit msg("Current Encryption/Decryption status: Encrypting file... :D:D");
tag = "-encrypted";
pv.setMode("encrypt", "");
}
else
{
emit msg("Current Encryption/Decryption status: Decrypting file... :D:D");
tag = "-decrypted";
pv.setMode("decrypt", keyFile);
}
dest.setFileName(QFileInfo(src).absolutePath() + "/" + QFileInfo(src).baseName()
+ tag + "." + QFileInfo(src).completeSuffix());
length = src.bytesAvailable();
}
void FileCrypto::run()
{
qint64 done = 0;
quint8 r, outChar;
char ch;
QDataStream in(&src);
in.setVersion(QDataStream::Qt_4_7);
src.open(QIODevice::ReadOnly);
QDataStream out(&dest);
out.setVersion(QDataStream::Qt_4_7);
dest.open(QIODevice::WriteOnly);
while(!in.atEnd() && !stopIt)
{
done++;
in >> r;
ch = char(r);
if(mode == 1)
outChar = pv.encrypt(QString(ch)).at(0).toAscii();
else
outChar = pv.decrypt(QString(ch)).at(0).toAscii();
out << outChar;
emit completed(int((done / length) * 100));
}
src.close();
dest.close();
if(stopIt)
this->exit(0);
if(mode == 1)
{
emit pathMsg1(QFileInfo(src).absoluteFilePath());
emit pathMsg2(QFileInfo(dest).absoluteFilePath());
}
else
{
emit pathMsg1(QFileInfo(dest).absoluteFilePath());
emit pathMsg2(QFileInfo(src).absoluteFilePath());
}
emit keyMsg(pv.keyFilePath);
emit msg("Current Encryption/Decryption status: Idle... :'(");
}
This is how I am making the thread and connecting it on the main GUI thread:
FileCrypto *fc = new FileCrypto(ui->lineEdit_4->text(), "", 1);
connect(fc, SIGNAL(completed(int)), ui->progressBar, SLOT(setValue(int)));
connect(fc, SIGNAL(msg(QString)), ui->statusBar, SLOT(showMessage(QString)));
connect(fc, SIGNAL(pathMsg1(QString)), ui->lineEdit_4, SLOT(setText(QString)));
connect(fc, SIGNAL(pathMsg2(QString)), ui->lineEdit_5, SLOT(setText(QString)));
connect(fc, SIGNAL(keyMsg(QString)), ui->lineEdit_2, SLOT(setText(QString)));
connect(fc, SIGNAL(keyMsg(QString)), this, SLOT(done()));
If I don't update the progress bar i.e. don't emit the percentage, the process happens much faster. I also tried printing the percentage. It slows it down like hell but the values are fine. Also can you suggest a way to change it to buffered IO....
Any sort of help is much appreciated here.......
The problem does not lie in the fact that you are calling from a different thread. It is located in:
emit completed(int((done / length) * 100));
Since done and length are int types, and done <= length, done/length == 0. So change it to:
emit completed(100 * done / length);
(it can lead to arithmetic overflow).
I've been poring over this program for ages, and have no idea why it doesn't work. I'm reasonably sure it's doing everything right but instead of actually working it just hangs indefinitely after printing the first prompt, and I just can't figure out why. I'm pretty much at my wit's end now, so if any can suggest what I'm doing wrong, I'd be much obliged...
It's C99, and you'll need the mhash library to compile it (uses for the CRC32 calculation). It's pretty portable but I developed it on Linux. Do not run in a VM!
#define _BSD_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <mhash.h>
/* WARNING: Do not debug this program. Halting on breakpoints at the wrong
* time can be extremely hazardous. YOU HAVE BEEN WARNED. */
/* Structures used to define our layout. Note the careful use of volatile;
* we don't want the compiler optimising away part of the invocation. */
typedef struct
{
const char name[7]; /* sigil at focus */
volatile int target; /* summoning point */
volatile char invocation; /* current char of invocation */
} focus_t;
typedef struct node
{
const char name[4]; /* name of node */
focus_t* center; /* points to the evocation focus */
struct node* cw; /* clockwise binding ring */
struct node* ccw; /* counterclockwise binding ring */
struct node* star; /* next node of star */
const char* linkname; /* name of star linkage */
volatile uint32_t angel; /* protective angel for this node */
} node_t;
/* The pentacle nodes are circularly linked in both directions to form
* a binding perimeter. In addition, they are singly linked to form a
* classic 'daemon trap' five-pointed star. Each node points towards the
* evocation focus (but not the other way around!) to enforce the geometry
* we want. The design is based heavily on the Pentagram of Solomon. */
struct
{
focus_t focus;
node_t node[5];
}
S =
{
/* None of the symbols for the pentacle are in Unicode. So we have to make
* do with Latin transcriptions. */
.focus = { "SOLUZEN", 0 },
.node = {
[0] = { "TE", &S.focus, &S.node[1], &S.node[4], &S.node[2], "BELLONY" },
[1] = { "TRA", &S.focus, &S.node[2], &S.node[0], &S.node[3], "HALLIY" },
[2] = { "GRAM", &S.focus, &S.node[3], &S.node[1], &S.node[4], "HALLIZA" },
[3] = { "MA", &S.focus, &S.node[4], &S.node[2], &S.node[0], "ABDIA" },
[4] = { "TON", &S.focus, &S.node[0], &S.node[3], &S.node[1], "BALLATON" }
}
};
/* Name of spirit to summon --- rot13'd for safety.
* (#65 from Crowley's translation of SHEMHAMPHORASH.)
* This is Andrealphus, he that has dominion over menusuration, astronomy and
* geometry. He seems fairly non-threatening. */
const char spiritname[] = "NAQERNYCUHF";
int rot13(int c) { return 'A' + (((c - 'A') + 13) % 26); }
/* We invoke the following names around the circle as a protective measure.
* Strictly these should be in Hebrew script, but as the computer is a dumb
* instrument we're relying on the symbolism rather than the actual literal
* meaning themselves. Plus, working in RTL is a pain. */
const char* angels[] = {
"Kether", "Eheieh", "Metatron", "Chaioth ha-Qadesh",
"Rashith ha-Gilgalim", "Chokmah", "Jah", "Ratziel", "Auphanim",
"Masloth", "Binah", "Jehovah Elohim", "Tzaphkiel", "Aralim",
"Shabbathai", "Chesed", "El", "Tzadkiel", "Chasmalim", "Tzadekh",
"Geburah", "Elohim Gibor", "Khamael", "Seraphim", "Madim",
"Tiphareth", "Eloah Va-Daath", "Raphael", "Malachim", "Shemesh",
"Netzach", "Jehovah Sabaoth", "Haniel", "Elohim", "Nogah", "Hod",
"Elohim Sabaoth", "Michael", "Beni Elohim", "Kokab", "Yesod",
"Shaddai El Chai", "Gabriel", "Cherubim", "Levanah"
};
const int angelcount = sizeof(angels)/sizeof(*angels);
/* Place the next angel on the pentacle. */
static void updatepentacle()
{
static int angelnode = 0;
static int angelindex = 0;
const char* angel = angels[angelindex++];
angelindex %= angelcount;
/* Hash the angel's name to reduce its essence to 32 bits (which lets us
* copy the angel bodily into the pentacle node. */
uint32_t angelhash;
MHASH td = mhash_init(MHASH_CRC32);
mhash(td, angel, strlen(angel));
mhash_deinit(td, &angelhash);
S.node[angelnode].angel = angelhash;
angelnode = (angelnode + 1) % 5;
}
int main(int argc, const char* argv[])
{
/* Lock the evocation into memory, to prevent it from being paged out
* while the spirit has manifested --- which would be bad. */
int e = mlock(&S, sizeof(S));
if (e != 0)
{
fprintf(stderr, "Unable to lock evocation, refusing to run\n");
exit(1);
}
/* Actually perform the invocation: continually cycle the spirit's
* name into the evocation focus (while maintaining our pentacle
* integrity!) until something shows up in the target of the
* evocation focus. */
printf("Summoning...\n");
do
{
for (int i = 0; i < sizeof(spiritname)-1; i++)
{
S.focus.invocation = rot13(spiritname[i]);
updatepentacle();
usleep(100); /* don't CPU-starve our spirit */
}
}
while (S.focus.target == 0);
printf("Summoning successful! %d\n", S.focus.target);
/* Our spirit's arrived! Dismiss it immediately by using a null
* invocation. Keep going until the evocation focus remains empty.
* FIXME: a particularly mean spirit might find a way to hide. Until
* we can sort this out, only summon relatively benign ones. This is
* probably safe anyway, as when the process terminates the spirit's
* address space will be nuked, taking the spirit with it. */
printf("Dismissing...\n");
do
{
S.focus.target = 0;
for (int i = 0; i < 1000; i++)
{
S.focus.invocation = 0;
updatepentacle();
}
}
while (S.focus.target != 0);
printf("Done.\n");
return 0;
}
Incidentally, shouldn't there be a goetic tag?
Edit: Sorry I haven't gotten back earlier --- after I posted my query last night I ran some more tests and then my computer started making funny burning smells which didn't go away when I switched it off, so I spent the rest of the night tearing it down trying to find which part was faulty. (Didn't find anything.) I'm going to grab some sleep and get back to you. Thanks for the replies!
Edit: I'm posting this from a web café. My house has burnt down. Don't have time to post more but have to warn you: do not run this program for any reason! Really! Not joking! Have to go now, must find sanctuary somewhere---
Edit: 𝕳𝖔𝖈 𝖘𝖙𝖚𝖑𝖙𝖚𝖘 𝖒𝖊𝖚𝖘 𝖊𝖘𝖙. 𝕹𝖔𝖓 𝖎𝖓𝖙𝖊𝖗𝖕𝖔𝖓𝖊 𝖖𝖚𝖎 𝖓𝖔𝖓 𝖎𝖓𝖙𝖊𝖑𝖑𝖎𝖌𝖊𝖗𝖊.
Crux sacra sit mihi lux!
Nunquam draco sit mihi dux.
Vade retro Satana!
Nunquam suade mihi vana!
Sunt mala quae libas.
Ipse venena bibas!
You are definitely lacking a lot of evil features. You should switch to C++ and have a look at the Comp.lang.c++-FAQ on evil features.
I don't know enough about demons and angels, but you must be summoning them incorrectly, since nothing is changing S.focus.target for you.
I am very much stuck in the following issue. Any help is very much appreciated!
Basically I have a program wich contains an array of structs and I am getting a segmentation error when I call an external function. The error only happens when I have more than 170 items on the array being passed.
Nothing on the function is processed. The program stops exactly when accessing the function.
Is there a limit for the size of the parameters that are passed to external functions?
Main.c
struct ratingObj {
int uid;
int mid;
double rating;
};
void *FunctionLib; /* Handle to shared lib file */
void (*Function)(); /* Pointer to loaded routine */
const char *dlError; /* Pointer to error string */
int main( int argc, char * argv[]){
// ... some code ...
asprintf(&query, "select mid, rating "
"from %s "
"where uid=%d "
"order by rand()", itable, uid);
if (mysql_query(conn2, query)) {
fprintf(stderr, "%s\n", mysql_error(conn2));
exit(1);
}
res2 = mysql_store_result(conn2);
int movieCount = mysql_num_rows(res2);
// withhold is a variable that defines a percentage of the entries
// to be used for calculations (generally 20%)
int listSize = round((movieCount * ((double)withhold/100)));
struct ratingObj moviesToRate[listSize];
int mvCount = 0;
int count =0;
while ((row2 = mysql_fetch_row(res2)) != NULL){
if(count<(movieCount-listSize)){
// adds to another table
}else{
moviesToRate[mvCount].uid = uid;
moviesToRate[mvCount].mid = atoi(row2[0]);
moviesToRate[mvCount].rating = 0.0;
mvCount++;
}
count++;
}
// ... more code ...
FunctionLib = dlopen("library.so", RTLD_LAZY);
dlError = dlerror();
if( dlError ) exit(1);
Function = dlsym( FunctionLib, "getResults");
dlError = dlerror();
(*Function)( moviesToRate, listSize );
// .. more code
}
library.c
struct ratingObj {
int uid;
int mid;
double rating;
};
typedef struct ratingObj ratingObj;
void getResults(struct ratingObj *moviesToRate, int listSize);
void getResults(struct ratingObj *moviesToRate, int listSize){
// ... more code
}
You are likely blowing up the stack. Move the array to outside of the function, i.e. from auto to static land.
Another option is that the // ... more code - array gets populated... part is corrupting the stack.
Edit 0:
After you posted more code - you are using C99 variable sized array on the stack - Bad IdeaTM. Think what happens when your data set grows to thousands, or millions, of records. Switch to dynamic memory allocation, see malloc(3).
You don't show us what listsize is, but I suppose it is a variable and not a constant.
What you are using are variable length arrays, VLA. These are a bit dangerous if they are too large since they usually allocated on the stack.
To work around that you can allocate such a beast dynamically
struct ratingObj (*movies)[listSize] = malloc(sizeof(*movies));
// ...
free(movies);
You'd then have in mind though that movies then is a pointer to array, so you have to reference with one * more than before.
Another, more classical C version would be
struct ratingObj * movies = malloc(sizeof(*movies)*listsize);
// ...
free(movies);
I've noticed that at several places in our code base we use dynamically expanding arrays, i.e. a base array coupled with an element counter and a "max elements" value.
What I want to do is replace these with a common data structure and utility functions, for the usual object-oriented reasons.
The array elements can be either basic data types or structs, I need fast random access to the elements, and preferably a type-safe implementation.
So, basically, what I would like to use is an STL vector, but the code base is restricted to C89 so I have to come up with something else :-)
I gave it some thought and whipped up this initial draft, just to show what I'm aiming at:
/* Type-safe dynamic list in C89 */
#define list_declare(type) typedef struct _##type##_list_t { type * base_array; size_t elements; size_t max_size; } type##_list_t
#define list(type) type##_list_t
#define list_new(type, initial_size) { calloc(initial_size, sizeof(type)), 0, initial_size }
#define list_free(list) free(list.base_array)
#define list_set(list, place, element) if ( list.elements < list.max_size ) { list.base_array[place] = element; } else { /* Array index out of bounds */ }
#define list_add(list, element) if ( list.elements < list.max_size ) { list.base_array[list.elements++] = element; } else { /* Expand array then add */ }
#define list_get(list, n) list.base_array[n]
/* Sample usage: */
list_declare(int);
int main(void)
{
list(int) integers = list_new(int, 10);
printf("list[0] = %d\n", list_get(integers, 0));
list_add(integers, 4);
printf("list[0] = %d\n", list_get(integers, 0));
list_set(integers, 0, 3);
printf("list[0] = %d\n", list_get(integers, 0));
list_free(integers);
return EXIT_SUCCESS;
}
...however, there must be someone else who has done this before. I'm aware of the FreeBSD sys/queue.h implementation of a similar concept for some different queues, but I can't find anything like that for arrays.
Is anyone here any wiser?
glib provides an GArray type, which implements a dynamically growing array. If you can use external 3rd party libraries, glib is almost always a good choice as "standard" library for C. It provides types for all basic data structures, for unicode strings, for date and time values, and so on.
here a simple vector-replacement, its ONE function for all, its strictly C89 and threadsafe;
libs are too difficult for me, i use my own;
no performance, but easy to use
/* owner-structs too */
typedef struct {
char name[20],city[20];
int salary;
} My,*Myp;
typedef char Str80[80];
/* add here your type with its size */
typedef enum {SPTR,INT=sizeof(int),DOUBLE=sizeof(double),S80=sizeof(Str80),MY=sizeof(My)} TSizes;
typedef enum {ADD,LOOP,COUNT,FREE,GETAT,GET,REMOVEAT,REMOVE} Ops;
void *dynarray(char ***root,TSizes ts,Ops op,void *in,void *out)
{
size_t d=0,s=in?ts?ts:strlen((char*)in)+1:0;
char **r=*root;
while( r && *r++ ) ++d;
switch(op) {
case ADD: if( !*root ) *root=calloc(1,sizeof r);
*root=realloc(*root,(d+2)*sizeof r);
memmove((*root)+1,*root,(d+1)*sizeof r);
memcpy(**root=malloc(s),in,s);
break;
case LOOP: while( d-- ) ((void (*)(char*))in)((*root)[d]); break;
case COUNT: return *(int*)out=d,out;
case FREE: if(r) {
++d; while( d-- ) realloc((*root)[d],0);
free(*root);*root=0;
} break;
case GETAT: { size_t i=*(size_t*)in;
if(r && i<=--d)
return (*root)[d-i];
} break;
case GET: { int i=-1;
while( ++i,d-- )
if( !(ts?memcmp:strncmp)(in,(*root)[d],s) )
return *(int*)out=i,out;
return *(int*)out=-1,out;
}
case REMOVEAT: { size_t i=*(size_t*)in;
if(r && i<=--d) {
free((*root)[d-i]);
memmove(&(*root)[d-i],&(*root)[d-i+1],(d-i+1)*sizeof r);
return in;
}
} break;
case REMOVE: while( *(int*)dynarray(root,ts,GET,in,&d)>=0 )
dynarray(root,ts,REMOVEAT,&d,0);
}
return 0;
}
void outmy(Myp s)
{
printf("\n%s,%s,%d",s->name,s->city,s->salary);
}
main()
{
My z[]={{"Buffet","Omaha",INT_MAX},{"Jobs","Palo Alto",1},{"Madoff","NYC",INT_MIN}};
Str80 y[]={ "123","456","7890" };
char **ptr=0;
int x=1;
/* precondition for first use: ptr==NULL */
dynarray(&ptr,SPTR,ADD,"test1.txt",0);
dynarray(&ptr,SPTR,ADD,"test2.txt",0);
dynarray(&ptr,SPTR,ADD,"t3.txt",0);
dynarray(&ptr,SPTR,REMOVEAT,&x,0); /* remove at index/key ==1 */
dynarray(&ptr,SPTR,REMOVE,"test1.txt",0);
dynarray(&ptr,SPTR,GET,"t3.txt",&x);
dynarray(&ptr,SPTR,LOOP,puts,0);
/* another option for enumerating */
dynarray(&ptr,SPTR,COUNT,0,&x);
while( x-- )
puts(ptr[x]);
dynarray(&ptr,SPTR,FREE,0,0); /* frees all mallocs and set ptr to NULL */
/* start for another (user)type */
dynarray(&ptr,S80,ADD,y[0],0);
dynarray(&ptr,S80,ADD,y[1],0);
dynarray(&ptr,S80,ADD,y[2],0);
dynarray(&ptr,S80,ADD,y[0],0);
dynarray(&ptr,S80,LOOP,puts,0);
dynarray(&ptr,S80,FREE,0,0); /* frees all mallocs and set ptr to NULL */
/* start for another (user)struct-type */
dynarray(&ptr,MY,ADD,&z[0],0);
dynarray(&ptr,MY,ADD,&z[1],0);
dynarray(&ptr,MY,ADD,&z[2],0);
dynarray(&ptr,MY,ADD,&z[0],0);
dynarray(&ptr,MY,LOOP,outmy,0);
dynarray(&ptr,MY,FREE,0,0);
return 0;
}
There is sglib, which implements various lists,hashmaps and rbtrees in a generic fashion (i.e. by specializing over a type). There is also a fast sorting function for arrays:
http://sglib.sourceforge.net/
qLibc implements a vector in pure C. The data structure allows it to store any type of object like (void *object) and it provides convenient wrappers for string, formatted string and integer types.
Here's a sample code for your idea.
qvector_t *vector = qvector(QVECTOR_OPT_THREADSAFE);
vector->addstr(vector, "Hello");
vector->addstrf(vector, "World %d", 123);
char *finalstring = vector->tostring(vector);
printf("%s", finalstring);
free(finalstring)
vector->free(vector);
for object type:
int a = 1, b = 2;
qvector_t *vector = qvector(QVECTOR_OPT_THREADSAFE);
vector->add(vector, (void *)&a, sizeof(int));
vector->add(vector, (void *)&b, sizeof(int));
int *finalarray = vector->toarray(vector);
printf("a = %d, b = %d", finalarray[0], finalarray[1]);
free(finalarray)
vector->free(vector);
Note) I made this sample code just for your reference, copying from its example code.
it might have typo errors.
You can check out the Full API reference at http://wolkykim.github.io/qlibc/
I'm using the following macro implementation without problems so far. It isn't a complete implementation but grows the array automatically :
#define DECLARE_DYN_ARRAY(T) \
typedef struct \
{ \
T *buf; \
size_t n; \
size_t reserved; \
} T ## Array;
#define DYN_ARRAY(T) T ## Array
#define DYN_ADD(array, value, errorLabel) DYN_ADD_REALLOC(array, value, errorLabel, realloc)
#define DYN_ADD_REALLOC(array, value, errorLabel, realloc) \
{ \
if ((array).n >= (array).reserved) \
{ \
if (!(array).reserved) (array).reserved = 10; \
(array).reserved *= 2; \
void *ptr = realloc((array).buf, sizeof(*(array).buf)*(array).reserved); \
if (!ptr) goto errorLabel; \
(array).buf = ptr; \
} \
(array).buf[(array).n++] = value; \
}
To use you first write: DECLARE_DYN_ARRAY(YourType)
To declare variables you write DYN_ARRAY(YourType) array = {0}.
You add elements with DYN_ADD(array, element, errorLabel).
You access elements with array.buf[i].
You get the number of elements with array.n.
When done you free it with free(array.buf) (or whatever function you used to allocate it.)
I usually roll my own code for purposes such as this, like you did. It's not particularly difficult, but having type safety etc. is not easily achievable without a whole OO framework.
As mentioned before, glib offers what you need - if glib2 is too big for you, you could still go with glib1.2. It's quite old, but doesn't have external dependencies (except for pthread if you need thread support). The code can also be integrated into larger projects, if necessary. It's LGPL licensed.
Personally, I prefer "Gena" library. It closely resembles stl::vector in pure C89.
It is comfortable to use because you can:
Access vector elements just like plain C arrays: vec[k][j];
Have multi-dimentional arrays;
Copy vectors;
Instantiate necessary vector types once in a separate module, instead of doing this every time you needed a vector;
You can choose how to pass values into a vector and how to return them from it: by value or by pointer.
You can check it out here:
https://github.com/cher-nov/Gena