I am trying to use Tcl C api for creating a hashtable of my C elements and link them to some string (key is string and the value is pointer to my C object).
my problem is that when I want to create the destroy function for my object, this destroy function gets clientData that is pointer that can be casted to my object type but I can't find this object in the hash table with this pointer (because the key's are strings).
How can I solve this issue? is Tcl_linkvar is something that will be usefull in this case?
I will provide some code that I wrote:
Tcl_InitHashTable(hash_table,TCL_STRING_KEYS);
...
int addMyObj(My_Obj * _obj , const char* _obj_name) {
Tcl_HashEntry * _new_entry;
int newptr;
if (_obj == NULL || strlen(_obj_name) == 0) return TCL_ERROR;
char * _name = (char *) malloc (strlen(_obj_name));
if (_name == NULL) return TCL_ERROR;
_new_entry=Tcl_CreateHashEntry(hash_table,_name,&newptr);
if (newptr == 0) {
printf("Error: obj with name %s already exists\n",_obj_name);
return TCL_ERROR;
}
Tcl_SetHashValue(_new_entry,_obj);
return TCL_OK;
}
void removeMyObj(const char * _obj_name) {
Tcl_HashEntry * _entry;
_entry = Tcl_FindHashEntry(hash_table,_obj_name);
// entry was found
if (_entry != NULL) {
My_Obj * _my_obj = (My_Obj * ) Tcl_GetHashValue(_entry);
Tcl_DeleteHashEntry(_entry);
delete _my_obj;
}
return;
}
My_Obj * getMyObj(const char * _obj_name) {
Tcl_HashEntry * _entry;
_entry = Tcl_FindHashEntry(hash_table,_obj_name);
// entry was found
if (_entry != NULL) {
My_Obj * _my_obj = (My_Obj * ) Tcl_GetHashValue(_entry);
return _my_obj;
}
return NULL;
}
// The problem is that in this function I should remove the object from hash table and delete it afterwards.
extern "C" void My_Obj_destroy(ClientData clientData) {
if (clientData != NULL) {
My_Obj * _my_obj = (My_Obj *) clientData;
removeMyObj(_my_obj); // should be removed from the hash table but it is receiving pointer to my_obj and not it's name
delete _my_obj ;
_my_obj = NULL;
}
return;
}
thank you
There are two ways to handle this:
Keep a copy of the name of the object in the object.
Keep a pointer to the Tcl_HashEntry created when you make a name for the object in the hash table. (It's just a pointer, but it is guaranteed to be valid from creation until it is deleted.)
In your case, it's probably best to keep that Tcl_HashEntry * — it's the value returned by Tcl_CreateHashEntry() or looked up with Tcl_FindHashEntry() — so that you can delete easily. The only tricky bit is that this means you must make sure that you are careful about deletion order, which means taking care when you seek to delete the overall hash table.
Related
Function is waiting for a pointer but I want to return an integer in the function lookup (i can't modify the return type of the function), what can i do to solve this problem ?
int hashtable_insert(HashTable ** ptable, void *data, void (*delete) (void *))
{
if(hashtable_lookup(*ptable, data) != -1){
return -1;
}
data = malloc(sizeof(size_t));
list_append((*ptable)->list, data, (*ptable)->size);
_hashtable_resize(ptable);
return 0;
}
warning: comparison between pointer and integer
if(hashtable_lookup(*ptable, data) != -1){
void * hashtable_lookup(HashTable * table, void *data)
{
for(int i = 0; i < (table)->length; i++){
if((table)->list[i] == data){
return data;
}
}
return -1;
}
warning: return makes pointer from integer without a cast [-Wint-conversion]
return -1;
Function is waiting for a pointer but I want to return an integer in the function lookup (i can't modify the return type of the function), what can i do to solve this problem ?
If the function returns void * and you cannot change that, then returning an integer simply is not an option. You could return an integer converted to a pointer (and compare the return value against a similar value), but unless your hash table supports null values, a null pointer would make a better failure code:
void * hashtable_lookup(HashTable * table, void *data) {
// look up data ...
// lookup failed
return NULL;
}
// ...
if (hashtable_lookup(*ptable, data) != NULL) {
// data is already present in the hash table
return -1;
}
But if a null pointer would be valid data for the table, then
void * hashtable_lookup(HashTable * table, void *data) {
// look up data ...
// lookup failed
return (void *) -1;
}
// ...
if (hashtable_lookup(*ptable, data) != (void *) -1) {
// data is already present in the hash table
return -1;
}
First warning is because you are comparing a void* to an int. The second one is because you're returning an int instead of a pointer.
You could add casts here and there to remove the warnings (if(hashtable_lookup(*ptable, data) != (void*)(-1)){ and return (void*)(-1);, but it would be harder to read and more error-prone since you usually check pointers to not be NULL, but not to be different than "-1".
Typically, you would return a NULL pointer to indicate that the function failed. Also, you might have if(hashtable_lookup(*ptable, data) != -1){ wrong since it looks like when hasthable_lookup() returns -1 it failed.
I think this is what you are looking for.
int hashtable_insert(HashTable ** ptable, void *data, void (*delete) (void *))
{
if(hashtable_lookup(*ptable, data) == NULL){
return -1;
}
data = malloc(sizeof(size_t));
list_append((*ptable)->list, data, (*ptable)->size);
_hashtable_resize(ptable);
return 0;
}
void * hashtable_lookup(HashTable * table, void *data)
{
for(int i = 0; i < (table)->length; i++){
if((table)->list[i] == data){
return data;
}
}
return NULL;
}
while I was trying to implement my own (string type) Map, I ran into a problem that causes a segmantation fault, while trying to put data in the "value" corresponds to the key Im trying to update.
this is the declaration of the structs, the map struct is an abstract one, so its pointer is in the header file:
typedef struct KeyValue {
char* key;
char* value;
} *keyValue;
struct Map_t {
keyValue* elements;
int size;
int max_size;
int iterator;
};
this is the function that allocates the memory for all the elements inside the map, and initializing them:
Map mapCreate() {
Map map = malloc(sizeof(*map));
if (map == NULL) {
return NULL;
}
map->elements = malloc(INITIAL_SIZE * sizeof(keyValue));
if (map->elements == NULL) {
free(map);
return NULL;
}
map->size = 0;
map->max_size = INITIAL_SIZE;
map->iterator = 0;
return map;
}
this is the function that put an element to a key - override it if there is already an existing key, or making a new one if needed:
MapResult mapPut(Map map, const char* key, const char* data) {
if (map == NULL || key == NULL || data == NULL) {
return MAP_NULL_ARGUMENT;
}
int index = mapFind(map,key);
char* tmp_key = copyString(key); //making a copy of the const key
char* tmp_value = copyString(data); //making a copy of the const data
if (index != ELEMENT_NOT_FOUND) {
keyValue element = map->elements[index];
element->value = tmp_value; //assigning the requested data to the value corresponds to the key
free(tmp_value);
free(tmp_key);
return MAP_SUCCESS;
}
if (map->size == map->max_size) {
if (expand(map) == MAP_OUT_OF_MEMORY) {
return MAP_OUT_OF_MEMORY;
}
}
return createKeyValue(map, tmp_key ,tmp_value); //creates a new key-value
}
and this is the createKeyValue function:
static MapResult createKeyValue(Map map, char* tmp_key, char* tmp_value) {
// we use this function inside another one that checks for null arguments
assert(map != NULL);
if (tmp_key == NULL || tmp_value == NULL) {
return MAP_OUT_OF_MEMORY;
}
int index = map->size;
keyValue element = map->elements[index];
strcpy(element->key,tmp_key); // segmantation fault here
strcpy(element->value,tmp_value);
free(tmp_key);
free(tmp_value);
map->size++;
return MAP_SUCCESS;
}
Im getting the segmentation fault while this function is trying to access with the strcpy function. I already checked if I allocated memorry correctly, and to me it seems that I did everything I should do.
Im really lost because for 2 days I tried everything and cant find the solution.
You have many problems, some of which are listed in comments.
But the root cause seems to be that you don't actually allocate memory for the struct KeyValue structure objects. That means map->elements[index] will be an indeterminate and invalid pointer, for all possible indexes.
You need to allocate memory for map->elements[index].
A possibly fixed version of the createKeyValue function could look something like:
static MapResult createKeyValue(Map map, char* tmp_key, char* tmp_value) {
// we use this function inside another one that checks for null arguments
assert(map != NULL);
if (tmp_key == NULL || tmp_value == NULL) {
return MAP_OUT_OF_MEMORY;
}
int index = map->size;
// Allocate memory for the structure
map->elements[index] = malloc(sizeof map->elements[index]);
// Make the key and value pointers point to the newly allocated "temporary" strings
map->elements[index]->key = tmp_key;
map->elements[index]->value = tmp_value;
map->size++;
return MAP_SUCCESS;
}
I wrote a piece of code that recursively finds the smallest string in a tree and deletes it. However, printing the tree after deleting the node returns (null).
static char* findMinimum(TreeNodePtr treePtr){
if(treePtr->left == NULL){
printf("Minimum node is %s\n", treePtr->item);
char * temp = treePtr->item;
(treePtr)->item = NULL;
return(temp);
}
else{
findMinimum(treePtr->left);
}
}
I THINK this function works since it deletes the minimum value even using different strings. Should I write a condition to make sure NULL pointers won't get printed? Just in case, here's the print function as well:
static void printTree(TreeNodePtr treePtr) {
if (treePtr != NULL) {
level++;
printTree(treePtr->left);
printf(">%*s%s\n", level*5, "", treePtr->item);
printTree(treePtr->right);
level--;
}
}
I see couple of problems in your findMinimum function:
1) What do you return in else-case in findMinimum? I guess you forgot to add return:
static char* findMinimum(TreeNodePtr treePtr){
if(treePtr->left == NULL){
printf("Minimum node is %s\n", treePtr->item);
char * temp = treePtr->item;
(treePtr)->item = NULL;
free(treePtr->item);
return(temp);
}
else{
return findMinimum(treePtr->left); // added return
}
}
2) Is your tree a binary search tree? Consider what happens in this case:
root-node
/ \
smallest largest
\
not-smallest
You should rehang not-smallest node instead of smallest.
3) Why do you free NULL?
(treePtr)->item = NULL;
free(treePtr->item);
You're deleting the smallest node without changing the child of its parent. If you delete a node, you should also change its parent to point to NULL. Note that setting treePtr->item to NULL doesn't accomplish this as treePtr->left points to a TreeNodePtr, not to its item member.
This function
static char* findMinimum(TreeNodePtr treePtr){
if(treePtr->left == NULL){
printf("Minimum node is %s\n", treePtr->item);
char * temp = treePtr->item;
(treePtr)->item = NULL;
free(treePtr->item);
return(temp);
}
else{
findMinimum(treePtr->left);
}
}
does not make sense.
For starters this part or the code
else{
findMinimum(treePtr->left);
}
returns nothing. So the function already have undefined behavior.
Also consider these statements
(treePtr)->item = NULL;
free(treePtr->item);
The call of free does nothing.
Otherwise if you will exchange the statements when the function returns a pointer to already deleted string. And again the progarm will have undefined behavior.
Also it is unclear how the function will behave when it will be called the second time when the smallest string was already deleted.
And you have to dynamically create a copy of the smallest string that will be returned from the function.
I would suggest the following function implementation (without testing).
static char * findMinimum( TreeNodePtr treePtr )
{
if ( treePtr == NULL || treePtr->item == NULL ) return NULL;
if ( treePtr->left == NULL || treePtr->left->item == NULL )
{
char *s = malloc( strlen( treePtr->item ) + 1 );
strcpy( s, treePtr->item );
free( treePtr->item );
treePtr->item = NULL;
return s;
}
else
{
return findMinimum( treePtr->left );
}
}
I'm a beginner C programmer and have issues implementing an (ordered) dynamic array of structs.
Before adding an element to the array, I want to check if it is full and double it's size in that case:
void insert_translation(dict_entry **dict, char *word, char *translation){
if( dictionary_entries == dictionary_size ){
dict_entry *temp_dict;
temp_dict = realloc(&dict, (dictionary_size *= 2) * sizeof(dict_entry) );
// printf("Increased dict size to %d\n", dictionary_size);
// if(temp_dict == NULL){
// fprintf(stderr, "Out of memory during realloc()!\n");
// /*free(dict);
// exit(EXIT_OUT_OF_MEMORY);*/
// }
//free(dict);
//*dict = temp_dict;
}
dictionary_entries++;
printf("Inserted %s into dict - %d of %d filled.\n", word, dictionary_entries, dictionary_size);
}
I call the function from the main function like this:
dictionary_size = 2; //number of initial key-value pairs (translations)
dictionary_entries = 0;
dict_entry *dictionary = malloc(dictionary_size * sizeof(dict_entry));
[...]
insert_translation(&dictionary, "bla", "blub");
In my understanding, dictionary is a pointer to a space in memory. &dictionary is a pointer to the pointer, which I pass to the function. In the function, dict is said pointer to pointer, so &dict should be the pointer to the area in memory? However, when I try to compile, I get the following error message:
pointer being realloc'd was not allocated
Edit
I expanded the code sample to show more of the code in the main function.
The problem is in this statement
temp_dict = realloc(&dict, (dictionary_size *= 2) * sizeof(dict_entry) );
The parameter dict has the type
dict_entry **dict
in the statement that reallocs the memory you have to use the value of the pointer *dic but you are uisng an expression &dict that has the type dict_entry ***.
Compare the type of the left side of the assignment
ict_entry *temp_dict
with the type of the reallocated pointer. They should be the same (except in C one of them can have the type void *)
So you need to write
temp_dict = realloc(*dict, (dictionary_size *= 2) * sizeof(dict_entry) );
^^^^^
In C arguments are passed by value. If you want to change the original value of an argument you should to pass it by reference through a pointer to the argument. In the function you need to dereference the pointer that to change the object pointed to by the pointer.
&dict -> *dict. You can simplify the code by using a return type, to avoid such bugs:
dict_entry* insert_translation(dict_entry* dict, char *word, char *translation)
{
...
if( dictionary_entries == dictionary_size )
{
dictionary_size *= 2;
dict_entry *tmp = realloc(dict, sizeof(dict_entry[dictionary_size]));
if(tmp == NULL)
{
// error handling, free(dict) etc
}
else
{
dict = tmp;
}
}
...
return dict;
}
i have a task in class to the return an array of struck Symbol from huffman tree.
the function getSL get a huffman tree(only) and return struck of Symbol.
each spot in the array contain a char from the "leaf" of the tree and the
length of his code(how many cross section till the leaf).
my main problem was to find how i advance the cnt of the arry that it will not overright the arry.
thank you.
typedef struct HNode {
char chr;
struct HNode *left, *right;
} HNode;
typedef struct {
char chr;
int counter;
}Symbol;
this is what i did till now.
Symbol * getSL(HNode *root) {
if (root->left == NULL && root->right == NULL) {
Symbol* b = (Symbol*)malloc(100);
b->counter=0;
b->chr = root->chr;
return b;
}
Symbol* a = (Symbol*)malloc(100);
if (root->left != NULL) {
a= getSL(root->left);
a->counter++;
}
if (root->right != NULL) {
a= getSL(root->right);
a->counter++;
}
return a;
}
Apart from the malloc problem (see the comments already), you have a fundamental problem: You allocate a new struct, but then replace it with the one returned from the recursive call. So you lose the one created before (actually, memory leaking!).
Easiest variant would now be converting your Symbol to linked list nodes; then you simply could do:
Symbol* lastLeafFound; // probaly a function parameter!
if(!(root->left || root->right))
{
// leaf found:
Symbol* a = (Symbol*)malloc(sizeof(Symbol));
a->chr = root->chr;
a->counter = /* ... */;
a->next = NULL;
lastLeafFound->next = a;
// you might return a now as last leaf found, using it in the next recursive call
}
Sure, above code is incomplete, but should give you the idea...
If you cannot modify your struct, then you need to create an array and pass it on to every new recursive call (prefer not to use global variables instead):
void doGetSL
(
HNode* root,
Symbol** symbols, // your array to be used
unsigned int* count, // number of symbols contained so far
unsigned int* capacity // maximum possible symbols
)
Passing all data as pointers allows the function to modify them as needed and they are still available from outside...
Symbol* getSL(HNode* root)
{
if(!root)
return NULL;
unsigned int count = 0;
unsigned int capacity = 128;
// allocate a whole array:
Symbol* array = malloc(capacity*sizeof(Symbol));
if(array) // malloc could fail...
{
doGetSL(root, &array, &count, &capacity);
// as you cannot return the number of leaves together with
// the array itself, you will need a sentinel:
array[count].chr = 0;
// obvious enough, I'd say, alternatively you could
// set counter to 0 or -1 (or set both chr and counter)
}
return array;
}
doGetSL will now use above set up "infrastructure":
{
if(!(root->left || root->right))
{
if(*count == *capacity)
{
// no memory left -> we need a larger array!
// store in separate variables:
unsigned int c = *capacity * 2;
Symbol* s = realloc(symbols, c * sizeof(Symbol));
// now we can check, if reallocation was successful
// (on failure, s will be NULL!!!):
if(s)
{
// OK, we can use them...
*symbols = s; // <- need a pointer for (pointer to pointer)!
*capacity = c;
}
else
{
// re-allocation failed!
// -> need appropriate error handling!
}
}
(*symbols)[count].chr = root->chr;
(*symbols)[count].counter = /*...*/;
++*count;
}
else
{
if(root->left)
{
doGetSL(root->left, symbols, count, capacity);
}
if(root->right)
{
doGetSL(root->right, symbols, count, capacity);
}
}
}
One thing yet omitted: setting the counter. That would be quite easy: add another parameter to doGetSL indicating the current depth, which you increment right when entering doGetSL, you can then just assign this value when needed.
You can further improve above variant (especially readability), if you introduce a new struct:
struct SLData
{
Symbol* symbols, // your array to be used
unsigned int count, // number of symbols contained so far
unsigned int capacity // maximum possible symbols
};
and pass this one instead of the three pointers:
doGetSL(HNode*, struct SLData*, unsigned int depth);
struct SLData data =
{
.count = 0;
.capacity = 128;
.array = malloc(capacity*sizeof(Symbol));
};
if(data.array)
doGetSL(root, &data, 0); // again passed as pointer!