A few suggestions
In general I don't trust the pre-processor to do the right constant calculation for me. it's too easy to forget a decimal point or arrange math in a way you would loose precision so for float v2 = analogRead (v2Pin) * (5 / 1023.) * 4.0432; // check voltage divider nominal level 18V I actually would use a calculator and calculate myself what (5 / 1023.) * 4.0432 is worth and use that like
#define ADJUST_VALUE 0.019761485826002 // (5 / 1023.) * 4.0432
...
float v2 = analogRead (v2Pin) * ADJUST_VALUE; // check voltage divider nominal level 18V
In your case that's fine the way you did it and will lead to the right behavior though. so feel free to keep it.
v2char[0] = '0'; // clear out array to start
v2char[1] = '0';
v2char[2] = '0';
v2char[3] = '0';
v2char[4] = '0';
when I see this obviously I'm thinking of a for loop.
for(int i=0;i<5;i++) v2char[i] = '0';
BUT then if you think even more globally about what you want to do, the next thing your code does is
if (v2 < 10.0) dtostrf (v2, 4, 2, &v2char [1]); // number, width, decimal places, buffer
else dtostrf (v2, 5, 2, &v2char [0]); // number, width, decimal places, buffer
The dtostrf() function converts the double value passed in val into an ASCII representation that will overwrite most of your v2char you just set --> So there is no reason to set those '0' characters there by default.
You know that v2 is the result of an analogRead() so a positive number between 0 and 1023 and that you multiplied by a positive constant that is less than 1 - actually less than 0.02 so you know that v2 is between 0 and 20,46. that's lots of good information for code optimization as you definitely know you won't have more than 2 trailing digits (since the first integer part is at max 20) and as you want 2 digits after the decimal point, you won't have more than 5 chars total.
NOTE that it means that hopefully you declared v2char[6] (at least) and not v2char[5] otherwise the dtostrf() call will overwrite memory after your array with the training '\0' character it adds
Then your code calls either dtostrf (v2, [color=red]4[/color], [color=blue]2[/color],...) or dtostrf (v2, [color=red]5[/color], [color=blue]2[/color], ...)
What you know:
2 is the number of digits you want after the decimal point always.
dtostr() will add a training null char into your array and you are doing some math to see where you want to start writing in memory.
--> but you know that your array will ends with a dot, two digits and an '\0' after calling dtostrf()
The only thing dtostrf() won't do for you is put a leading '0' (seems this is what you want). dtostrf()
will put a leading space instead of a '0' if your value is less than 10. that is if v2 is 2.6753 your char array will be " 2.67" with a leading space that looks good because you asked a minimum width of 5. and if it's above 10 then that space will have the right char.
--> so if you prefer a leading '0' rather than a space (personal preference but I find this annoying because it's not a normal mathematical notation) then the only thing you need to do after the call dtostrf() is to set the first char to '0' if it is a space. so your code can become
float v2 = analogRead (v2Pin) * (5 / 1023.) * 4.0432; // check voltage divider nominal level 18V
dtostrf (v2, 5, 2, v2char); // number, width, decimal places, buffer
if (v2char[0] == ' ') v2char[0] = '0'; // put a leading '0' instead of a space if needed
final note, if you were to use dtostrf (v2, [b][color=red]-5[/color][/b], 2, v2char); then your string would be right aligned with a TRAILING space if needed. so 2.3456 would be represented as "2.34 " and 12.3456 would be represented by "12.34" with no leading space.
hope this helps