C -- Deallocating memory from a calling function - c

My main question is, is my scheme just plain bad practice? Can it be done? Should it be done?
I'm writing a little dinky key-value pair "dictionary" structure just to familiarize my self with C. One of the functions I've written is intended to return an array of strings of all the values associated with a provided key. The function definition:
char** get_values(const struct dict* d, const char* key)
{
// if key does not exist
if(contains_key(d, key) == 0)
{
return NULL;
}
// count the number of times the key occurs in the dict
int count = count_keys(d, key);
// make a return value
char** key_values = alloc_list(count);// definition included below
int curr_count = 0;
// fill return array
for(int pos = 0; pos < DSIZE; pos++)
{// if current key in dict matches requested key...
if(strcmp(d->keys[pos], key) == 0)
{
// add current value to return array
strcpy(key_values[curr_count], d->values[pos]);
curr_count++;
}
}
return key_values;
}
This function allocates the memory for the string array:
static char** alloc_list(int count)
{
// Allocate list of strings
char** slist = (char**)malloc(sizeof(char*) * count);
// if allocation was great success...
if(slist)
{
// ... allocate memory for each string
for(int pos = 0; pos < DSIZE; pos++)
{
slist[pos] = (char*)malloc(DSIZE * sizeof *slist[pos]);
}
}
return slist;
}
Then in main():
add(&dictionary, "a", "a");
add(&dictionary, "a", "aa");
add(&dictionary, "a", "aaa");
char** a_val = get_values(&dictionary, "a"); // TODO: how do I free this!
assert(strcmp(a_val[0], "a") == 0);
assert(strcmp(a_val[1], "aa") == 0);
assert(strcmp(a_val[2], "aaa") == 0); // all these assertions pass
free(*a_val); // with * omitted, execution aborts, with * included, no warnings
// from gcc, yes I am stabbing in the dark here.
a_val = NULL;
I don't believe the last two lines are doing what I hope they are doing, when I print the values of a_val[0-2] in gdb, they are still there.
I realize I could fix this problem by allocating a string array in main(), and then change get_values() to accept the array and then let get_values() do its business, and then free() the allocated array of strings when I am done with it. But before I go ahead and do that, I was just wanted to see if and how one goes about deallocating memory from a calling function. I've read a little bit about it, and all that was said was "it is the programmers responsibility to deallocate memory in the calling function", but the book did not say how for a situation such as this.
Thanks in advance for any help!

In order to properly deallocate a_val you will need first a for-loop to free/deallocate the char arrays allocated previously and then free the double pointer (i.e., a_val). Otherwise you will create a memory leak since the memory pointed by elements/pointers of a_val will be unreferenced/orphaned:
char** a_val = get_values(&dictionary, "a");
...
for(int pos = 0; pos < DSIZE; pos++) {
free(a_val[pos]);
}
free(a_val);
Stating free(*a_val); is equivalent as stating free(a_val[0]). Thus only the first string of a_val is going to be deallocated.

Related

How to return an array of structs properly (in this codewars example)?

I've been stuck on this particular codewars exercise for a while now. Not because the puzzle itself is hard (no, I was able to print the correct results after only a few minutes), but because I can't seem to figure out how to return the result.
I'm supposed to return an array of structs. I know I can't just statically allocate it and then return it. I must dynamically allocate memory and return the pointer. I do this like this (n-m is the max amount of structs I might have to return):
Pair* res = malloc((n-m)*sizeof(Pair));
I then assign values as follows:
res[t].first = i;
res[t].snd = sum;
And then return the array:
return res;
If I print the whole array before returning it, it appears filled. But the codewars system says I returned an empty array?
I was able to fix this by adding an ampersand to return the address. By doing this, it returns the first struct properly (I was able to figure this out by adding manual checks), but the second struct would be rubbish data.
Anyone know what I might be doing wrong?
Here's the full function (removed the calculations because they're irrelevant to the problem, and also might spoil the puzzle for others who stumble upon this question while solving it):
Pair** listSquared(long long m, long long n, int* length) {
Pair* res = malloc((n-m)*sizeof(Pair));
int t = 0;
long long sum = 0;
for(int i = m; i<=n; i++)
{
if(sum = isSumSquare(i))
{
res[t].first = i;
res[t].snd = sum;
t++;
}
}
*length = t;
return res;
}
One more thing: I did notice that the return type is Pair**. I'm guessing this is what I'm doing wrong, but I also tried making the datatype of res Pair** (and then replacing the . with -> when assigning), and/or taking the sizeof(Pair*) instead of just Pair. I tried more combinations than I can count, but still haven't gotten anything that works. I have a feeling I'm missing something fundamental knowledge about pointers here...
Anyone who can tell me what I'm doing wrong?
edit: as requested by Gilles, the exact problem statement: https://i.imgur.com/gFdDJlz.png
As mentioned above, type controls everything. You were given a function prototype with Pair **listSquared (...). The function must return type Pair** (e.g. a pointer-to-pointer to type Pair)
Returning a pointer-to-pointer to dynamically allocated object requires first declaring the object of type Pair** within listSquared and allocating the number of pointers required, e.g.
Pair **res = malloc ((n-m) * sizeof *res);
(note: if you always set your typesize by using the dereferenced pointer, sizeof *res instead of sizeof (Pair*), there is no way you can get it wrong)
Then within your function in the loop where you fill each struct Pair, you first need to allocate a block of memory for each struct and assign the beginning address for that block to your pointer, e.g.
res[t] = malloc (sizeof *res[t]);
In each case, and with EVERY allocation, you need to validate that the allocation succeeded before attempting to make use of the pointers or block of memory. For example:
if (!res) { /* validate EVERY allocation */
perror ("malloc-res");
*length = 0; /* set length zero */
return NULL; /* return NULL indicating failure */
}
and in the case of failure allocating for res[t], you need to free() each previously allocated struct and the pointers before returning to avoid creating a memory leak, e.g.
if(sum = isSumSquare(i))
{ /* allocate for res[t] and validate, free all on failure */
if (!(res[t] = malloc (sizeof *res[t]))) {
perror ("malloc-res[t]");
while (t--) /* free previously allocated structs */
free (res[t]);
free (res); /* free pointers */
*length = 0; /* set length zero */
return NULL; /* return NULL indicating failure */
}
res[t].first = i;
res[t].snd = sum;
t++;
}
Based on my best understanding of what you needed to do, you could put it altogether with something like:
Pair **listSquared (long long m, long long n, int *length)
{
Pair **res = malloc ((n-m) * sizeof *res);
int t = 0;
long long sum = 0;
if (!res) { /* validate EVERY allocation */
perror ("malloc-res");
*length = 0; /* set length zero */
return NULL; /* return NULL indicating failure */
}
for(int i = m; i<=n; i++)
{
if(sum = isSumSquare(i))
{ /* allocate for res[t] and validate, free all on failure */
if (!(res[t] = malloc (sizeof *res[t]))) {
perror ("malloc-res[t]");
while (t--) /* free previously allocated structs */
free (res[t]);
free (res); /* free pointers */
*length = 0; /* set length zero */
return NULL; /* return NULL indicating failure */
}
res[t].first = i;
res[t].snd = sum;
t++;
}
}
*length = t;
return res;
}
In the case of allocation failure your function returns NULL and has freed any memory it had allocated up to the point of failure eliminating all potential memory leaks.
I'm glad you got things working and have submitted your code. If you have any questions about the reasoning above, just drop a comment and I'm happy to help further.

Clear char array in C without any standard library

I'm working on a class project that would require me to make unique strings and I want to concatenate a number to a string. However I do NOT have access to C Standard Library (memset, malloc, etc.). I made this which works:
char* concat(char* name, int num) {
int i, j;
char newName[50], stack[5];
for(i=0; name[i]!='\0'; ++i) {
newName[i] = name[i];
}
for (j=0; num>=1 || num==0; j++) {
stack[j] = (num % 10) + '0';
num = num / 10;
if (num==0) break;
}
while (j>=0) {
newName[i++] = stack[j--];
}
name[0] = '\0';
return newName;
}
But then as I tested it with multiple strings, I realized that newName was being reused over and over. For ex.
This test file outputs the following:
int main() {
char* rebecca = concat("rebecca", 1);
char* bill = concat("bill", 2);
Write(rebecca); /* bill2ca1 */
Write(bill); /* bill2ca1 */
}
It successfully appends the 1 to rebecca, but then when I call concat on bill, it overwrites the first 5 letter but keeps the same chars from before in newName.
QUESTION: How to clear a char array so the next time it's called it will be set to empty, or dynamically allocate it (without using C Standard Library)?
Without using malloc, you can simply put the memory on the stack of the calling function, to keep in the scope where it is needed. It's easier to add the buffer pointer to the argument list like so:
char* concat(char *newName, char* name, int num) {
int i, j;
char stack[5];
:
:
}
int main() {
char rebecca[50];
char bill[50];
concat(rebecca, "rebecca", 1);
concat(bill, "bill", 2);
write(rebecca);
write(bill);
}
Generally speaking, assign memory where it will be used. Embedded programming (which might need to run for months without a reboot) avoids malloc like the plague, just because of the risk of memory leaks. You then need to assign extra space since you may not know the size at compile time, and then ideally check for running past the end of the buffer. Here we know the string sizes and 50 chars is more than enough.
Edit:
The other issue is that you're not null terminating. The print will go until it hits 0x00. Your line
name[0] = '\0';
should be
newName[i] = '\0';
You've got a major issue that you're overlooking. In your function, newName is a local variable (array) and you're returning it from the function. This invokes undefined behavior. The beauty of UB is that, sometime it appears to work as expected.
You need to take a pointer and allocate memory dynamically instead, if you want to return it from your concat() function. Also, in the main(), after using it, you need to free() it.
A better alternative, maybe, if you choose to do so, is
Define the array in the caller.
Pass the array to the function.
Inside the function, memset() the array before you perform any other operation.
One thing to remember, this way, every call to the function will clean the previous result.
EDIT:
If you cannot use memset(), in the main, you can use a for loop like
for (i = 0; i < sizeof(arr)/sizeof(arr[0]); i++)
arr[i] = 0;
to clear the array before passing it on next time.
You're returning the address of a local variable. Since the variable goes out of scope when the function returns, this invokes undefined behavior.
You function should dynamically allocate memory for the result of the concatenation, then return that buffer. You'll need to be sure to free that buffer later to prevent a memory leak:
char* concat(char* name, int num) {
int i, j;
char *newName, stack[5];
// allocate enough space for the existing string and digits for a 64-bit number
newName = malloc(strlen(name) + 30);
for(i=0; name[i]!='\0'; ++i) {
newName[i] = name[i];
}
for (j=0; num>=1 || num==0; j++) {
stack[j] = (num % 10) + '0';
num = num / 10;
if (num==0) break;
}
while (j>=0) {
newName[i++] = stack[j--];
}
newName[i] = '\0';
return newName;
}
int main() {
char* rebecca = concat("rebecca", 1);
char* bill = concat("bill", 2);
Write(rebecca);
Write(bill);
free(rebecca);
free(bill);
}

Memory Leaks in C

So I'm very new to C, and I'm writing a matrix compression function for a trivial Bitmap Image recognition program. I have the following code, and Valgrind in telling me I have memory leaks at the following marked lines, although I have no idea what's causing it. Any advice would be appreciated.
/* Returns a NULL-terminated list of Row structs, each containing a NULL-terminated list of Elem structs.
* See sparsify.h for descriptions of the Row/Elem structs.
* Each Elem corresponds to an entry in dense_matrix whose value is not 255 (white).
* This function can return NULL if the dense_matrix is entirely white.
*/
Row *dense_to_sparse(unsigned char *dense_matrix, int width, int height) {
Row *result = NULL;
_Bool first_row;
for (int row = height - 1; row >= 0; row--) {
first_row = 0;
for (int elem = width - 1; elem >= 0; elem--) {
unsigned char curr_item = dense_matrix[(row*width) + elem];
if (curr_item!= 255) {
if (!first_row) {
(Memory Leak) Row *curr_row = (Row *) malloc(sizeof(Row));
if (curr_row == NULL) {
allocation_failed();
}
curr_row->next = result;
curr_row->y = row;
curr_row->elems = NULL;
result = curr_row;
//free(curr_row);
first_row = 1;
}
(Memory Leak) Elem *curr_elem = (Elem *) malloc(sizeof(Elem));
if (curr_elem == NULL) {
allocation_failed();
}
curr_elem->value = curr_item;
curr_elem->x = elem;
curr_elem->next = result->elems;
result->elems = curr_elem;
//free(curr_elem);
}
}
}
return result;
}
I believe it may be a problem with freeing curr_row and curr_elem, although when I try to free them at the end of each loop, it gives me a runtime error:
parsify(73897,0x7fff75584310) malloc: * error for object 0x7fbf81403a48: incorrect checksum for freed object - object was probably modified after being freed.
You need to call free on every pointer that you get from malloc. C doesn't automatically free up memory that you allocate, so you need to tell it "I'm done." Free is how you do this.
EDIT: You should also probably call free at the very end of the function, after you know you're done with the memory. If you do it at the end of the loop, you may run into problems with using memory you already freed.
EDIT EDIT: When you free it, note that you have put result in curr_row->next. You're probably accessing this later, post-free, which is a serious problem. You likely want to free all of them at the same time, as clearly you still need the memory (you still have pointers to it).
You cannot free the memory in dense_to_sparse because the whole point of the function is to create and return the newly allocated data structure. Presumably, the code that calls dense_to_sparse wants to use the result.
You will need a separate function to deallocate the memory that you should call once you no longer need it.
void free_sparse_matrix (Row *matrix)
{
Row *row = matrix;
while (row != NULL) {
Row *next_row = row->next;
Elem *elem = row->elems;
while (elem != NULL) {
Elem *next_elem = elem->next;
free (elem);
elem = next_elem;
}
free (row);
row = next_row;
}
}

Return the contiguous block in c

I create an array (char *charheap;) of length 32 bytes in the heap, and initialize all the elements to be \0. Here is my main function:
int main(void) {
char *str1 = alloc_and_print(5, "hello");
char *str2 = alloc_and_print(5, "brian");
}
char *alloc_and_print(int s, const char *cpy) {
char *ncb = char_alloc(s);// allocate the next contiguous block
if (ret == NULL) {
printf("Failed\n");
} else {
strcpy(ncb, cpy);
arr_print();// print the array
}
return ncb;
}
Here is what I implement:
/char_alloc(s): find the FIRST contiguous block of s+1 NULL ('\0')
characters in charheap that does not contain the NULL terminator
of some previously allocated string./
char *char_alloc(int s) {
int len = strlen(charheap);
for (int i = 0; i < len; i++) {
if (charheap[0] == '\0') {
char a = charheap[0];
return &a;
} else if (charheap[i] == '\0') {
char b = charheap[i+1];
return &b;
}
}
return NULL;
}
Expected Output: (\ means \0)
hello\\\\\\\\\\\\\\\\\\\\\\\\\\\
hello\brian\\\\\\\\\\\\\\\\\\\\\
This solution is completely wrong and I just print out two failed. :(
Actually, the char_alloc should return a pointer to the start of contiguous block but I don't know how to implement it properly. Can someone give me a hint or clue ?
Your function is returning a pointer to a local variable, therefore the caller receives a pointer to invalid memory. Just return the pointer into the charheap, which is what you want.
return &charheap[0]; /* was return &a; which is wrong */
return &charheap[i+1]; /* was return &b; which is wrong */
Your for loop uses i < len for the terminating condition, but, since charheap is \0 filled, strlen() will return a size of 0. You want to iterate through the whole charheap, so just use the size of that array (32 in this case).
int len = 32; /* or sizeof(charheap) if it is declared as an array */
The above two fixes should be enough to get your program to behave as you expect (see demonstration).
However, you do not place a check to make sure there is enough room in your heap to accept the allocation check. Your allocation should fail if the distance between the start of the available memory and the end of the charheap is less than or equal to the desired size. You can enforce this easily enough by setting the len to be the last point you are willing to check before you know there will not be enough space.
int len = 32 - s;
Finally, when you try to allocate a third string, your loop will skip over the first allocated string, but will overwrite the second allocated string. Your loop logic needs to change to skip over each allocated string. You first check if the current location in your charheap is free or not. If it is not, you advance your position by the length of the string, plus one more to skip over the '\0' terminator for the string. If the current location is free, you return it. If you are not able to find a free location, you return NULL.
char *char_alloc(int s) {
int i = 0;
int len = 32 - s;
while (i < len) {
if (charheap[i] == '\0') return &charheap[i];
i += strlen(charheap+i) + 1;
}
return NULL;
}

Freeing Object Error

I am mallocing an array of c strings. After releasing it, I get the following error:
Assembler(87536) malloc: *** error for object 0x108500840: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Why is that? I am pretty sure I am doing the malloc correctly. I'm pretty experienced with memory management, but I am not sure why this is giving me an error. The array is should hold three strings, each of which is 2 characters long.
Here is how I am mallocing the array:
char **reg_store;
reg_store = malloc(3 * (sizeof(char*)));
if (reg_store == NULL) {
fprintf(Out, "Out of memory\n");
exit(1);
}
for (int i = 0; i < 3; i++) {
reg_store[i] = malloc(2 * sizeof(char));
if (reg_store[i] == NULL) {
fprintf(Out, "Out of memory\n");
exit(1);
}
}
Here is how I am freeing it:
for (int i = 0; i < 3; i++) {
free(reg_store[i]);
}
free(reg_store);
Here is what I have in between:
// Keeps a reference to which register has been parsed for storage
int count = 0;
char *reg = NULL;
char *inst_ptr // POINTS TO SOME STRING. EXAMPLE: $t2, $t1, $a0
while (1) {
// Parses the string in inst_ptr with dollar, comma and space as a delimiter.
reg = parse_token(inst_ptr, " $,\n", &inst_ptr, NULL);
if (reg == NULL || *reg == '#') {
break;
}
reg_store[count] = reg;
count++;
free(reg);
}
I am printing out reg after I call parse_token and it does print out correctly. I am also printing out reg_store[count] and it does also print out correctly.
Your problem is here:
reg_store[count] = reg;
free(reg);
and later
free(reg_store[i]);
reg is already freed and you free it another time (not talking about the problems with using it later). to fix this replace
reg_store[count] = reg;
with
strcpy(reg_store[count], reg);
or as suggested in the comments, since you know its two charaters, its better to memcpy it:
memcpy(reg_store[count], reg, 2);
I would suggest adding some printfs (or use the debugger) to see the values of all the malloced pointers just after they have been malloced. Then do the same just before they are freed, to make sure they are the same. Perhaps there is some other rogue code elsewhere in the program that is stomping over memory.
Your problem is in the "in between" code, in particular, right here:
reg_store[count] = reg;
count++;
free(reg);
You allocated reg_store[count] with malloc during your set up, then you overwrite the allocated value with reg and then free reg. The result is a memory leak from the original pointers that were in reg_store and a double-free on each element of reg_store when you try to clean everything up.
You need to copy reg into the memory already allocated in reg_store[count] (watching the size of course) or don't allocate any space for the elements of reg_store before the "in between" code at all.
The error was already pointed out so no need to write it again.
I can however point out that i don't like the way you are handling errors.
void freeRegStore(char** reg_store)
{
int i;
if (reg_store != NULL)
{
for (i = 0; i < 3; i++)
free(reg_store[i]);
free(reg_store);
}
}
char** allocRegStore()
{
int i;
char **reg_store;
reg_store = calloc(3 * (sizeof(char*)), 1);
if (reg_store != NULL)
{
for (i = 0; i < 3; i++)
{
reg_store[i] = malloc(2 * sizeof(char));
if (reg_store[i] == NULL)
{
freeRegStore(reg_store);
return NULL;
}
}
}
return reg_store;
}
In this method, the function allocRegStore will return NULL if there was not enough memory without leaving pieces around.
Then you can handle this case in main and not in the allocation function itself.
I disagree with the use of printf and exit inside functions.
int main()
{
char** reg_store = allocRegStore();
if (reg_store == NULL)
{
puts("Out of memory");
return 1;
}
... do your stuff
freeRegStore();
return 0;
}
I can also say that the memory used by this program will never go out of memory :) i would not worry about that.

Resources