This function appends a desired value to the end of the array. When I tested the code, I used the value 100776, but when I printed out the array, the value of the last element was 135009, which is completely different than what my desired value was. Does anybody know why that's the case?
Here is the struct for my append function:
typedef struct {
int* data;
unsigned int len;
} intarr_t;
And this is my actual append function:
intarr_result_t intarr_push( intarr_t* ia, int val )
{
unsigned int len = ia->len;
if (ia == NULL)
{
return INTARR_BADARRAY;
}
else
{
ia->data = realloc(ia->data, (sizeof(int)*len+1));
if (ia->data != 0)
{
ia->data[len+1]=val;
ia->len=len+1;
assert (ia->data);
return INTARR_OK;
}
else
{
return INTARR_BADALLOC;
}
}
return 0;
}
given you have:-
(sizeof(int)*len+1)
then this is off the end of your array :-
ia->data[len+1]=val;
for two reasons :-
you haven't allocated enough memory because the + 1 occurs after the multiplication.
if you allocate 1 then your first spot is data[0] not data[1].
so you should do :-
a->data = realloc(ia->data, (sizeof(int)*(len+1)));
and
ia->data[len]=val;
ia->len++;
and your last item is ia->data[ia->len-1];
Related
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!
Create a function with a static variable that is a pointer (with a default argument of zero). When the caller provides a value for this argument it is used to point at the beginning of an array of int. If you call the function with a zero argument (using the default argument), the function returns the next value in the array, until it sees a “-1” value in the array (to act as an end-of-array (indicator). Exercise this function in main( ).
Here is what I have :
int pr(int *p = 0) {
static int* po =0 ;
if (p) {
po = p;
return *po;
}
else {
return -1;
}
if (*p == -1) {
return -1;
}
return *po++;
}
int ar[] = {2,5,1,2,6,-1};
int main() {
pr(ar);
int pl;
pl = pr();
while (pl != -1) {
cout << pl << endl;
pl = pr();
}
}
When I start it, nothing gets printed and I dont know why. Any help ?
You will need to keep the next array index around, too:
int f(int* a = NULL) {
static int* arr = NULL; // internal state ...
static int idx = 0; // ...in these two vars
// Reset the internal state if a new array is given
if (a != NULL) {
arr = a;
idx = 0;
}
// #1
if (arr == NULL || arr[idx] == -1) { return -1; }
return arr[idx++];
}
I made some assumptions about the parts you didn't specify in your question on the line marked #1. If no pointer has yet been provided, or if the array end has previously been reached, we just return -1 each time.
i have decleard a structure and allocate some memory too . using a function i update datas . i got error segmentation fault when i acssing data.
This is my code
In headerfile :
typedef struct
{
int member;
char *name;
}place;
void update(place **,int);
void display(place **,int);
in function
static memallocate(place **ptr,int viname,int index)
{
ptr[index]=(place *)malloc(sizeof(place));
ptr[index]->name=(char *)malloc(viname*sizeof(char *));
}
void update(place **ptr,int index)
{
---read string value "na" find the strlen as "pp"---
memallocate(ptr,pp,index);
ptr[index]->name=na;
}
void display(place **ptr,int index)
{
int i;
for(i=0;i<index;i++)
{
printf("%s\n",ptr[i]->name);
printf("%s\n",ptr[i]->country);
}
}
in main file :
void main()
{
int index=0;
place *pla[5]={NULL};
while(index<2)
{
update(&pla[index],index);
index++;
}
display(pla,index);
}
my problem is i got segmentation fault when acessing function display and can't print datas ptr[0]->name,ptr[0]->country,ptr[1]->name,ptr[1]->country ..why this happen ? any memory fault . I got printing when i use printf after each updation .
I see two mayor issues here.
1st
Here
static void memallocate(place **ptr,int viname,int index)
{
ptr[index]=(place *)malloc(sizeof(place));
ptr[index]->name=(char *)malloc(viname*sizeof(char *));
}
you allocate too much memory. It shall be
static void memallocate(place ** ptr, int viname, int index)
{
ptr[index] = malloc(sizeof(place));
ptr[index]->name = malloc(viname * sizeof(char));
}
or even better:
static int memallocate(place ** ptr, size_t viname, size_t index)
{
int result = 0;
if (NULL == ptr)
{
result = -1;
errno = EINVAL;
}
else
{
ptr[index] = malloc(sizeof *ptr[index]);
if (NULL == ptr[index])
{
result = -1;
}
else
{
ptr[index]->name = malloc(viname * sizeof *(ptr[index]->name));
if (NULL == ptr[index]->name)
{
result = -1;
free(ptr[index]);
}
}
}
return result;
}
2nd
Then here (assuming na to be a char* properly initilaised to reference a C-"string")
void update(place **ptr,int index)
{
---read string value "na" find the strlen as "pp"---
memallocate(ptr,pp,index);
ptr[index]->name=na;
}
you overwrite what you just assigned to name. To copy a C-"string" use strcpy().
int update(place ** ptr, size_t index)
{
---read string value "na" find the strlen as "pp"---
int result = memallocate(ptr, pp, index)
if (-1 == result)
{
perror("memallocate() failed");
}
else
{
strcpy(ptr[index]->name, na);
}
return result;
}
Then call it like this:
int main(void)
{
size_t index = 0;
place * pla[5] = {NULL};
/* Loop over all array's elements. */
while (index < sizeof pla/sizeof *pla)
{
update(pla, index);
++index;
}
...
}
Notes:
Always check the outcome of relevant function calls (here malloc()) and design your functions to be able to pass failures up to the caller.
Do not cast the result of malloc(), calloc() and realloc() in C. It is not needed nor recommended.
Prefer using size_t over int for memory sizes and indexes. size_t does not waste a bit for negative numbers and it is guaranteed to be large enough to address any arrays' element or represent any memory size. sizeof as well as strlen() return size_t not int for example.
When you call your update(), you are passing a place ** of the current index as argument.
However, you nevertheless pass index too and later in your memallocate() allocate memory as if it was a pointer to the place *[].
So it should help to remove the parameter index from update() and memallocate() and change the memory allocation to something like:
*ptr = (place *)malloc(sizeof(place));
*ptr->name = (char *)malloc(viname*sizeof(char *));
In my binary search tree I want to create a function that can get all words starting with a prefix and store all words in an array called results
this is my tree
struct BinarySearchTree_t
{
char *mot,*def;
struct BinarySearchTree_t *left;
struct BinarySearchTree_t *right;
};
typedef struct BinarySearchTree_t BinarySearchTree;
my function :
size_t findWordsByPrefix(BinarySearchTree* tree, char* prefix, char*** results)
{
BinarySearchTree *tmp;
tmp=tree;
static int size=0;
if (!tmp)
return 0;
else if (strncmp(tmp->mot,prefix,strlen(prefix))==0)
{
(*results)= realloc(*results,(1+size)*sizeof(*(*results)));
(*(*results+size))= malloc(strlen(tmp->mot)*sizeof(char));
strcpy((*results)[size],tmp->mot);
size++;
return (1 + findWordsByPrefix(tmp->left,prefix, &results) + findWordsByPrefix(tmp->right,prefix, &results));
}
else
return (strncmp(tmp->mot,prefix,strlen(prefix))<0)?findWordsByPrefix(tmp->right,prefix, &results):findWordsByPrefix(tmp->left,prefix, &results) ;
}
This function should return a number of words starting with the given prefix.
my problem is that the program crash when it is run , and I don't how to resize my array results
so every time I found a word I should increase the size of the results array .
and I would know how exacly manipulate the pointer of pointer of pointer given in arg of this function (char ***results) : what exactly means?
If I simply compile your code, I get severe compiler warnings including:
1>binarysearchtree.c(98) : warning C4047: 'function' : 'char ***' differs in levels of indirection from 'char ****'
1>binarysearchtree.c(98) : warning C4024: 'findWordsByPrefix' : different types for formal and actual parameter 3
This alone will cause a crash -- you are calling your own function recursively with the wrong arguments.
Next, I believe you need to allocate one more than the length of the string, to hold a copy of a string:
malloc((strlen(tmp->mot) + 1 )*sizeof(char))
Next, you're passing around an array of strings of variable size -- and storing the size in a static variable. It's impossible to know if this will work, so don't do it.
Instead, if you want to use a dynamic array of strings, I suggest extracting out a struct to hold them, like so:
struct ResultTable_t
{
int size;
char **results;
};
typedef struct ResultTable_t ResultTable;
void InitializeResults(ResultTable *p_table)
{
p_table->size = 0;
p_table->results = NULL;
}
void AddResult(ResultTable *p_table, char *result)
{
if (result == NULL)
return;
p_table->size++;
p_table->results = realloc(p_table->results, p_table->size * sizeof(*p_table->results));
p_table->results[p_table->size-1] = malloc((strlen(result) + 1) * sizeof(**p_table->results));
strcpy(p_table->results[p_table->size-1], result);
}
void FreeResults(ResultTable *p_table)
{
if (p_table->results != NULL)
{
int i;
for (i = 0; i < p_table->size; i++)
{
free(p_table->results[i]);
}
free(p_table->results);
}
p_table->size = 0;
p_table->results = NULL;
}
(As an improvement, you might consider using geometric growth instead of linear growth for your table of results.)
Then your function becomes:
size_t findWordsByPrefix(BinarySearchTree* tree, char* prefix, ResultTable *p_table)
{
if (!tree)
return 0;
else if (strncmp(tree->mot,prefix,strlen(prefix))==0)
{
AddResult(p_table, tree->mot);
return (1 + findWordsByPrefix(tree->left,prefix, p_table) + findWordsByPrefix(tree->right,prefix, p_table));
}
else if (strncmp(tree->mot,prefix,strlen(prefix))<0)
{
return findWordsByPrefix(tree->right,prefix, p_table);
}
else
{
return findWordsByPrefix(tree->left,prefix, p_table);
}
}
And you would use it like:
ResultTable results;
InitializeResults(&results);
// Get some prefix to search for.
char prefix = GetSomePrefix();
int size = findWordsByPrefix(tree, prefix, &results);
// Do something with the results
// Free all memory of the results
FreeResults(&results);
Update
If the ResultTable is distasteful for some reason, you can pass the dynamic array and array sizes in directly:
void AddResult(char ***p_results, int *p_size, char *word)
{
if (word == NULL)
return;
(*p_size)++;
(*p_results) = realloc(*p_results, ((*p_size)+1) * sizeof(**p_results));
(*p_results)[(*p_size)-1] = malloc((strlen(word) + 1) * sizeof(***p_results));
strcpy((*p_results)[(*p_size)-1], word);
}
void FreeResults(char ***p_results, int *p_size)
{
int i;
if (p_results == NULL || *p_results == NULL)
return;
for (i = 0; i < (*p_size); i++)
{
free ((*p_results)[i]);
}
free (*p_results);
*p_results = NULL;
*p_size = 0;
}
size_t findWordsByPrefix(BinarySearchTree* tree, char* prefix, char ***p_results, int *p_size)
{
if (!tree)
return 0;
else if (strncmp(tree->mot,prefix,strlen(prefix))==0)
{
AddResult(p_results, p_size, tree->mot);
return (1 + findWordsByPrefix(tree->left,prefix, p_results, p_size) + findWordsByPrefix(tree->right,prefix, p_results, p_size));
}
else if (strncmp(tree->mot,prefix,strlen(prefix))<0)
{
return findWordsByPrefix(tree->right,prefix, p_results, p_size);
}
else
{
return findWordsByPrefix(tree->left,prefix, p_results, p_size);
}
}
and use like:
char **results = NULL;
int tablesize = 0;
// Get some prefix to search for.
char prefix = GetSomePrefix();
int size = findWordsByPrefix(tree, prefix, &results, &tablesize);
// Do something with the results
// Free all memory of the results
FreeResults(&results, &tablesize);
The definition of intarr_t:
typedef struct {
int* data;
unsigned int len;
} intarr_t;
First, I need to set a value to a given index of array and return typedef'd status codes accordingly.
My work for setting a value to an array is:
intarr_result_t intarr_set( intarr_t* ia,
unsigned int index,
int val )
{
if(ia == NULL) // if ia is null
{
return INTARR_BADARRAY;
}
unsigned int len = ia->len;
if(index >= 0 && index < len) // if index is valid
{
ia[index].data = &val; // set value at ia[index] to val
return INTARR_OK;
}
else // if index is not valid
{
return INTARR_BADINDEX;
}
}
Second, I need to set a value of an array to a pointer variable.
My work to get a value is:
intarr_result_t intarr_get( const intarr_t* ia,
unsigned int index,
int* i )
{
if(ia == NULL)
{
return INTARR_BADARRAY;
}
unsigned int len = ia->len;
if((index >= 0 && index < len) && i != NULL)
{
i = ia[index].data;
return INTARR_OK;
}
else
{
return INTARR_BADINDEX;
}
}
When testing myself, I get a value from what I set, but the automated marker says the values returned, at the same index, from each functions is different to each other. I'm not sure where I did wrong and how I should fix it. Help me out please.
change
ia[index].data = &val;
...
i = ia[index].data;
to
ia->data[index] = val;
...
*i = ia->data[index];
You are storing a pointer to a local variable:
ia[index].data = &val;
int val does not exists outside the function context, hence you should not reference it.
If you want to store a pointer, change your function header:
intarr_result_t intarr_set( intarr_t* ia,
unsigned int index,
int* ptr )
and make sure the object ptr points to still exists when calling intarr_get