Nav
Nav

Reputation: 13

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.

Upvotes: 1

Views: 332

Answers (4)

guga
guga

Reputation: 724

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...

Upvotes: 0

Timothy Jones
Timothy Jones

Reputation: 22125

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));

Upvotes: 2

Ed Swangren
Ed Swangren

Reputation: 124642

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));
    /* ... */
}

Upvotes: 1

paxdiablo
paxdiablo

Reputation: 881443

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.

Upvotes: 1

Related Questions