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;
}
Related
I have the task of going through a binary search tree and collecting the keys in every node and storing them in an array. After this, I have to set the last element of this array as NULL. This is all done inside a function, which then returns this array of *char.
I believe the part about collecting the keys and storing them in the array is working well, as I've tested that enough. However, I'm not able to define the last element of the array as NULL correctly. I thought it should be done like this:
list_keys[tree_size(tree)] = NULL;
However, after some printf's, I realized that this was cleaning my tree. When I print tree_size(tree) before this line, it gives me the size of the tree correctly. However, when I do it after that line, it gives me 0. I don't believe that the problem is in the function tree_size() because when I attempt to access an element of the tree before that line, it works well, but after the line, I get a Segmentation fault (core dumped) error, probably due to trying access something that doesn't exist anymore.
I have no idea what's wrong, so any help is appreciated. Thanks in advance.
EDIT:
The tree is of the type tree_t and it's defined as:
struct tree_t {
struct entry_t *entry;
struct tree_t *right_child;
struct tree_t *left_child;
};
The tree_size() is defined as:
int tree_size(struct tree_t *tree) {
if (tree->entry != NULL) {
//if two children exist
if (tree->left_child != NULL && tree->right_child != NULL) {
return 1 + tree_size(tree->left_child) + tree_size(tree->right_child);
}
//there's a right child and there isnt a left child
if (tree->right_child != NULL && tree->left_child == NULL) {
return 1 + tree_size(tree->right_child);
}
//there's a left child and there isnt a right child
if (tree->left_child != NULL && tree->right_child == NULL) {
return 1 + tree_size(tree->left_child);
}
//there are no children
if (tree->left_child == NULL && tree->right_child == NULL) {
return 1;
}
}
//if the entry is empty
return 0;
}
Basically, what I'm doing right now is:
First, I define list_keys and allocate memory:
char **list_keys;
list_keys = (char *)malloc((tree_size(tree)+1)*sizeof(char));
Then, I call an auxiliary function tree_get_keys_aux(tree, list_keys, 0) that will do the initial part I mentioned. It is defined as:
void tree_get_keys_aux(struct tree_t *tree, char **list_keys, int index) {
//N
list_keys[index] = (char *)malloc((strlen(tree->entry->key))*sizeof(char)); //allocating memory for each string that I want to add to the list
strcpy(list_keys[index],tree->entry->key); //copying the content
index = index + 1;
//L
if (tree->left_child != NULL) {
tree_get_keys_aux(tree->left_child, list_keys, index);
}
//R
if (tree->right_child != NULL) {
tree_get_keys_aux(tree->right_child, list_keys, index);
}
return;
}
Then, I do the line that's bringing me problems,
list_keys[tree_size(tree)] = NULL;
And lastly,
return list_keys;
Firstly,
list_keys = (char *)malloc((tree_size(tree)+1)*sizeof(char));
is wrong. The elements are char*, so you have to allocate for that or you will cause out-of-range access.
It should be:
list_keys = malloc((tree_size(tree)+1)*sizeof(char*));
or
list_keys = malloc((tree_size(tree)+1)*sizeof(*list_keys));
See also: c - Do I cast the result of malloc? - Stack Overflow
Secondly,
list_keys[index] = (char *)malloc((strlen(tree->entry->key))*sizeof(char)); //allocating memory for each string that I want to add to the list
strcpy(list_keys[index],tree->entry->key); //copying the content
is wrong. You have to allocate one more element for terminating null-character.
It should be:
list_keys[index] = malloc((strlen(tree->entry->key) + 1)*sizeof(char)); //allocating memory for each string that I want to add to the list
strcpy(list_keys[index],tree->entry->key); //copying the content
Thirdly, tree_get_keys_aux is not recoginizing number of elements in left child and data from left child will be overwritten by data from right child.
To avoid this overwriting, you can use tree_size to determint the tree size and advance index according to that.
//L
if (tree->left_child != NULL) {
tree_get_keys_aux(tree->left_child, list_keys, index);
index += tree_size(tree->left_child); // add this
}
//R
if (tree->right_child != NULL) {
tree_get_keys_aux(tree->right_child, list_keys, index);
}
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.
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!
I have a struct which has a char * to act as it's name for finding it. I also have an array of struct declared. I am trying to assign a struct a name, but the problem I am having is the char * is continuing to change values to whatever the last name is set. This is wrecking havoc for the logic of my code. I have tried using malloc(), but that did not change the results.
code:
struct foo {
char* label;
}
typedef struct foo fum;
fum foolist[25];
/*initialize all elements in foo list to be "empty"*/
bool setArray(char* X) {
for(int i =0; i <25;i++) {
if(strncmp("empty", foolist[i].label,5*sizeof(char))==0) {
//tried char* temp = (char*)malloc(32*sizeof(char));
//foolist[i].label = temp; no change.
foolist[i].label = X;
return true;
}
}
return false;
}
I want label to not change with 'X' once the declaration is made, i have tried using malloc(), probably not correctly though.
You can do either:
foolist[i].label = malloc(strlen(X) + 1);
if ( !foolist[i].label ) {
perror("couldn't allocate memory"):
exit(EXIT_FAILURE);
}
strcpy(foolist[i].label, X);
or, if you have strdup() available:
foolist[i].label = strdup(X);
if ( !foolist[i].label ) {
perror("couldn't allocate memory"):
exit(EXIT_FAILURE);
}
I have a static array and in a function I create a new struct in a loop and assign it to each index in an array. In the function I can see the values but in a different function I see junk for the array values. Do I have to use malloc for something like this?
struct file_types
{
char * typename;
char * MIMEtype;
};
static struct file_types *file_type_table; //Table of parameters
static int file_type_table_num=0;
int add_to_filetype_table(char *param, int param_len, char *value, int val_len, char* value2)
{ if ((param == NULL) || (value==NULL) || (value2 == NULL))
return 0;
if ((strcmp(param,"type") != 0) || (strcmp(value,"") == 0) || (strcmp(value2,"") == 0))
return 0;
if (file_type_table==NULL)
file_type_table = emalloc(sizeof(struct file_types));
else
file_type_table = erealloc(file_type_table, (file_type_table_num*sizeof(struct file_types)+ sizeof(struct file_types)));
file_type_table_num += 1;
int index = file_type_table_num -1;
struct file_types new_struct;
new_struct.typename = value;
new_struct.MIMEtype = value2;
file_type_table[index] = new_struct;
return 1;
}
Problem is in accessing the structs here:
char* get_table_value(char * key)
{ logg("In get_table_value");
int i;
char* value;
for (i=0;i<file_type_table_num;i++)
{
if (strcmp(((file_type_table)[i]).typename, key) == 0)
{
return (file_type_table[i]).MIMEtype;
}
}
return value;
}
There are two problems in your code:
Problem 1:
The structure new_struct itself is located on the stack and it gets deallocated once the scope of the function ends, So what your array elements point to beyond the scope of the function is something that doesn't exist, aka garbage.
Solution:
The structure needs to reside on the heap memory to be accessed beyond the scope.
Problem 2:
new_struct.typename = value;
new_struct.MIMEtype = value2;
Creates a shallow copy of the pointers being passed to the function add_to_filetype_table(), From the example it is not clear who owns the pointers being passed to the function & what is their lifetime, If these pointers are deallocated before you call get_table_value() then your global static structure is left with dangling pointers and hence you would get garbage values when you output them.
Solution:
You need to make a Deep copy of the pointers being passed.
Allocate memory to the structure members and then copy(strcpy()) the strings in to allocated memory.