The C99 standard §7.20.3.4 (realloc) says:
The realloc function deallocates the old object pointed to by ptr and returns a
pointer to a new object that has the size specified by size. The contents of the new
object shall be the same as that of the old object prior to deallocation, up to the lesser of
the new and old sizes. Any bytes in the new object beyond the size of the old object have
indeterminate values.
If ptr is a null pointer, the realloc function behaves like the malloc function for the
specified size. Otherwise, if ptr does not match a pointer earlier returned by the
calloc, malloc, or realloc function, or if the space has been deallocated by a call
to the free or realloc function, the behavior is undefined. If memory for the new
object cannot be allocated, the old object is not deallocated and its value is unchanged.
Returns
The realloc function returns a pointer to the new object (which may have the same
value as a pointer to the old object), or a null pointer if the new object could not be
allocated.
Note that the old object is deallocated; the new object may happen to point to the same location as the old. And there could be problems. It is pretty unlikely, but it is far simpler to go with a rule 'always' than to have odd exceptions.
The normal counter-argument is "if this cannot fail, it means I have an error path that I cannot test". Up to a point, that is true. However, it could be that there has been some trampling of the memory so that the allocation cannot succeed - because the control information has been corrupted. More likely you'll just get a core dump, but maybe the code is robust enough to be able to avoid that. (I assume the hard coded 100 and 50 are for purposes of asking the question; real life code would not over-allocate when it knows how much it really needs.)
Where the two calls to 'realloc()' are adjacent, as here, there is very little room for anything to go wrong. However, real life working code would have some operations in between the two - and that code could cause the second 'realloc()' to fail.
Regarding your 'Edit 2'...
The code might be better written as:
if (b != NULL)
a = b;
return a;
But the basic concept is OK. Note that the standard explicitly says that the original allocation is safe if the new one cannot be created.