Is it well-defined to use a pointer pointing to one-past-malloc?
It is well defined if p
is pointing to one past the allocated memory and it is not dereferenced.
n1570 - §6.5.6 (p8):
[...] If the result points one past the last element of the array object, it shall not be used as the operand of a unary *
operator that is evaluated.
Subtracting two pointers are valid only when they point to elements of the same array object or one past the last element of the array object, otherwise it will result in undefined behavior.
(p9):
When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object [...]
The above quotes are well applicable for both dynamically and statically allocated memory.
int a[5];
ptrdiff_t diff = &a[5] - &a[0]; // Well-defined
int *d = malloc(5 * sizeof(*d));
assert(d != NULL, "Memory allocation failed");
diff = &d[5] - &d[0]; // Well-defined
Another reason that this is valid for dynamically allocated memory, as pointed by Jonathan Leffler in a comment is:
§7.22.3 (p1):
The order and contiguity of storage allocated by successive calls to the aligned_alloc
, calloc
, malloc
, and realloc
functions is unspecified. The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement and then used to access such an object or an array of such objects in the space allocated (until the space is explicitly deallocated).
The pointer returned by malloc
in the above snippet is assigned to d
and the memory allocated is an array of 5 int
objects.
new
then it's perfectly fine. – Oldtimenew
is a different beast. It's more than mere memory allocation. Plus, C++ language lawyers would say that just writing to the memory returned by malloc doesn't create an object there, let alone make the memory have an effective type. – Melletaa + 6
for instance. – Melletaint *some_variable = (int *) 0x1234
is perfectly valid, and often used on small embedded system for memory mapped registers. Having a pointer to anywhere is not a problem as long as you don't attempt to do anything with it. It's using the pointer that can lead to UB, if it doesn't point anywhere valid. – Overviewaligned_alloc
,calloc
,malloc
, andrealloc
functions is unspecified. The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement and then used to access such an object or an array of such objects in the space allocated (until the space is explicitly deallocated). It says "an array of such objects"—it's OK for arrays; therefore it's OK here. – Natmalloc
a special case is that the allocated data has no effective type. The type of the allocated data is determined upon access, as specified in 6.5/6. When writingint* ptr = malloc(n*sizeof *ptr); ...ptr[0] = x;
you actually never get an array type, but each chunk of data accessed gets the effective typeint
. Not an array of int, but a whole bunch of individualint
. The C standard doesn't make much sense here. – Dorcyint diff
might be too small for the difference between the first and last element of an array. Andptrdiff_t
as well - if that happens, behaviour is undefined. – Bowerbirdp-a
returns a typeintptr_t
whose range can exceedint
. – Squirmy