Topic: memset() preprocessor macro

I'm bored waiting for my ports to upgrade so I'm experimenting with memset but I can't get it to set my pointers to null.  The code is below:

#include <stdio.h>
#include <string.h>

#define memzero(s, n) memset((s), 0, (n))

main()
{
    int * ptr;
    memzero(ptr, sizeof(ptr));

    printf("%p\t%p\n", ptr);
}

Running this program causes a segfault... however it should set the pointer to null and thus dereferencing ought to be a no-op.  Anyways, advice would be helpful.

Re: memset() preprocessor macro

try: memzero(&ptr, sizeof(ptr));

Why? memset(s, c, n) changes the memory pointed to by s, or in your example, by ptr. Since you don't initialize ptr, it points to a somewhat random memory location, which in most cases your program may not access, hence the segfault.

Re: memset() preprocessor macro

OK, well that worked but my question is why? When you declare a pointer it's value is generally some random memory which you often don't have access to (hence the seg fault) but when you call memset with &ptr you're passing the address of the actual pointer variable not the value of the pointer(which is also a memory address).  If you wanted to change the value of ptr wouldn't you call memset with a dereference like so: memset((*ptr), sizeof(ptr))?

Re: memset() preprocessor macro

No, simply doing "*ptr" on an uninitialized pointer leads to a segfault in most cases. So basically, before you play with a pointer's value, initialize it, for example like this:

int SIZE = 10; // just some constant
int* ptr = malloc(SIZE * sizeof(int)); // initialize ptr, now points to a valid memory region
if (ptr == null) { perror("malloc"); exit 1; } // check for malloc failure
memset(ptr, 0, SIZE * sizeof(int)); //now the memory region can be cleared

Re: memset() preprocessor macro

If the pointer is initialized to null first a dereference is a no-op correct?  The following is safe then:

int * ptr;
memset(&ptr, 0, sizeof(ptr));
*ptr;

The idea is to create a macro for setting any pointer to null to prevent dereferencing an uninitialized pointer.  I still don't understand why you need to pass &ptr to memset and not just ptr.  I'm coming from C++ and I'm used to passing pointers by references instead of by pointers-to-pointers.  I assume that memset needs a pointer to a void data type and that's why you have to pass it's address using the & operator.

Re: memset() preprocessor macro

kce wrote:

If the pointer is initialized to null first a dereference is a no-op correct?  The following is safe then:

int * ptr;
memset(&ptr, 0, sizeof(ptr));
*ptr;

No, if ptr is null, then *ptr will cause a null pointer dereference, which will cause a segfault. With just the code above, you won't notice it (at least on my machine it seems to be optimized away), but try the following snippet:

int* ptr = 0;
int a = *ptr;
kce wrote:

The idea is to create a macro for setting any pointer to null to prevent dereferencing an uninitialized pointer.

Why not just use: int* ptr = 0; ?

kce wrote:

I still don't understand why you need to pass &ptr to memset and not just ptr.

Because memset internally works with *ptr.

kce wrote:

I'm coming from C++ and I'm used to passing pointers by references instead of by pointers-to-pointers.  I assume that memset needs a pointer to a void data type and that's why you have to pass it's address using the & operator.

No, it has nothing to do with data types; when it comes to pointers, C is only very weakly typed. The reason behind this behaviour is that C only knows value parameters, not reference parameters, in function calls.

Re: memset() preprocessor macro

Hmm, your snippet does indeed lead to a seg fault.  I was under the impression that dereferencing a null pointer is a no-op and that consequentially it was about the only 'safe' thing you could do with pointers without risking a segfault.  For example, in C++ as long as all my class constructors would at the very least set the pointers to null the destructor could just deallocate them.  If there was memory there it'd be deallocated and if not and the pointer was null it'd be a no-op.  Either this is different in C or as you pointed out it could be entirely implementation dependent (the compiler removes the lines I assume).

The only reason to use a preprocessor macro for memset is for syntactic clarity and to remind myself that if I am defining a pointer I should declare it null.  However if a null pointer deference does indeed segfault there's no reason to do this.

Thanks for your help on this one.  You obviously know your business with code.

Re: memset() preprocessor macro

It is not a no-op; it is a special case.  If the pointer is the null pointer, then memory deallocation functions are specified to not attempt to deallocate the memory.  Whether this is actually a good thing is another question...