So I've been studying C programming for a little while now, and while I can understand the basic concept behind pointers, I'm still having a lot of trouble implementing them in my programming, especially when it comes to passing them across multiple different structs. For example, I have this code snippet (I've omitted the non-relevant parts):
main.c
Globals globals;
static void display(Globals *globals)
{
int i;
for (i = 0; i < 20; i++)
{
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex3f(globals->trees[i].pos.x, globals->trees[i].pos.y, globals->trees[i].pos.z);
glTexCoord2f(1, 0);
glVertex3f(globals->trees[i].pos.x + 5, globals->trees[i].pos.y, globals->trees[i].pos.z);
glTexCoord2f(1, 1);
glVertex3f(globals->trees[i].pos.x + 5, globals->trees[i].pos.y + 5, globals->trees[i].pos.z);
glTexCoord2f(0, 1);
glVertex3f(globals->trees[i].pos.x, globals->trees[i].pos.y + 5, globals->trees[i].pos.z);
glEnd();
}
}
globals.h
struct Globals
{
Tree *trees; // tree array
};
globals.c
void initGlobals(Globals *globals)
{
initTrees(&globals->trees, &globals->grid);
}
tree.h
#pragma once
#if __cplusplus
extern "C" {
#endif
#include "utils.h"
typedef struct Tree Tree;
typedef struct Grid Grid;
struct Tree
{
vec3f pos;
};
void initTrees(Tree *trees, Grid *grid);
#if __cplusplus
}
#endif
trees.c
#include "tree.h"
void initTrees(Tree *trees, Grid *grid)
{
trees = (Tree *) calloc(20, sizeof(Tree));
if (trees == NULL)
{
printf("COULD NOT ALLOCATE.");
exit(1);
}
srand(time(NULL));
float x_rand, z_rand;
int i;
for (i = 0; i < 20; i++)
{
x_rand = rand() & 50;
z_rand = rand() & 50;
Tree tree;
tree.pos = cVec3f(x_rand, accumHeight(grid, x_rand, z_rand) + 1, z_rand);
trees[i] = tree;
}
}
At the moment, I'm trying to add a set of tree structs to a tree array and then draw them one by one in main.c, but I'm getting an unhandled exception. I'm almost 100% sure that it's because there's something wrong with my pointer syntax, but I'm not sure what.
You're passing the address of a pointer (and thus a pointer-to-pointer) to a function expecting a single-indirection pointer.
Anytime you see this:
void foo(Something* p)
{
p = some allocation function
...
}
raise your brow, because its likely going to result in a memory leak, if not an outright invalid indirection, (and likely both).
In your case,
void initTrees(Tree *trees, Grid *grid);
is being invoked with
//globals.c
void initGlobals(Globals *globals)
{
initTrees(&globals->trees, &globals->grid);
}
where globals->trees is declared as:
//globals.h
struct Globals
{
Tree *trees; // tree array
};
The type of what is being passed is Tree**, yet the function expects Tree* (incorrectly, but we'll get to that in a minute). The pattern I described in the outset of this answer is repeated here:
void initTrees(Tree *trees, Grid *grid)
{
trees = (Tree *) calloc(20, sizeof(Tree)); // LOOK HERE
if (trees == NULL)
{
printf("COULD NOT ALLOCATE.");
exit(1);
}
srand(time(NULL));
float x_rand, z_rand;
int i;
for (i = 0; i < 20; i++)
{
x_rand = rand() & 50;
z_rand = rand() & 50;
Tree tree;
tree.pos = cVec3f(x_rand, accumHeight(grid, x_rand, z_rand) + 1, z_rand);
trees[i] = tree;
}
}
All this does is allocate some memory and use a trees as a value-parameter (the value is the address of... something... but thats not relevant; that address is lost the moment you make that assignment).
initTrees, needs a double-indirection pointer Tree ** and should dereference it to save the proper data being allocated:
void initTrees(Tree **trees, Grid *grid)
{
Tree *res = calloc(20, sizeof(Tree)); // NOTE: local used for allocation
if (res == NULL)
{
printf("COULD NOT ALLOCATE.");
exit(1);
}
srand(time(NULL));
float x_rand, z_rand;
int i;
for (i = 0; i < 20; i++)
{
x_rand = rand() & 50;
z_rand = rand() & 50;
res[i].pos = cVec3f(x_rand, accumHeight(grid, x_rand, z_rand) + 1, z_rand);
}
// save result
*trees = res; // NOTE: save to out-parameter
}
Or something similar. Note your compiler should be screaming at your about passing an invalid parameter (types mismatching). Also, note the removal of the calloc cast, which isn't needed (nor advised) in C programs.
Best of luck
Related
I'm trying to use a "fixed memory scheme" and pre-allocate memory & reuse it via alloc, init, free fashion as many times as possible.
free() will called at shutdown only, but I want to test many iterations.
Although I call my alloc function bn_tree_alloc_node_space_heap() & init function bn_tree_init_node_heap(), I can only call free function bn_tree_free_node_space once.
Below is a complete reproducible snippet of my memory management, maint_test.c:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <float.h>
#define BN_TREE_HEAP_SIZE 100
/*variables internal*/
typedef struct bntree_internals;
/*bn_tree_node is single bntree_t leaf*/
typedef struct bn_tree_node {
struct bn_tree_node* left;
struct bn_tree_node* right;
float* dataset;
float distance_to_neighbor;
int visited;
int heap_index;
} bn_tree_node;
/*tree*/
typedef struct {
/*in order to keep track of the bn-tree root*/
bn_tree_node* _root;
/*pointer to internal variables struct*/
struct bntree_internals* _internals;
} bntree_t;
/*bn tree leaf nodes heap*/
bn_tree_node* node_processing_space = NULL;
/*leaf nodes*/
void bn_tree_alloc_node_space_heap(int max_dimensions);
bn_tree_node*
get_pre_allocated_bn_tree_node_heap();
void bn_tree_init_node_heap(bn_tree_node* nodes, int max_dimensions);
void bn_tree_free_node_space(bn_tree_node* nodes);
int main(int argc, char** argv) {
/*PROBLEM:called the alloc,init,free cycle several times, problem,
getting seg fault on 2nd call of free()*/
bn_tree_alloc_node_space_heap(3);
assert(get_pre_allocated_bn_tree_node_heap());
printf("alloc\n");
bn_tree_init_node_heap(node_processing_space, 3);
printf("init\n");
bn_tree_free_node_space(node_processing_space);
printf("free\n");
bn_tree_alloc_node_space_heap(3);
assert(get_pre_allocated_bn_tree_node_heap());
printf("alloc\n");
bn_tree_init_node_heap(node_processing_space, 3);
printf("init\n");
bn_tree_free_node_space(node_processing_space);
printf("free\n");
bn_tree_alloc_node_space_heap(3);
assert(get_pre_allocated_bn_tree_node_heap());
printf("alloc\n");
bn_tree_init_node_heap(node_processing_space, 3);
printf("init\n");
bn_tree_free_node_space(node_processing_space);
printf("free\n");
bn_tree_alloc_node_space_heap(3);
assert(get_pre_allocated_bn_tree_node_heap());
printf("alloc\n");
bn_tree_init_node_heap(node_processing_space, 3);
printf("init\n");
bn_tree_free_node_space(node_processing_space);
printf("free\n");
return (EXIT_SUCCESS);
}
void bn_tree_alloc_node_space_heap(int max_dimensions) {
if (NULL == node_processing_space) {
node_processing_space = (bn_tree_node*) calloc(BN_TREE_HEAP_SIZE, sizeof (bn_tree_node));
//TODO: bn_tree_set_k_dimensions (max_dimensions);
int i = 0;
for (; i < BN_TREE_HEAP_SIZE; i++) {
node_processing_space[i].dataset = (float*) calloc(max_dimensions, sizeof (float));
}
//bn_heap_tail_index = bn_heap_head_index = 0;
}
}
bn_tree_node* get_pre_allocated_bn_tree_node_heap() {
return node_processing_space;
}
void bn_tree_init_node_heap(bn_tree_node* nodes, int max_dimensions) {
int i = 0;
int c = 0;
for (; i < BN_TREE_HEAP_SIZE; i++) {
/*reset values */
if (NULL != nodes[i].dataset) {
c = 0;
for (; c < max_dimensions; c++) {
nodes[i].dataset[c] = FLT_MIN;
}
}
nodes[i].visited = 0;
nodes[i].distance_to_neighbor = FLT_MAX;
nodes[i].left = NULL;
nodes[i].right = NULL;
nodes[i].heap_index = -1;
}
}
/*PROBLEM is subsequent call to free(), but if I alloc again why cant I free again?*/
void bn_tree_free_node_space(bn_tree_node* nodes) {
int i = 0;
for (; i < BN_TREE_HEAP_SIZE; i++) {
if (nodes[i].dataset) {
free(nodes[i].dataset);
}
}
free(nodes);
nodes = NULL;
}
Here is the output that I expect/want:
alloc
init
free
alloc
init
free
alloc
init
free
alloc
init
free
But Im getting this output/error:
alloc
init
free
alloc
init
double free or corruption (!prev)
Aborted (core dumped)
How can fix this?
Can't I do alloc,init,free as many times as I want (as long as I called alloc before free) OR I can do only alloc() once, then many init(), free() once?
Thanks a million & please be kind enough to provide concise answers with minimal changes.
The problem is that your bn_tree_free_node_space function takes, as its argument, a copy of the pointer variable - that is, you are passing the pointer by value - thus, the line nodes = NULL; at the end of that function only sets the local variable to NULL and does not change the value of the node_processing_space variable.
To fix this (with minimal changes to your code logic1), you need to pass that function a pointer to the pointer, and dereference that in the function. So, your function should look like this:
void bn_tree_free_node_space(bn_tree_node** nodes) // Argument is pointer-to-pointer
{
int i = 0;
for (; i < BN_TREE_HEAP_SIZE; i++) {
if ((*nodes)[i].dataset) { // Now we need to use (*nodes) to get the underlying pointer
free((*nodes)[i].dataset); // ... same here
}
}
free(*nodes); /// ... and here
*nodes = NULL;
}
You will, of course, also need to change the function prototype (just before your main) to match the new definition:
void bn_tree_free_node_space(bn_tree_node** nodes); // Must match definition!
Fruther, you will (clearly) need to change the calls to that function to pass the address of the node_processing_space pointer:
bn_tree_free_node_space(&node_processing_space); // Likewise for the other 3 calls!
Feel free to ask for further clarification and/or explanation.
1 EDIT: There are other ways (some may argue better ways) to implement your system, and also other 'minor' issues in your code. However, you did explicitly ask for "concise answers with minimal changes," so I have endeavoured to comply with that request!
Since the array address may change when memory is reallocated,
the main part of the program (in the body of the function main ()) should refer to the elements by
indexes, not pointers. Why?
Can you show an example of accessing items with pointers?
(Sorry for my English).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Nameval Nameval;
struct Nameval {
char *name;
int value;
};
struct NVtab {
int nval; /* current number of values */
int max; /* allocated number of values */
Nameval *nameval; /* array of name-value pairs */
};
enum {NVINIT = 1, NVGROW = 2};
/* addname: add new name and value to nvtab */
int addname(struct NVtab *nvtab, Nameval newname) {
Nameval *nvp;
if (nvtab->nameval == NULL) { /* first time */
nvtab->nameval = (Nameval *) malloc(NVINIT * sizeof(Nameval));
if (nvtab->nameval == NULL)
return -1;
nvtab->max = NVINIT;
nvtab->nval = 0;
} else if (nvtab->nval >= nvtab->max) { /* grow */
nvp = (Nameval *) realloc(nvtab->nameval,
(NVGROW*nvtab->max)*sizeof(Nameval));
if (nvp == NULL)
return -1;
nvtab->max *= NVGROW;
nvtab->nameval = nvp;
}
nvtab->nameval[nvtab->nval] = newname;
return nvtab->nval++;
}
int main(void) {
struct NVtab nvtab = {0, 0, NULL};
int curnum;
curnum = addname(&nvtab, (Nameval) {.name="Andy", .value=12});
printf("%d\n", curnum);
curnum = addname(&nvtab, (Nameval) {.name="Billy", .value=18});
printf("%d\n", curnum);
curnum = addname(&nvtab, (Nameval) {.name="Jack", .value=71});
printf("%d\n", curnum);
for (int i = 0; i < nvtab.nval; i++) {
printf("%s %d\n", nvtab.nameval[i].name,
nvtab.nameval[i].value);
}
}
For example, why can`t we show array like this:
for (int i = 0; i < nvtab.nval; i++)
printf("%s %d\n", nvtab.*(nameval+i).name, nvtab.*(nameval+i).value);
You are not supposed to assign a pointer calculated for a specific index to a variable with storage duration which could extend over an insert operation.
That pointer could become invalid, so the lesson behind that example is to always re-evaluate iterators on dynamic data structures.
E.g. what not to do:
auto *foo = &nvtab.nameval[i];
addname(&nvtab, (Nameval) {.name="Billy", .value=18});
printf("%s %d\n", foo->name, foo->value);
In the last line it can work or crash. Depending on whether realloc moved the allocation or resized in-place. Except that you can never know for sure until you execute it, as it isn't even fully deterministic.
This is not valid syntax:
nvtab. *(nameval+i).name
The member access operator . expects to be followed by the name of the member. What you want is:
(*(nvtab.nameval+i)).name
I got assigment from the professor to create a list using pointers. I'm having a problem with free() in all of my functions when I try to free memory. I keep getting a message:
"HEAP CORRUPTION DETECTED: after Normal block (#83) at 0x00D58CE0.
CRT detected that the application wrote to memory after end of heap buffer."
I have no idea how to fix it. I've tried different things but nothing worked so far. I'm not sure where to search for it either anymore. I know that my program is not properly secured yet, but it doesn't affect the problem. I'm trying to eliminate it first before going further with it. Also, do you have any advice on detecting memory leaks from the program in visual studio? Here are my functions, full source code is below in the link:
Full Source Code
struct ListElement
{
int value;
struct element *next;
};
typedef struct ListElement List;
typedef List *ListEl;
void ViewListBackwards(ListEl *list_el)
{
ListEl current_element = *list_el;
int size = 0;
int i = 0;
int *reversed_array;
while (current_element->next != NULL)
{
size++;
current_element = current_element->next;
}
current_element = *list_el;
reversed_array = (int*)malloc(size * sizeof(*reversed_array));
for (i = size; i >= 0; i--)
{
reversed_array[i] = current_element->value;
current_element = current_element->next;
}
for (i = 0; i <= size; i++)
{
printf(" %d. %d\n", i + 1, reversed_array[i]);
}
free(reversed_array);
}
void RemoveFromListFront(ListEl *list_el)
{
if (ListEmpty(list_el) == 0)
{
ListEl current_element = *list_el;
*list_el = current_element->next;
free(current_element);
}
else
{
printf("List is empty!\n");
}
}
void RemoveFromListBack(ListEl *list_el)
{
if (ListEmpty(list_el) == 0)
{
ListEl current_element = *list_el;
ListEl last_element = *list_el;
while (current_element->next != NULL)
{
last_element = current_element;
current_element = current_element->next;
}
last_element->next = NULL;
free(current_element);
}
}
In the following code:
reversed_array = (int*)malloc(size * sizeof(*reversed_array));
for (i = size; i >= 0; i--)
{
reversed_array[i] = current_element->value;
current_element = current_element->next;
}
for (i = 0; i <= size; i++)
{
printf(" %d. %d\n", i + 1, reversed_array[i]);
}
you are allocating (what amounts to) an int reversed_array[size] array, but then proceed to write to reversed_array[size], which is sizeof(int) past the end of the allocated memory segment.
You instead want to change your for loops to:
for (i = size - 1; i >= 0; i--)
so that the indices you write to start at reversed_array[size - 1].
EDIT:
As an aside, please, as other people have suggested in the comments, don't cast malloc(). This is unneeded in C, as void * can be assigned to any object pointer type variables, and in addition can hide bugs in your code, such as forgetting to include stdlib.h.
And FWIW, you don't need the parentheses around sizeof(*reversed_array), as parentheses are only needed when applying the sizeof operator to types.
This is mostly just a style suggestion; it is preferred by many (myself included) that you omit the extraneous parentheses and write that expression as sizeof *reversed_array, as that makes it clear that sizeof is a unary operator and not a function.
I trying to use a dynamic array, when i finish using it, i try to free the memory used and i get this error.
free(): invalid next size (fast): 0x00652098
This are the declarations of the struct variables:
struct player {
int played_time;
int min_time;
int max_time;
int errors;
int color;
};
struct Players {
struct player *array;
size_t player_number;
size_t size;
};
typedef struct Players Player_list;
This are the method used to manage the dynamic array:
void initArray(Player_list *list, size_t initialSize) {
list->array = (struct player *) malloc(initialSize * sizeof(struct player));
list->player_number = 0;
list->size = initialSize;
}
void insertArray(Player_list *list, struct player element) {
if (list->player_number == list->size) {
list->size *= 2;
list->array = (struct player *) realloc(list->array,
list->size * sizeof(struct player));
}
list->array[list->player_number++] = element;
}
void freeArray(Player_list *list) {
free(list->array);
list->array = NULL;
list->player_number = list->size = 0;
}
int disqualified(Player_list *list, int errors) {
int i = 0;
for (i = 0; i < list->player_number; i++) {
if (list->array[i].errors >= errors) {
return 1;
}
}
return 0;
}
And here is how i use it in the main:
/**
* When button is pressed 1 add an error to a random player
*/
void button_s_isr(void) {
int index = rand() % (players.player_number);
point_players->array[index].errors = point_players->array[index].errors + 1;
}
...
int main(void) {
...
// set up of GPIO
// get with scanf NUMBER_OF_PLAYERS and MAX_ERRORS values
int i;
for (i = 0; i < NUMBER_OF_PLAYERS; i++) {
struct player player;
player.color = PLAYER_COLORS[i];
player.errors = 0;
player.max_time = 0;
player.min_time = 0;
player.played_time = 0;
insertArray(&players, player);
}
while (disqualified(&players, MAX_ERRORS) != 1) {
// wait
}
printf("\n Se ha acabdo el juego: ");
freeArray(point_players);
return EXIT_SUCCESS;
}
I must say i am quite new to C, sorry if it is difficult to understand.
What i want to do is a dynamic list of struct (players), where each player has own parameters (played_time, min_time , max_time, errors, color). And inside the main i want to have a game where i can control this parameters from each player.
Any help to improve the code is appreciated.
the posted code:
does not compile
is missing definitions for PLAYER_COLORS[i], which is a bad idea to use as the number of players could exceed the available colours in the array.
incorrectly calculates the size needed for the realloc()
fails to check the returned values from functions like malloc() and realloc()
contains a confusing (even for the OP) naming of variables and struct instances
is missing the definition for num_jugadores
incorrectly tries to assign a struct rather than copying the struct
fails to declare an instance of struct Players
and now, corrected code that compiles cleanly:
caveat: not fully tested
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // memcpy()
struct player
{
int played_time;
int min_time;
int max_time;
int errors;
int color;
};
struct Players
{
struct player *array;
size_t player_number;
size_t numPlayers;
};
//This are the method used to manage the dynamic array:
void freeArray(struct Players *pArray)
{
free(pArray->array);
pArray->array = NULL;
pArray->player_number = pArray->numPlayers = 0;
}
void initArray( struct Players *pArray )
{
if( NULL == (pArray->array = malloc(sizeof(struct player)) ) )
{ // then malloc failed
freeArray( pArray );
exit( EXIT_FAILURE );
}
// implied else, malloc successful
pArray->player_number = 0;
pArray->numPlayers = 1;
}
size_t sizeof_array(size_t size)
{
return size * sizeof(struct player);
}
void insertArray(struct Players *pArray, struct player *element)
{
if (pArray->player_number == pArray->numPlayers)
{ // then currently allocated memory for array of players is full
struct player *temp = NULL;
if( NULL == (temp = realloc(pArray->array, sizeof_array(pArray->numPlayers)*2) ) )
{ // then, realloc failed
freeArray( pArray );
exit( EXIT_FAILURE );
}
// implied else, realloc successful
pArray->numPlayers *= 2;
pArray->array = temp;
}
memcpy( &(pArray->array[pArray->player_number]), element, sizeof( struct player ) );
pArray->player_number++;
}
//and here is how i use it in the main method:
#define num_jugadores (20)
int main( void )
{
int i;
struct Players playerList;
initArray(&playerList);
for (i = 0; i < num_jugadores; i++)
{
struct player myPlayer;
//player.color = PLAYER_COLORS[i];
myPlayer.errors = 0;
myPlayer.max_time = 0;
myPlayer.min_time = 0;
myPlayer.played_time = 0;
insertArray(&playerList, &myPlayer);
}
//...
freeArray(&playerList);
} // end function: main
An error like this usually occurs because you are writing past the end of declared memory. While we could probably find the bug by carefully pouring over every line of code, valgrind would find it much faster for you.
Try compiling your code in debug mode, without optimizations, (gcc -g -O0 if you are using gcc) and run your program under valgrind (e.g., valgrind myprog -my-prog-options). It should flag the error right away.
All this assumes you are running a variant of linux. If you are using visual studio, there will probably be a similar memory checker, but I don't know what it is or how to run it.
Good Luck!
I am implementing a way to transfer a set of data to a programmable dongle. The dongle is based on a smart card technology and can execute an arbitrary code inside. The input and output data is passed as a binary blocks that can be accessed via input and output pointers.
I would like to use an associative array to simplify the data processing code. Everything should work this way:
First the host application:
// Host application in C++
in_data["method"] = "calc_r";
in_data["id"] = 12;
in_data["loc_a"] = 56.19;
in_data["loc_l"] = 44.02;
processor->send(in_data);
Next the code inside the dongle:
// Some dongle function in C
char* method_name = assoc_get_string(in_data, "method");
int id = assoc_get_int(in_data, "id");
float loc_a = assoc_get_float(in_data, "loc_a");
float loc_l = assoc_get_float(in_data, "loc_l");
So my question is about the dongle part functionality. Is there C code or library to implement such an associative array behavior like the above?
Glib's hash table. implements a map interface or (associative array).
And it's most likely the most used hash table implementation for C.
GHashTable *table=g_hash_table_new(g_str_hash, g_str_equal);
/* put */
g_hash_table_insert(table,"SOME_KEY","SOME_VALUE");
/* get */
gchar *value = (gchar *) g_hash_table_lookup(table,"SOME_KEY");
My suspicion is that you would have to write your own. If I understand the architecture you are describing, then you will need to send the entire chunk of data in a single piece. If so, then most libraries will not work for that because they will most likely be allocating multiple pieces of memory, which would require multiple transfers (and an inside understanding of the structure). It would be similar to trying to use a library hash function and then sending its contents over the network on a socket just by passing the root pointer to the send function.
It would be possible to write some utilities of your own that manage a very simple associative array (or hash) in a single block of memory. If the amount of data is small, it could use a simple linear search for the entries and would be a fairly compact bit of code.
Try uthash, a header library implementing a hash table in C. It's small and fairly easy to use.
This is an old thread, but I thought this might still be useful for anyone out there looking for an implementation. It doesn't take too much code; I did mine in ~100 lines of without any extra library. I called it a dictionary since it parallels (sort of) the python datatype. Here is my code:
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
typedef struct hollow_list hollow_list;
struct hollow_list{
unsigned int size;
void *value;
bool *written;
hollow_list *children;
};
//Creates a hollow list and allocates all of the needed memory
hollow_list hollow_list_create(unsigned int size){
hollow_list output;
output = (hollow_list) {.size = size, .value = (void *) 0, .written = calloc(size, sizeof(bool)), .children = calloc(size, sizeof(hollow_list))};
return output;
}
//Frees all memory of associated with a hollow list and its children
void hollow_list_free(hollow_list *l, bool free_values){
int i;
for(i = 0; i < l->size; i++){
hollow_list_free(l->children + i, free_values);
}
if(free_values){
free(l->value);
}
free(l);
}
//Reads from the hollow list and returns a pointer to the item's data
void *hollow_list_read(hollow_list *l, unsigned int index){
if(index == 0){
return l->value;
}
unsigned int bit_checker;
bit_checker = 1<<(l->size - 1);
int i;
for(i = 0; i < l->size; i++){
if(bit_checker & index){
if(l->written[i] == true){
return hollow_list_read(l->children + i, bit_checker ^ index);
} else {
return (void *) 0;
}
}
bit_checker >>= 1;
}
}
//Writes to the hollow list, allocating memory only as it needs
void hollow_list_write(hollow_list *l, unsigned int index, void *value){
if(index == 0){
l->value = value;
} else {
unsigned int bit_checker;
bit_checker = 1<<(l->size - 1);
int i;
for(i = 0; i < l->size; i++){
if(bit_checker & index){
if(!l->written[i]){
l->children[i] = hollow_list_create(l->size - i - 1);
l->written[i] = true;
}
hollow_list_write(l->children + i, bit_checker ^ index, value);
break;
}
bit_checker >>= 1;
}
}
}
typedef struct dictionary dictionary;
struct dictionary{
void *value;
hollow_list *child;
};
dictionary dictionary_create(){
dictionary output;
output.child = malloc(sizeof(hollow_list));
*output.child = hollow_list_create(8);
output.value = (void *) 0;
return output;
}
void dictionary_write(dictionary *dict, char *index, unsigned int strlen, void *value){
void *hollow_list_value;
dictionary *new_dict;
int i;
for(i = 0; i < strlen; i++){
hollow_list_value = hollow_list_read(dict->child, (int) index[i]);
if(hollow_list_value == (void *) 0){
new_dict = malloc(sizeof(dictionary));
*new_dict = dictionary_create();
hollow_list_write(dict->child, (int) index[i], new_dict);
dict = new_dict;
} else {
dict = (dictionary *) hollow_list_value;
}
}
dict->value = value;
}
void *dictionary_read(dictionary *dict, char *index, unsigned int strlen){
void *hollow_list_value;
dictionary *new_dict;
int i;
for(i = 0; i < strlen; i++){
hollow_list_value = hollow_list_read(dict->child, (int) index[i]);
if(hollow_list_value == (void *) 0){
return hollow_list_value;
} else {
dict = (dictionary *) hollow_list_value;
}
}
return dict->value;
}
int main(){
char index0[] = "hello, this is a test";
char index1[] = "hello, this is also a test";
char index2[] = "hello world";
char index3[] = "hi there!";
char index4[] = "this is something";
char index5[] = "hi there";
int item0 = 0;
int item1 = 1;
int item2 = 2;
int item3 = 3;
int item4 = 4;
dictionary d;
d = dictionary_create();
dictionary_write(&d, index0, 21, &item0);
dictionary_write(&d, index1, 26, &item1);
dictionary_write(&d, index2, 11, &item2);
dictionary_write(&d, index3, 13, &item3);
dictionary_write(&d, index4, 17, &item4);
printf("%d\n", *((int *) dictionary_read(&d, index0, 21)));
printf("%d\n", *((int *) dictionary_read(&d, index1, 26)));
printf("%d\n", *((int *) dictionary_read(&d, index2, 11)));
printf("%d\n", *((int *) dictionary_read(&d, index3, 13)));
printf("%d\n", *((int *) dictionary_read(&d, index4, 17)));
printf("%d\n", ((int) dictionary_read(&d, index5, 8)));
}
Unfortunately you can't replicate the list[x] syntax, but this is the best alternative I have come up with.
Yes, but it will not work in the way you have specified. It will instead use a struct to store the data and functions that operate on that struct, giving you the result you want. See A Simple Associative Array Library In C. Example of use:
struct map_t *test;
test=map_create();
map_set(test,"One","Won");
map_set(test,"Two","Too");
map_set(test,"Four","Fore");
GLib's Hash Tables and Balanced Binary Trees might be what you're after.
Mark Wilkins gave you the right answer. If you want to send the data as a single chunk, you need to understand how C++ maps are represented in your architecture and write the access functions.
Anyway, if you decide to recreate the map on the dongle, I've written a small C library where you could write thinks like:
tbl_t in_data=NULL;
tblSetSS(in_data,"method","calc_r");
tblSetSN(in_data,"id",12);
tblSetSF(in_data,"loc_a",56.19);
tblSetSF(in_data,"loc_l",44.02);
and then:
char *method_name = tblGetP(in_data, "method");
int id = tblGetN(in_data, "id");
float loc_a = tblGetF(in_data, "loc_a");
float loc_l = tblGetF(in_data, "loc_l");
The hashtable is a variation of the Hopscotch hash, which is rather good on average, and you can have any mix of type for keys and data (i.e. you can use an entire table as a key).
The focus for that functions was on easing programming rather than pure speed and the code is not thoroughly tested but if you like the idea and want to expand on it, you can have a look at the code on googlecode.
(There are other things like variable length strings and a fast sttring pattern matching function but those might not be of interest in this case).