void *ptr = mmap( NULL, N, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, 0, 0);
where N is the number of bytes of RAM to ask for from the OS.
Here's one important constraint you must follow: N must be an integer multiple of the system's page size (or if mapping hugepages, an integer multiple of a hugepage's size). Usually it's 4096 bytes, but the actual value is reported by sysconf(PAGESIZE).
When this statement executes, what is ptr pointing to?
The beginning of the portion of the address space this particular mapping has been created at. With a non-anonymous mapping you can map the same memory several times at different addresses (this is a neat trick to implement transparent ringbuffers).
Is it pointing to the start of the shared memory between processes?
At this particular point, it's just pointing to some memory. There's nothing shared about this yet. The mapping however will be shared after a fork (or a clone with the right flags); this already is process shared memory, but you probably will want to also execve into a different executable.
Also, if in this memory space say I want to store 1,000 int pointers, do I need to have N = 1000 * sizeof(int *);?
Well, technically you need to have n * sysconf(PAGESIZE) == N >= 1000 * sizeof(int*); however why do you want to share int pointers? Unless you have those pointers point into (another) shared memory region, that's at the same address in every process that uses those pointers, it's pretty useless to share pointers. Of course after a fork the address space of the processes is identical, but a execve will unmap all previous mappings, and you'd have to use non-anonymous mmap with MAP_FIXED and a filedescriptor obtained with, e.g., memfd_create, and use the first parameter of mmap where exactly to map it at (which might fail, or overmap a previously existing mapping).
What you can sensibly share is offsets and bulk data.
Oh, and just to eliminate any confusion: Placing a pointer in a shared memory region will not automagically share the memory it's pointing to.
And assuming that I am correct, where is the second place in memory that I can store something? Is it at ptr + 1 or ptr + 4 because an int * is 4 bytes on a 32-bit system?
It's just plain memory, that you can use, as if it were allocated with malloc. Cast the pointer to whatever type you see fit and use it as usual.
((int*) ptr)[1](which is equivalent to*(((int*) ptr) + 1))mmap()a standard io stream? I'd recommendmmap(NULL, N, flags, flags, -1, 0), personally.MAP_ANONYMOUSeffectively impliesfd = -1, but for portability you shouldn't writefd = 0. When in doubt, read the manpage.