The reason this worked (and this is somewhat of a guess) is that when you run your program the OS allocates a page of memory to your program. This is such a small program that the program stack isn't going to take up a whole lot of space, so there is PLENTY of room left on your page of memory (which is probably a few mega bytes). When you call malloc, it's going to retrieve a memory location somewhere in this page (but definitely NOT on the stack--it will be on the heap which is always separate from the stack).
So, you got a "good" memory location and thus can write to it. This is opposed to a "bad" memory location (like if you hadn't initialized the pointer) which means the memory points to somewhere off of your program's page and thus would cause a segfault. There's nothing unsafe about that because your OS doesn't allow your program to write to stuff it's not supposed to...now, you CAN overwrite things like the stack which can cause strange behavior, but this isn't going to happen with malloc. But if you did something like you added to the pointer (or subtracted...depending on the layout), you COULD get into the stack and cause problems.
I am interested to see what would happen if you did something like this:
int *ptr1 = malloc(0);
int *prt2 = malloc(sizeof(int));
*ptr1 = 9;
*ptr2 = 10;
printf("ptr1 is %d and ptr2 is %d\n", *ptr1, *ptr2);
free(ptr1);
free(ptr2);
My suspicion is that ptr1 and ptr2 will point to the same memory location (in the heap) and thus they would both end up being 10 in this case. If you did something like allocated say 1 or 2 bytes the first time, it may or may not do something even weirder.
Edit:
I tried that, it didn't work and here's why: http://linux.die.net/man/3/malloc
"If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be successfully passed to free()."
So, when you put in 0, apparently you are getting a unique pointer value (i.e. a valid one).