i have c function in my project which creates a struct and returns the pointer.
typedef struct object
{
float var1;
float var2;
}
Object;
Object *createObject(float newVar1, float newVar2)
{
Object *object; //create new structure
object = (Object*)malloc(sizeof(Object)); //malloc size for struct object
if(object != NULL) //is memory is malloc'd
{
object->var1 = newVar1; //set the data for var1
object->var2 = newVar2; //set the data for var2
return object; //return the pointer to the struct
}
return NULL; //if malloc fails, return NULL
}
now the struct gets used and after a while i want to delete this structure, i made this function:
void deleteMarnix(Object *objectPointer)
{
free(objectPointer); //free the memory the pointer is pointing to
objectPointer = NULL; //stop it from becomming a dangling pointer
}
this last code snippet shows how i make an object, use it and try to delete it, however, it seems that it doesn't completely free the memory. what am i doing wrong?
Object *object = createObject(21.0f, 1.87f);
//do things here with object.
deleteMarnix(object);
From the snippets you posted, there's no leak.
I think that with:
it seems that it doesn't completely free the memory
you mean that object still holds the old value.
In deleteMarnix, when you set objectPointer to NULL, you only set the value of the pointer in that function scope.
It doesn't set the value of the actual pointer object in the outer function.
To do that you can either:
set it to NULL in the outer function
Object *object = createObject(21.0f, 1.87f);
deleteMarnix( object );
object = NULL;
pass a pointer to a pointer to your deleteMarnix function:
void deleteMarnix(Object **objectPointer)
{
free(*objectPointer); //free the memory the pointer is pointing to
*objectPointer = NULL; //stop it from becomming a dangling pointer
}
...
Object *object = createObject(21.0f, 1.87f);
deleteMarnix( &object );
What free() does is not free the memory held by the pointer completely, but actually makes it available for later use if we call a malloc after calling free().
An evidence to this is you will be able to access the memory location after calling free and before setting the pointer to NULL ( assuming you haven't already called malloc() ). Of course the values will be reset to some default values. ( On some compilers i found int was set to 0 ).
Although there is no memory leak, this might answer your question.
Let us know :)
Related
This code is taken from: page 20-21 of this lecture notes pdf from ocw.
struct node∗ nalloc ( int data )
{
struct node∗ p=( struct node ∗) malloc ( sizeof (node )) ;
if ( p!=NULL) {
p−>data=data ;
p−>next=NULL;
}
return p;
}
struct node∗ addfront ( struct node∗ head , int data )
{
struct node∗ p= nalloc (data );
if ( p==NULL) return head ;
p−>next=head;
return p;
}
I think the code is wrong because the pointer p is local to nalloc() and using it in addfront() would yield undefined behavior. I have seen the answer to this question and believe I am correct but can someone verify?
The function is right. But your logic is not so wrong. The variable p is effectively local and won't exist anymore when the function will return. However, p is not the memory you allocated with malloc, but a variable storing the address of the memory you allocated.
Thus, the statement return p; will return a copy of p, so a copy of the address of the memory you allocated using malloc().
In the linked question, the user creates a local array and returns a pointer to it. See, the array is local and now dynamically allocated using new or malloc(). So his variable effectively contains the (automatically) allocated memory, and not the address of it. However, only the address is returned so the memory is lost.
You are not correct. While p is a local variable on stack, what it points to isn't. What is happening is a pointer to a node on the heap is returned from nalloc and a copy of that pointer is used safely in addfront. The code is fine.
Consider you have a function and the function output will be the Head and Tail address of a Linked List (a function for copy a Linked List in another address):
struct path *copyPath(struct path *head) {
struct path *temp = malloc(sizeof (struct path));
// array of newHead and newTail
struct path *resultPath[2];
struct path *newHead = NULL;
struct path *newTail = NULL;
while (head != NULL) {
temp = malloc(sizeof (struct path));
if (newHead == NULL) {
// Add a new node to the first of list and save newHead as the beginning of the list
} else {
// Add the other nodes and save the last node address as newTail
}
head = head -> next;
}
resultPath[0] = newHead;
resultPath[1] = newTail;
return resultPath;
}
I defined an array of struct path and I return it. In the main function an array has been defined:
struct path *newPath;
newPath = copyPath(path_head, nextNode);
When I run it, I do not have anything in newPath and it is empty.
So, what is the best way to return these addresses and why I do not have it in newPath?
Also, when I use:
struct path *newPath[2];
newPath = copyPath(path_head, nextNode);
I have an error: error: assignment to expression with array type
How to can I pass these two values to the main function?
In addition to the comments, your funciton has two primary problems, 1) you leak memory by overwriting the address of the first allocated block of memory; and 2) you attempt to return returnPath which has automatic storage duration declared local to copyPath.
Memory Leak
You leak memory in your function by overwriting the pointer temp before it has been assigned, e.g.
struct path *temp = malloc(sizeof (struct path));
...
while (head != NULL) {
temp = malloc(sizeof (struct path));
By allocating a second time for temp before you have assigned the original pointer to another variable, you lose the original pointer in temp pointing to the first block of memory allocated. That memory can never be freed by your program from that point forward.
Returning Array with Automatic Storage Declared Local to Function
When I run it, I do not have anything in newPath and it is empty.
struct path *resultPath[2]; declares an array-of-pointers to struct path (two of them). Automatic storage for resultPath is declared local to copyPath within it function stack frame. When copyPath returns, all local variables with automatic storage duration are destroyed (function stack frame memory is released for reuse). This is expressly explained by C11 Standard - §6.2.4 Storage durations of objects
1) An object has a storage duration that determines its lifetime. There are four storage durations: static, thread, automatic, and allocated. Allocated storage is described in 7.22.3.
2) The lifetime of an object is the portion of program execution during which storage is guaranteed to be reserved for it. An object exists, has a constant address,33) and retains its last-stored value throughout its lifetime.34) If an object is referred to outside of its lifetime, the behavior is undefined. The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the end of its lifetime.
6) For such an object that does not have a variable length array type, its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way.
(emphasis ours)
So, what is the best way to return these addresses and why I do not have it in newPath?
In order to return resultPath, you need to allocate storage for it dynamically and return a pointer to it. Objects with allocated storage duration extend for the lifetime of the program or until they are freed.
The easiest way to declare and allocate for an object capable of storing two pointers to struct path is to declare an pointer-to-pointer to struct path, (effectively a dynamic array of pointers), and allocate storage for two pointers, e.g.
/* allocate & validate 2 pointers to struct path */
struct path **resultPath = malloc (sizeof *resultPath * 2);
if (!resultPath) { /* always validate all memory allocations */
perror ("malloc resultPath failed.");
return NULL;
}
...
resultPath[0] = newHead; /* newHead & newTail must point to allocated memory */
resultPath[1] = newTail;
return resultPath;
You can now safely return resultPath and storage for resultPath will survive the return eliminating your access of memory that is no longer available. You then access newHead and newTail through newPath[0] and newPath[1], respectively, in the caller.
You will also need to change the return type for copyPath to stuct path **, e.g.
struct path **copyPath(struct path *head)
and update the type in the caller.
Whenever you allocate a dynamic memory(using malloc, calloc, realloc), appropriately typecast the return address to the proper data type. Because these functions return void pointer. In the below line you are assigning the void pointer type address to the struct path type pointer.
temp = malloc(sizeof (struct path));
It can be written as:
temp = (struct path *)malloc(sizeof (struct path));
Second thing, you are returning a array of pointer of type "struct path", but you are collecting this return array of pointer value in a regular pointer of type "struct path" in main which is against the C standard. Correct this mistakes and try to run the code.
In Main use array of pointer to collect the return value:
struct path *newPath[2];
newPath = copyPath(path_head, nextNode)
struct Temp {};
struct Temp *newTemp() {
struct Temp *temp = malloc(sizeof(struct Temp));
return temp;
}
int main() {
struct Temp *temp = newTemp(); // any problem?
return 0;
}
Is there any problem with returning an instance of a struct from inside the function (factory method).
Will the pointer will be invalid. I was suggested that if you return a pointer it should point to something on the caller's stack, a global, or something on the heap
C structure must contain at least one member as per standard, but gcc allows it as an extension.
And what you did is legal - you can return pointer to dynamically allocated memory and use it in other function.
Memory allocated by malloc has storage duration (allocated storage duration) beyond the scope on which it is declared. You can use it without any problem.
It's expected that you would free the allocated memory and check the return value of malloc (saves you from dereferencing null in case of failure).
Standard N1570 C11 standard also mentions it under §7.22.3 memory management functions:
....The lifetime of an allocated object extends from the allocation until the deallocation.
You have two ways to return a struct from a function:
return a pointer to a dynamically allocated struct (your example code)
The lifetime of a dynamically allocated object extends until it is de-allocated, so the caller will be able to use it. Simply you must not forget to free it when you no longer need it. Not doing so is called a memory leak. So a fixed version should be:
struct Temp {
int i; // a struct should not be empty...
};
struct Temp *newTemp() {
struct Temp *temp = malloc(sizeof(struct Temp));
return temp;
}
int main() {
struct Temp *temp = newTemp(); // any problem?
// use temp...
free(temp);
return 0;
}
return a temporary object
A struct is a first class object in C, so you can directly assign to it. You can then build a struct in a function and return it (beware: returning a pointer to it would actually return a dangling pointer because lifetime would end when function returns). So an alternate way is:
struct Temp {
int i; // a struct should not be empty...
};
struct Temp newTemp() {
struct Temp temp;
// set values of temp members...
return temp;
}
int main() {
struct Temp temp = newTemp(); // no problem?
// use temp...
return 0;
}
The good news here is that the struct is an automatic object in the caller, so it has not to (and shall not) be free-d. And decent compilers can even elide the copy by having the callee to directly use the caller automatic storage.
malloc allocates memory on heap. Objects allocated on heap has static storage duration. It is valid to return a pointer from a function to an object allocated by malloc.
Note that the empty struct you are using is not standard C. GCC provide this feature as an extension.
In legacy C code I have one pointer basically an array of size equal to one of enumerator and it is static in local scope. But now I have to remove that enumeration and now this static local array is giving error. I can convert that array to normal pointer and then allocate it dynamically but I am not sure how to do that. Below is sample code I have simplified from existing code base.
enum
{
E1,
E2,
EOL
};
void func
{
//static int array[EOL]; //-> that how it was earlier
static int *array = (int*)malloc(sizeof(int)*EOL); //Will this allocated memory only once
//or on every invokation.
free(array);//will it free the memory more than once?
}
Now I can move array pointer to global scope and then allocate it in main and free it in atexit functions but I want to keep changes minimum as I am not sure of impact it will have in shared projects?
Thanks
The malloc will occure only once.
1) You can use a static boolean to let you know if the pointer in the array variable can be free.
2) You can free the pointer then set it to NULL. The next occuration of the free will do nothing.
If you want to keep changes minimal then simply move the enumeration definition inside the function body before this static variable. Or you can use even an unnamed enum with one enumerator for the size of the array.
I do not understand your attempts to substitute the array for a dynamically allocated array.
Moreover at present C allows to use variable length arrays. So your could define the function such a way that it had a parameter that would specify the size of the local (non-static) array.
You can't initialise a static variable with something non const if you are using C.
If you are using C++, then the static pointer will only get a memory pointer allocated to it once.
I just solved the problem by using one function which basically is collects all memory allocated to local static pointers like above and then other functions free them during the end as it is registered using atexit function.
struct node
{
node *next;
void *content;
};
node* head = NULL, tail =NULL;
void addToList(void* ptr)
{
struct node* p = (struct node*)malloc(sizeof(struct node));
p->next = NULL;
p->conent = ptr;
tail->next = p;
tail = p;
return;
}
void freeList()
{
struct node* p = NULL, p1 = NULL;
for(p = head; p != NULL; p = p->next)
{
free(p1);
free(p->content);
p1 = p;
}
head = tail = NULL;
return;
}
/*
*/
void func
{
//static int array[EOL]; //-> that how it was earlier
static int *array = (int*)malloc(sizeof(int)*EOL); //Will this allocated memory only once
addToList(array); //or on every invokation.
free(array);//will it free the memory more than once?
}
As you can see it above code a linked list is created in separate .c file and using .map method head,tail and node will not be exposed to outside world only addToList and freeList will be visible. In every places just after doing a malloc I am calling addToList and then freeList will free up the memory.
Thanks
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...