1) non voglio rubare il mestiere a Michele

Comunque direi che ci siamo. avr-size, il programma che viene usato per il calcolo dell'impegno delle memorie, analizza il codice e fa una previsione sul consumo delle variabili statiche, ossia quelle inizializzate con il classico
byte a = 1 ad esempio. Qui il compilatore sa per certo che il consumo è 1 byte. Poi nella RAM ci vanno anche stack (per i salti, ossia le chiamate alle routine) ed heap (la memoria allocata dinamicamente, come appunto gli oggetti String). E queste sono cose che non sono prevedibili a priori.
2.a)
eh, sì. Perché hai 100 byte lasciati indietro dal compilatore.
Ovviamente se nel mezzo ci sono altre variabili.
Ossia mettiamo che la tua memoria sia:
Stringa di 100
byte
byteHai 2 byte occupati dopo la stringa. Se la "svuoti" e poi la riassegni con 200 caratteri, nel buco di 100 byte iniziale non ci sta più, quindi il compilatore va dopo i 2 byte e lì ricrea una stringa di 200 caratteri.
2.b) No. Il compilatore riusa i 100 byte iniziali solo se dentro può metterci un oggetto che è 100 byte oppure meno. Non esiste il concetto di divisione dei dati. Se la stringa è lunga 300 byte, questi devono essere tutti contigui l'uno all'altro.
2.c) con reserve hai la certezza di riservare quel quantitativo di memoria anche se la tua stringa è lunga, in fase di inizializzazione, di meno. In questo modo sai per certo che fino a che la stringa sarà lunga 200 o meno byte, essa starà sempre nello stesso spazio di memoria.