Yes, that's pretty much you will need to do - adjust pointers to serialized stuff, if you keep any. Or simply don't store any pointers to serialized data, just indices, then doing fread/fwrite will be everything you need to do.
I know people don't like C++ much here, but if you want then for serializing pointers you could use this helper template:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16  | template <class T>
struct Pointer32
{
    int32_t offset;
    T* operator ()
    {   
        return (T*)((uint8_t*)this + offset));
    }
    Pointer32& operator = (T* other)
    {
        ptrdiff_t diff = (uint8_t*)other - (uint8_t*)this;
        assert(diff>= INT_MIN && diff <= INT_MAX);
        offset= (int32_t)diff;
        return *this;
    }
};
 
 | 
 
This will allow to write code like this:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13  | struct Blob
{
  float x;
  float y;
  Pointer32<Blob> next;
};
Blob* blob = ...; // unserialize
blob->x = 1;
blob->next->x = 2; // here we reference other object by relative offset
Blob* otherBlob = ...;
blob->Next = otherBlob; // change pointer
 
 | 
 
C++ will automatically resolve pointer from relative offset. And if you can guarantee that you are placing objects closer together you can create Pointer16 with int16_t offset, saving 2 bytes. Even just by using Pointer32 you will save 4 bytes per pointer on 64-bit architecture.
And you can easily fread/fread whole memory block that stores Blob's as array of bytes.
And because pointers are typically aligned at least at 4 or even 8 bytes, you can increase distance 4 or 8 types by always using 0 as lowest bits of offset and shifting it up 2 or 3 bits.
And if you are OK using MSVC specifc syntax you can look into 
__based keyword, but I recomend against using it and staying portable.