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...
Related
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)
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.
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
In this piece of code I'm trying to create a list which contains all the chars form an input file, and my main problem is with the sentence "You can't return a local variable of the function" Iv'e been told which made me very confused. I dynamically allocated a List and return it, can I just define List list without a dynamic allocation and return it? I believe it's wring since all the information would be automatically deleted and I would be left only with the address of the original list I created.
Here's the code for more information:
typedef struct Item {
char tav;
struct Item* next;
} Item;
typedef struct List {
Item* head;
} List;
List* create(char* path) {
FILE* file;
List* list;
Item* trav;
Item* curr;
char c;
file=fopen(path, "r");
if (file==NULL) {
printf("The file's not found");
assert(0);
}
if (fscanf(file, "%c", &c)!=1) {
printf("The file is empty");
assert(0);
}
trav=(Item *)calloc(1, sizeof(Item));
trav->tav=c;
list=(List *)calloc(1, sizeof(List)); /* allocating dynamiclly the list so it won't be lost at the end of the function*/
list->head=trav;
while (fscanf(file, "%c", &c)==1) {
curr=(Item*)calloc(1, sizeof(Item));
curr->tav=c;
trav->next=curr;
trav=curr;
}
trav->next=NULL;
fclose(file);
return list;
}
Am I correct? Is this necessary? can I define List instead a pointer to one a return it?
You cannot return a pointer to variable local to the function. The local variable does not live beyond the scope({,}) of the function.
Returning address of a variable local to a function will give you what is called as an Undefined Behavior.
You can very well return:
a local variable by value or
a pointer pointing to dynamically allocated memory
Prefer the first unless you are really bothered about the memory overhaed due to returning a copy.
can I just define List list without a dynamic allocation and return it?
Yes,
Provided you have:
List create(char* path);
You can't return a local variable of the function
This sentence is completely wrong. For example in this function:
int f(void)
{
int x = 5;
return x;
}
is a perfectly valid function in which you are returning a local variable.
What you should know is that you can't (or better say shouldn't) return the address of a local variable of the function. This is because after the function returns the address points to garbage and is not usable anymore.
In your example, you can very safely define a local List and return it.
Note that you still need to dynamically allocate trav, i.e. you can't take a local variable of type Item and the point list->head to it for the same reason above.
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 :)