Cannot figure out how to free my structure - c

I need to free() all the memory allocated for my structure config.
struct keysnvalues {
char* key;
char* value;
};
struct section {
char *name;
struct keysnvalues *keysnvalues;
int keysnvalues_ammount;
};
struct config {
struct section *sections;
int section_ammount;
};
In the beggining of the code I do this
struct section * sect = malloc(sizeof(struct section) * 255);
struct keysnvalues * keysnvalue = malloc(sizeof(struct keysnvalues) * 255);
If I want to add section I do this for the first one
sect[++num_section].name = buffer; // buffer is the name
And for the next sections
sect[num_section].keysnvalues = keysnvalue;
sect[num_section].keysnvalues_ammount = num_keysnvalues;
cfg -> section_ammount++;
//start with new keysnvalue
num_keysnvalues = 0;
keysnvalue = malloc(sizeof(struct keysnvalues) * 255);
sect[++num_section].name = buffer;
sect[num_section].keysnvalues = 0;
If I want to add a key and a value to section I am working with I do this
keysnvalue[num_keysnvalues].key = key;
keysnvalue[num_keysnvalues++].value = value;
The whole code is here: https://pastebin.com/pGztJ9k4
I am aware of the fact that this is probably a stupid question, but I could not figure out how to free the whole structure config for hours now.
I would really appreciate your help.

Generally, you should free() a pointer if and only if it has been allocated through malloc(). To achieve this, you have to make sure not to "loose" any pointer to a malloced memory address, e.g. by assigning malloc several times to the same variable without having copied it's previous value or without having freed the previously assigned memory.
I did not analyse the complete code you referred to.
But it seems as if you copy the value of keysnvalue to the current section before mallocing a new value for sect[i].keysnvalues.
Hence, it seems that each section get's its own keysnvalue, and you can loop it through:
for (int i=0;i< num_section;i++) {
if (sect[i].keysnvalues != NULL) {
free(sect[i].keysnvalues);
// free(sect[i].name); // if buffer has also been malloced
}
}
free (keysnvalue);
free (sect);
It may be that you also have to loop trough each sect[i].keysnvalue in order to eventually free key/value.
Make sure that section members that you are going to free at the end of the program are always initialised either with NULL or a malloced value in order to prevent your code from "freeing" a garbage pointer value.

When you reset 'keysnvalue' with the next 'malloc()', you are overwriting the pointer to the previous value of 'keysnvalue'. That leaves the associated storage unreachable, i.e a 'memory leak' [unless you maintain a copy of the previous value of 'keysnvalue' in another location]. If you are really replacing the structure with a fresh one, you must 'free()' the old one first, AND THEN 'malloc()' the next one - you cannot wait until the end to clean up everything.
Personally I wouldn't do it that way - for a fresh structure, I would call 'memset()' to zero out the existing structure.

Related

double linked list in c send data from function

This is my code:-
typedef struct Frame
{
char* name;
unsigned int duration;
char* path; // may need to scan (with fgets)
}frame_t;
typedef struct Link
{
frame_t* frame;
struct Link* next;
}link_t;
void addNewFrame(void)
{
link_t* newLink = (link_t**)malloc(sizeof(link_t*));
printf(" *** Creating new frame ***\n\n");
printf("Please insert frame path:\n");
// newLink->frame->name = (char*)malloc(sizeof(char) * MAX_LEN);
fgets(newLink->frame->name, MAX_LEN,stdin);
printf("%s", newLink->frame->name);
}
I just need to add a data to name variable in the "Frame" link list, please help me by reviewing this code.
You want to allocate the right types here:-
link_t* newLink = malloc(sizeof(link_t)); //Pointer to Link st
if(newLink){
newLink->frame = malloc(sizeof(frame_t)); //Pointer to frame member
if(newLink->frame){
newLink->frame->name = malloc(sizeof(char) * MAX_LEN); //Pointer to name member
if(newLink->frame->name){
//Rest of your code
}
}
}
EDIT:-
1. As pointed out in comments there's no need to cast the pointer returned by malloc()
2. Another very imp point you may want to check validity of the pointers before de-referencing them
First. You don't need to cast void * so (link_t **)malloc(... can be only malloc(....
Second. You allocated enough memory for a pointer not for a struct. I think you mean malloc(sizeof(link_t)) or even better malloc(sizeof(*newLink))
Third newLink->frame is a pointer so you need to allocate data for it too, newLink->frame = malloc(sizeof(frame_t))
Fourth newLink->frame->name is still a pointer so you need to allocate data for it too. newLink->frame->name = malloc(MAX_LEN)
The confusion that you are doing is pretty common. When you say type *something you are allocating a pointer to type in the stack. A pointer needs to point to somewhere else or NULL, or bad things happen. This applies to structures too. If your structure has a pointer member you need to point it to somewhere else. The somewhere else is where the real "type" object resides.
This also applies to arrays. If you say 'int foo[10]' you are allocating ten integers in the stack. If you say int *foo[10] you are allocating ten pointers in the stack. If you say int **foo you are allocating one pointer in the stack. Again all pointers need to be initialized, I mean, they need to point to some valid object, allocated somewhere else in the memory.
I hope this helps.
Some other points.
Always check pointer coming from malloc, if allocation failed you'll receive NULL. Dereferencing NULL will break your program.
Always initialize memory coming from malloc, fill it with zeros or something.
Don't use _t suffix, is POSIX reserved.
I didn't test any of this.

allocating memory to a struct using malloc

I have a struct called State:
typedef struct State{
char alphabets[2][6];
struct State *PREV; /*this points to the previous state it came from*/
struct State *NEXT; /*this points to the next state in the linked list*/
int cost; /*Number of moves done to get to this position*/
int zero_index;/*this holds the index to the empty postion*/
} State;
Here's my memAllocator() method:
memAllocator(){
struct State *p = (State*) malloc(sizeof(State));
if (p==NULL){
printf("Malloc for a new position failed");
exit(1);
}
return p;
}
Here's my main method.
main(){
State *start_state_pointer=memAllocator();
State start_state;
start_state.zero_index=15;
start_state.PREV = NULL;
start_state.alphabets[0][0]='C';
start_state.alphabets[0][1]='A';
start_state.alphabets[0][2]='N';
start_state.alphabets[0][3]='A';
start_state.alphabets[0][4]='M';
start_state.alphabets[0][5]='A';
start_state.alphabets[1][0]='P';
start_state.alphabets[1][1]='A';
start_state.alphabets[1][2]='N';
start_state.alphabets[1][3]='A';
start_state.alphabets[1][4]='L';
start_state.alphabets[1][5]='_';
start_state_pointer=&(start_state);
/*start_state=*start_state_pointer;*/
}
I think the statement start_state_pointer=&(start_state); is just assigning the pointer start_state_pointer to to the small amount of temporary space created during State start_state, rather than to the space I allocated.
But when I try the commented out statement start_state=*start_state_pointer to deference the pointer and allocate the space to start state. It gives me a segmentation fault.
I am just starting out in C. Can some one help me with this?
Your memAllocator and main functions don't have explicit return types. This style of code has been deprecated for over 10 years. Functions in C should always have a return type. For main, the return type should be int, and for your memAllocator function, it should be State *.
The second issue is that you allocate space for a State struct, but then fill a different State struct and overwrite the pointer to the previously allocated State struct using start_state_pointer = &(start_state);.
To use the memory that you just allocated, you want to use something like this:
State *start_state = memAllocator();
start_state->zero_index = 15;
start_state->PREV = NULL;
start_state->alphabets[0][0] = 'C';
// etc.
There is no need to create two State structs. When you use State start_start; in your original code, you are creating a struct with something called automatic storage. This means the space for this struct is allocated automatically and is deallocated automatically for you at the end of the scope it is declared in. If you take the address of this struct and pass it around other parts of your program, then you will be passing around a pointer to a deallocated struct, and this could be why your program is crashing.

C generic linked-list

I have a generic linked-list that holds data of type void* I am trying to populate my list with type struct employee, eventually I would like to destruct the object struct employee as well.
Consider this generic linked-list header file (i have tested it with type char*):
struct accListNode //the nodes of a linked-list for any data type
{
void *data; //generic pointer to any data type
struct accListNode *next; //the next node in the list
};
struct accList //a linked-list consisting of accListNodes
{
struct accListNode *head;
struct accListNode *tail;
int size;
};
void accList_allocate(struct accList *theList); //allocate the accList and set to NULL
void appendToEnd(void *data, struct accList *theList); //append data to the end of the accList
void removeData(void *data, struct accList *theList); //removes data from accList
--------------------------------------------------------------------------------------
Consider the employee structure
struct employee
{
char name[20];
float wageRate;
}
Now consider this sample testcase that will be called from main():
void test2()
{
struct accList secondList;
struct employee *emp = Malloc(sizeof(struct employee));
emp->name = "Dan";
emp->wageRate =.5;
struct employee *emp2 = Malloc(sizeof(struct employee));
emp2->name = "Stan";
emp2->wageRate = .3;
accList_allocate(&secondList);
appendToEnd(emp, &secondList);
appendToEnd(emp2, &secondList);
printf("Employee: %s\n", ((struct employee*)secondList.head->data)->name); //cast to type struct employee
printf("Employee2: %s\n", ((struct employee*)secondList.tail->data)->name);
}
Why does the answer that I posted below solve my problem? I believe it has something to do with pointers and memory allocation. The function Malloc() that i use is a custom malloc that checks for NULL being returned.
Here is a link to my entire generic linked list implementation: https://codereview.stackexchange.com/questions/13007/c-linked-list-implementation
The problem is this accList_allocate() and your use of it.
struct accList secondList;
accList_allocate(&secondList);
In the original test2() secondList is memory on the stack. &secondList is a pointer to that memory. When you call accList_allocate() a copy of the pointer is passed in pointing at the stack memory. Malloc() then returns a chunk of memory and assigns it to the copy of the pointer, not the original secondList.
Coming back out, secondList is still pointing at uninitialised memory on the stack so the call to appendToEnd() fails.
The same happens with the answer except secondList just happens to be free of junk. Possibly by chance, possibly by design of the compiler. Either way it is not something you should rely on.
Either:
struct accList *secondList = NULL;
accList_allocate(&secondList);
And change accList_allocate()
accList_allocate(struct accList **theList) {
*theList = Malloc(sizeof(struct accList));
(*theList)->head = NULL;
(*theList)->tail = NULL;
(*theList)->size = 0;
}
OR
struct accList secondList;
accList_initialise(secondList);
With accList_allocate() changed to accList_initialise() because it does not allocate
accList_initialise(struct accList *theList) {
theList->head = NULL;
theList->tail = NULL;
theList->size = 0;
}
I think that your problem is this:
You've allocated secondList on the stack in your original test2 function.
The stack memory is probably dirty, so secondList requires initialization
Your accList_allocate function takes a pointer to the list, but then overwrites it with the Malloc call. This means that the pointer you passed in is never initialized.
When test2 tries to run, it hits a bad pointer (because the memory isn't initialized).
The reason that it works when you allocate it in main is that your C compiler probably zeros the stack when the program starts. When main allocates a variable on the stack, that allocation is persistent (until the program ends), so secondList is actually, and accidentally, properly initialized when you allocate it in main.
Your current accList_allocate doesn't actually initialize the pointer that's been passed in, and the rest of your code will never see the pointer that it allocates with Malloc. To solve your problem, I would create a new function: accList_initialize whose only job is to initialize the list:
void accList_initialize(struct accList* theList)
{
// NO malloc
theList->head = NULL;
theList->tail = NULL;
theList->size = 0;
}
Use this, instead of accList_allocate in your original test2 function. If you really want to allocate the list on the heap, then you should do so (and not mix it with a struct allocated on the stack). Have accList_allocate return a pointer to the allocated structure:
struct accList* accList_allocate(void)
{
struct accList* theList = Malloc( sizeof(struct accList) );
accList_initialize(theList);
return theList;
}
Two things I see wrong here based on the original code, in the above question,
What you've seen is undefined behaviour and arose from that is the bus error message as you were assigning a string literal to the variable, when in fact you should have been using the strcpy function, you've edited your original code accordinly so.. something to keep in mind in the future :)
The usage of the word Malloc is going to cause confusion, especially in peer-review, the reviewers are going to have a brain fart and say "whoa, what's this, should that not be malloc?" and very likely raise it up. (Basically, do not call custom functions that have similar sounding names as the C standard library functions)
You're not checking for the NULL, what if your souped up version of Malloc failed then emp is going to be NULL! Always check it no matter how trivial or your thinking is "Ah sher the platform has heaps of memory on it, 4GB RAM no problem, will not bother to check for NULL"
Have a look at this question posted elsewhere to explain what is a bus error.
Edit: Using linked list structures, in how the parameters in the function is called is crucial to the understanding of it. Notice the usage of &, meaning take the address of the variable that points to the linked list structure, and passing it by reference, not passing by value which is a copy of the variable. This same rule applies to usage of pointers also in general :)
You've got the parameters slightly out of place in the first code in your question, if you were using double-pointers in the parameter list then yes, using &secondList would have worked.
It may depend on how your Employee structure is designed, but you should note that
strcpy(emp->name, "Dan");
and
emp->name = "Dan";
function differently. In particular, the latter is a likely source of bus errors because you generally cannot write to string literals in this way. Especially if your code has something like
name = "NONE"
or the like.
EDIT: Okay, so with the design of the employee struct, the problem is this:
You can't assign to arrays. The C Standard includes a list of modifiable lvalues and arrays are not one of them.
char name[20];
name = "JAMES" //illegal
strcpy is fine - it just goes to the memory address dereferenced by name[0] and copies "JAMES\0" into the memory there, one byte at a time.

Null pointer not staying Null in C

So my problem right now is that for some reason, I designate a pointer as NULL in the first function to be called, but then when I check it later, it's not NULL anymore.
So I have a few structs, detailed here:
#include <stdio.h>
typedef struct filenode {
struct filenode *next, *prev;
const char *name;
} Filenode;
typedef struct foldernode {
struct foldernode *next, *root, *subdir, *prev;
Filenode *filenodes;
const char *name;
} Folders;
typedef struct Filesystem {
Folders *current;
} Filesystem;
And then I go to my actual file, where I initialize the Filesystem.
This is the initialization function:
void mkfs(Filesystem *files) {
/* Initializes space for the filesystem itself */
files = malloc(sizeof(*files));
if(files == NULL) {
printf("Memory allocation failed!\n");
return;
}
/* Initializes space for the first root node */
files->current = malloc(sizeof(files->current));
if(files->current == NULL) {
printf("Memory allocation failed!\n");
return;
}
files->current->filenodes = NULL;
}
Now, when I go into the next function, mkdir, and I check if files->current->filenodes = NULL, and it is not NULL anymore. I'm extremely confused right now. And yes, the same *files variable is being passed in to every function.
From the comments, you say you can't change the signature of mkfs(). I'm going to assume it's called like this:
Filesystem files;
mkfs(&files);
If that's the case, you don't need to create space for the structure (since it's created on the stack just before your mkfs() call), so you can remove this line:
files = malloc(sizeof(*files));
Removing this line will fix the problem that you can't see the changes to files after the function has returned. This was causing you trouble since C is always pass by value - the malloc was changing the value of the local copy of the files pointer, meaning that no further changes were seen outside your function.
You will also run into trouble with this line:
files->current = malloc(sizeof(files->current));
Since files->current is a pointer to a struct foldernode, the sizeof call only tells you the size of the pointer. You probably meant:
files->current = malloc(sizeof(struct foldernode));
or:
files->current = malloc(sizeof(Folders));
And yes, the same "*files" variable is being passed in to every function.
as a copy of the real variable which won't be reflected back to the caller.
Your mkfs is broken. It assigns the result of malloc to the local copy of files, which is then tossed away on exit.
You will need something like:
void mkfs(Filesystem **pFiles) {
/* Initializes space for the filesystem itself */
*pFiles = malloc(sizeof(FileSystem));
if(*pfiles == NULL) {
printf("Memory allocation failed!\n");
return;
}
/* Initializes space for the first root node */
(*pFiles)->current = malloc(sizeof((*pfiles)->current));
if((*pFiles)->current == NULL) {
printf("Memory allocation failed!\n");
free (*pFiles); // <-- to avoid memory leaks
return;
}
(*pFiles)->current->filenodes = NULL;
}
and to call it with:
FileSystem *files;
mkfs (&files);
By passing in a pointer to the pointer, you can reflect any changes back to the original. This scheme should be used for any variable you want to change in a function and have reflected back.
Now you may think you're already doing that because you're passing in a pointer but, when it's the actual pointer that you want to change, you need the double-pointer.
You'll also notice that I've added a free call to free the first allocation if the second fails. That's needed to avoid memory leaks.
void mkfs(Filesystem *files)
Here the pointer files is passed by copy. This is not the pointer you declared and passed to the function, but instead a copy of that pointer which points to the same memory location. The pointers themselves reside in different memory locations.
files = malloc(sizeof(*files));
Here you assign a new value to the pointer files. However, this is again just a copy of the original pointer. So you give the copy a new value, but the original pointer remains unchanged.
If you need to assign a new value to the argument itself (not simply mutate what it points to, but actually assign a new value to it) then you need to pass a pointer to pointer.
void mkfs(Filesystem **files) {
/* Initializes space for the filesystem itself */
*files = malloc(sizeof(Filesystem));
/* ... */
}
Just to correct the answers below/above - Instead of doing
Type *pType;
pType = (Type *) malloc (sizeof (pType)); // <- the size allocated is for a pointer
What you want to do is
Type *pType;
pType = (Type *) malloc (sizeof (*pType)); // <- now allocates space for Type!
This is a common mistake...

Basic Malloc/Free

If I have a snippit of my program like this:
struct Node *node;
while(...){
node = malloc(100);
//do stuff with node
}
This means that every time I loop through the while loop I newly allocate 100 bytes that is pointed to by the node pointer right?
If this is true, then how do I free up all the memory that I have made with all the loops if I only have a pointer left pointing to the last malloc that happened?
Thanks!
Please allocate exactly the size you need: malloc(sizeof *node); -- if you move to a 64-bit platform that doubles the size of all your members, your old 96-byte structure might take 192 bytes in the new environment.
If you don't have any pointers to any of the struct Nodes you have created, then I don't think you should be allocating them with malloc(3) in the first place. malloc(3) is best if your application requires the data to persist outside the calling scope of the current function. I expect that you could re-write your function like this:
struct Node node;
while(...){
//do stuff with node
}
or
while(...){
struct Node node;
//do stuff with node
}
depending if you want access to the last node (the first version) or not (the second version).
Of course, if you actually need those structures outside this piece of code, then you need to store references to them somewhere. Add them to a global list keeping track of struct Node objects, or add each one to the next pointer of the previous struct Node, or add each one to a corresponding struct User that refers to them, whatever is best for your application.
If you set node = NULL before the loop and then use free(node) before node = malloc(100) you should be OK. You will also need to do a free(node) after the loop exits. But then again, it all depends on what "//do stuff with node" actually does. As others have pointed out, malloc(100) is not a good idea. What I would use is malloc(sizeof(*node)). That way, if the type of node changes, you don't have to change the malloc line.
If you don't need the malloc'ed space at the end of one iteration anymore, you should free it right away.
To keep track of the allocated nodes you could save them in a dynamically growing list:
#include <stdlib.h>
int main() {
int i;
void *node;
int prt_len = 0;
void **ptrs = NULL;
for (i = 0; i < 10; i++) {
node = malloc(100);
ptrs = realloc(ptrs, sizeof(void*) * ++prt_len);
ptrs[prt_len-1] = node;
/* code */
}
for (i = 0; i < prt_len; i++) {
free(ptrs[i]);
}
free(ptrs);
return 0;
}
Note: You should probably re-think your algorithm if you need to employ such methods!
Otherwise see sarnold's answer.
then how do I free up all the memory that I have made with all the loops if I only have a pointer left pointing to the last malloc that happened?
You can't. You just created a giant memory leak.
You have to keep track of every chunk of memory you malloc() and free() it when you're done using it.
You can not. You need to store all the pointer to free the memory. if you are saving those pointer somewhere then only you can free the memory.

Resources