tags:

views:

246

answers:

11

I am wondering , what exactly is stored in the memory when we say a particular variable pointer to be NULL. suppose I have a structure, say

typdef struct MEM_LIST MEM_INSTANCE;
struct MEM_LIST
{
      char *start_addr;
      int size;
      MEM_INSTANCE *next;
};
MEM_INSTANCE *front;

front = (MEM_INSTANCE*)malloc(sizeof(MEM_INSTANCE*));

-1) If I make front=NULL. What will be the value which actually gets stored in the different fields of the front, say front->size ,front->start_addr. Is it 0 or something else. I have limited knowledge in this NULL thing.
-2) If I do a free(front); It frees the memory which is pointed out by front. So what exactly free means here, does it make it NULL or make it all 0.
-3) What can be a good strategy to deal with initialization of pointers and freeing them .

Thanks in advance

+2  A: 

It depends on what you mean. A null is tradionally means no value.

In C generally null mean 0. Therefore a pointer points to address 0. However if you actually have a a piece of memory then there coulkd be anything the memory from whatever used it last. If you clear the memory to (say) 0's then if you say that that memory contains pointers, those pointers will be null.

You have to think about what a pointer is: Its simply a value that holds an address of some memory. So if the address is 0x1 then this pointer with the value is pointing at the second byte in memory (remember addressing traditionally is 0 for first item, 1 for second etc). So if I char * p = 0x1; is say p points to the memory starting at address 0. Since I have declared it as char *, I've saying that I'm interested in a char sized value in the memory pointed at by 0. So *p is the value in the second byte in memory.

for example: take the following

struct somestruct { char  p } ;

  // this means that I've got somestruct at location null (0x00000)
  somestruct* ptrToSomeStruct = null; 

so the ptrToSomeStruct->p says take the contents of where ptrToSomeStruct points (0x00000) and then what ever is there take tat to be a value of a char, so you are read the the first byte in memory

now if I declare it like so:

// this means that I've got somestruct on the stack and there for it's got some memory behind it.
somestruct ptrToSomeStruct; 

so the ptrToSomeStruct->p says take the contents of where ptrToSomeStruct points (somewhere on the stack) and then what ever is there take that to be a value of a char, so you are read the the some byte from the stack.

Reflecting the comments below: One of the key problems faced by C (and simmilar laguages) programmers is that sometimes a pointer will be pointing to the wrong part of memory, so when you read the value then you gone to the wrong part of memory to start with, hence what you find there is wrong anyway. In lots of cases the wrong address is actually set to 0. This like my examples means go to the start of memory and read stuff there. To help with programming errors where you actually have 0 in a pointer, many operating systems/architectures prevent you from reading or writing that memory and when you do, your program gets a address exception/fault.

Preet Sangha
Can you explain with different cases and scenarios, I understand the use of NULL when we initialize a pointer, so that it does not point anywhere. But suppose we say char *ptr. and if we initialize it to 0,Still 0 is a valid address, so how do we ensure that it points to no where, no confusion is what happens internally when we say NULL
Adi
@Adi, 0 is not still a valid address, and most OSes enforce this (by making the lower portion of memory protected and owned by the kernel, so that only the OS can save data there).
Michael Aaron Safyan
@Adi read my explanation above, why address 0x0 is invalid.
Etamar L.
+3  A: 

NULL assigned to a pointer does not change the "fields pointed by it".

In your case if you make front = NULL, front will no longer point to the structure allocated by your malloc, but will contain zero (NULL is 0 according to the C standard). Nothing will point to your allocated struct - it's a memory leak.

Note the critical distinction here between the pointer (front) and what it points to (the structure) - it's a big difference.

To answer your specific questions:

  1. If you run front=NULL, front will no longer point to a MEM_INSTANCE structure, and hence front->size will have no meaning (it will probably crash the program)
  2. If you do free(front) the OS will free the memory allocated to you for the MEM_INSTANCE structure. front will now point to memory that's no longer yours - and you can't access it
  3. It's a broad question - please ask a more specific one.
Eli Bendersky
Ok..so do you mean , if I do front = NULL, front->size = 0, front->start_addr=0, front->next = 0.. If yes, then front->start_addr = 0 is still a valid address isn't it. It is one of the addresses in the ROM. correct me if I am wrong.
Adi
@Adi: No, if you do `front = NULL` then `front->size` is no longer valid, as `front` doesn't point to a structure, it points *nowhere*.
Eli Bendersky
@Eli: ROM suggests that it's probably an embedded system, not a full POSIX system. 0 might be a valid address. More information is needed. Who knows what might happen at the very beginning of the address space of this system?
Tadeusz A. Kadłubowski
+2  A: 

NULL is a sentinel value that denotes that a pointer does not point to a meaningful location. I.e. "Do not attempt to dereference this".

So what exactly free means here, does it make it NULL or make it all 0.

Neither. It merely frees the memory block that front points to. The value in front remains as it was.

Alex
+1  A: 

Typically, in classic pointers, a null pointer points to address 0x0. It depends on architecture and specific language, but if it is a primitive type then the value 0 would be considered NULL.

In Intel architectures, the beginning of memory (address 0) contains reserved space, which cannot be allocated. It is also outside the boundary of any running application. So a pointer pointing there would quite safely mean NULL as well.

Etamar L.
+2  A: 

In C/C++ NULL == 0.

int* a = NULL; int* b = 0;

The value stored in variables 'a' & 'b' will both be 0. There is no special magic to "NULL". The day this was explained to me, pointers suddenly made sense.

Chris Masterton
A: 

Your question suggests that You don't understand pointers at all.

If you put "front = null" the campiler wil do "front = 0" ans as fron is containst an address of actual structure than You'll loose a pissibility to ferr it.

Read "Kernigham & Ritchie" one again.

lbownik
+2  A: 

The definition of NULL is usually

#define NULL 0
or
#define NULL (void*)0

Assigning it to a pointer merely makes that pointer stop pointing at whatever memory address it was pointing at and now point to memory address 0. This is usually done at initialization or after a pointer's memory has been free-d, though it isn't necessary. Setting a pointer equal to NULL does not deallocate memory or change any values of whatever it used to be pointing to.

Calling free() (in C) or delete (in C++) will deallocate the memory the pointer pointed to, but it will not set the pointer to NULL. Dereferencing the pointer after its been free-d is undefined behavior (ie. crashes normally). Therefore a common idiom is to set a pointer to NULL after it has been deallocated to more easily catch erroneous deferences later on.

cpalmer
+3  A: 

Assignment to a pointer is not the same as assigmment to the elements to which the pointer points. Assigning NULL to front will make it so that front points to nothing, but your allocated memory will be unaffected. It will not write any data into the fields formerly pointed to by front Moreover, that is a memory leak.

Invoking free(front) will deallocate the block of memory but will not affect the value of front; in other words, front will point to a memory region that you no longer own and which is no longer valid for you to access. This is also known as a "dangling pointer", and it is generally a good idea to follow free(front) immediately with front=NULL so that you know that front is no longer valid.

A good strategy for dealing with pointers is, at least in C++, to use smart pointer classes and to perform allocation only in constructors and to perform deallocation only in destructors. Another good strategy is to ensure that you always assign NULL to any pointer that you have just freed. In C, you really just have to make sure that your allocations are matched properly with deallocations. It can also help to use "name_of_object_create" and "name_of_object_destroy" functions that parallel C++ constructors/destructors; however, there is no way in C to ensure automatic destruction.

Michael Aaron Safyan
Assigning NULL to front doesn't make it point to nothing. It makes it point to the address 0, the beginning of the address space. Accessing the memory at address 0 is an error in most situations, but it might work perfectly fine in some low-level situations (OS kernels, embedded systems).
Tadeusz A. Kadłubowski
@Tadeusz, that is exactly right. When I said "points to nothing", I meant it semantically (i.e. we interpret it as pointing to nothing). One can attempt to dereference a null pointer, and the compiler will not catch it. However, that does invoke undefined behavior at runtime (but undefined behavior can be anything... including silently not failing... or failing silently ... or, if we are lucky or are using a sensible UNIX implementation and not programming in kernel space, causing a very loud and obvious failure in the form of a SEGFAULT).
Michael Aaron Safyan
@Tadeusz: Don't confuse possible implementation details what what the C and C++ ISO standard says about null pointers. As far as the language standard is concerned null pointers are just null pointers -- defined to not point to anything -- a high-level concept. The standard doesn't even require the null pointer value to be represented internally with a bunch of zero bytes. So, it's entirely possible to have a pointer like this: `void* foo = 0;` to be represented with bytes 0x42 0x42 ... 0x42, for example.
sellibitze
A: 

Speaking in C:

The preprocesor macro NULL is #defined (by stdio.h or stddef.h), with value 0 (or (void *)0)

-1) If I make front=NULL. What will be the value which actually gets stored in the different fields of the front, say front->size ,front->start_addr. Is it 0 or something else. I have limited knowledge in this NULL thing.

You will have front = 0x0. Doing font->size will raise a SIGSEG.

-2) If I do a free(front); It frees the memory which is pointed out by front. So what exactly free means here, does it make it NULL or make it all 0.

Free will mark the memory once held in front as free, so another malloc/realloc call may use it. Whether it sets your pointer to NULL or leaves its value unchanged its implementation dependant, but surely wont set all the struct to 0.

-3) What can be a good strategy to deal with initialization of pointers and freeing them .

I like to initialize my pointers to NULL and set them to NULL after being deallocated.

mcabral
+1  A: 

Wow, a lot of answers effectively claim that assigning NULL to a pointer sets it to point to the address 0, confusing value and representation. It does not. Setting a pointer to the value NULL or 0 is an abstract conception that sets the pointer to an invalid value not pointing to any valid object. The binary representation actually stored in memory does not need to be all bits 0. This is usually not an architecture thing, it is up to the compiler. In fact I had an old DOS compiler (on x86) that used all bits 1 for a NULL pointer.

Additionally, any pointer type is allowed to have its own binary representation for NULL, as long as all these pointers compare as equal when compared.

Granted, most of the times all bits are 0 for a NULL pointer for practical reasons, but it is not required. This means that using calloc() or memset(0) is not a portable initialization of pointers.

Secure
+2  A: 

There are many good contributed answers which adequately address the questions. However, the coverage of NULL is light.

In a modern virtual memory architecture, NULL points to memory for which any reference (that is, an attempt to read from or write to memory at that address) causes a segfault exception—also called an access violation or memory fault. This is an intentional protective mechanism to detect and deal appropriately with invalid memory accesses:

char  *p = 0;
for (int j = 0;  j < 50000000;  ++j)
        *(p += 1000000) = 10;

This code writes a ten at every millionth memory byte. It won't run for many loops—probably not even once. Either it will attempt to access an unmapped address, or it will attempt to modify read-only memory—where constant data or program code reside. The CPU will interrupt the instruction midway and report the exception to the operating system. Since there's no exception handling specified, the default o/s handling is to terminate the program. Linux displays Segmentation fault (for historical reasons). MS Windows is inconsistent, but tends to say access violation. The same should happen with any program in protected virtual memory doing this:

char *p = NULL;
if (p [34] == 'Y')
        printf ("A miracle has occurred!\n");

This segfaults. A memory location near the NULL address is being dereferenced.

At the risk of confusion, it is possible that a large offset from zero will be valid memory. Thirty-four certainly won't be okay, but 34,000 might be. Different operating systems and different program processing tools (linkers) reserve a fixed amount of the zero end of memory and arrange for it to be unmapped. It could be as little as 1K, though 8K was a popular choice in the 1990s. Systems with ample virtual address space (not memory, but potential memory) might leave an 8M or 16M memory hole. Some modern operating systems randomize the amount of space reserved, as well as randomly varying the locations for the code and data sections each time a program starts.

The other extreme is non-virtual memory architectures. Typically, these provide valid addresses beginning at address zero up to the limit of installed memory. Such is common in embedded processors, many DSPs, and pre-protected mode CPUs, 8 and 16-bit processors like the 8086, 68000, etc. Reading a NULL address does not cause any special CPU reaction—it simply reads whatever is there, which is usually interrupt vectors. Writes to low memory usually result in hard-to-diagnose dire consequences as interrupt vectors are used asynchronously and infrequently.

Even stranger is the segment model of the oddly named "real-mode" x86 using small or medium memory model conventions. Such data addresses are 16 bits using the DS register which is set to the program's initialized data area. Dereferencing NULL accesses the first bytes of this space, but MSDOS programs contain ancient runtime structures for compatibility with CP/M, an o/s Fred Flintstone used. No exceptions, and maybe no consequences for modifying the memory near NULL in this environment. These were challenging bugs to find without program source code.

Virtual memory protection was a huge leap forward in creating stable systems and protecting programmers from themselves. Properly used NULLs provide significant safety and rapid debugging of programming flaws.

wallyk
This is a great explanation. Thanks
Adi
Very good answer and an elaborate response! WTG. +1ed it.
Etamar L.
@wallyk, it is nevertheless, from a C++ standpoint, "undefined behavior" to dereference NULL.
Michael Aaron Safyan
I agree 90%. But unlike typical *undefined behavior*, there is no chance of the operation completing—at least in a virtual memory environment.
wallyk