Total noob question about char array and unexpected output

Hi all. I apologize in advance for my lack of knowledge of both electronics and programming. I am trying to learn, but Google searches only get me so far.

I bought an OLED LED module for my Arduino UNO Rev3, and probably should have waited to experiment with it until I'd gotten some other key concepts under my belt, but I was just too excited. This question is about the programming, not the OLED LED display.

I wanted to combine the standard example sketch "Read Analog Voltage" with the "Hello World" example from the u8glib library included for the display. My hope was to have the voltage shown on the display, in addition to the serial monitor.

Here is the code I'm using (note: I have removed a number of lines of commented display-specific options):

/*

  HelloWorld.pde
  
  "Hello World!" example code.
  
  Universal 8bit Graphics Library, http://code.google.com/p/u8glib/
  
  Copyright (c) 2012, olikraus@gmail.com
  All rights reserved.
  
*/


#include "U8glib.h"



/* SLboat Add Device */
U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_NONE); // I2C 128x64(col2-col129) SH1106,Like HeiTec 1.3' I2C OLED 

void draw(void) {
  
  int vltgread = analogRead(A0);
  float vltg = vltgread * (5.0 / 1023.0);
  
  // graphic commands to redraw the complete screen should be placed here  
  u8g.setFont(u8g_font_unifont);
  //u8g.setFont(u8g_font_osb21);
  u8g.drawStr( 0, 10, "VOLTAGE:");
  u8g.setFont(u8g_font_fub17);
  char buf[9];
  sprintf (buf, "%d", vltg);
  u8g.drawStr( 0, 58, buf);
  Serial.println(buf);
}

void setup(void) {
  Serial.begin(9600);


  // flip screen, if required
  // u8g.setRot180();
  
  // set SPI backup if required
  //u8g.setHardwareBackup(u8g_backup_avr_spi);

  // assign default color value
  if ( u8g.getMode() == U8G_MODE_R3G3B2 ) {
    u8g.setColorIndex(255);     // white
  }
  else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) {
    u8g.setColorIndex(3);         // max intensity
  }
  else if ( u8g.getMode() == U8G_MODE_BW ) {
    u8g.setColorIndex(1);         // pixel on
  }
  else if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
    u8g.setHiColorByRGB(255,255,255);
  }
}

void loop(void) {

  // read the input on analog pin 0:
  int sensorValue = analogRead(A0);
  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float voltage = sensorValue * (5.0 / 1023.0);
  // print out the value you read:
  Serial.println(voltage);
  

  // picture loop
  u8g.firstPage();  
  do {
    draw();
  } while( u8g.nextPage() );
  

  // rebuild the picture after some delay
  delay(2000);
}

My question has to do with my attempt to convert the float variable containing the calculated voltage (using a solution I found on more than one message board on the topic):

  int vltgread = analogRead(A0);
  float vltg = vltgread * (5.0 / 1023.0);
  
  // graphic commands to redraw the complete screen should be placed here  
  u8g.setFont(u8g_font_unifont);
  //u8g.setFont(u8g_font_osb21);
  u8g.drawStr( 0, 10, "VOLTAGE:");
  u8g.setFont(u8g_font_fub17);
  char buf[9];                       <--------
  sprintf (buf, "%d", vltg);     <--------
  u8g.drawStr( 0, 58, buf);    <--------
  Serial.println(buf);

When this sketch is run, the serial monitor shows two types of output: A single line showing the voltage calculated in the void loop section, which is a decimal number displaying to the hundredths. Then eight lines in succession with four-to-five-digit integers. For example (these are not real values):

1.53
8663
10224
8663
7940
12084
8663
8664
8664

This repeats every 2000ms (as the program indicates). The reading of the eight integers happens simultaneously, and causes the LED to display a jumble of broken numbers.

Here is what I can't figure out, because my programming knowledge is not deep, and Google isn't helping:

What is the purpose of assigning the variable buf as an array? And what is the relevance of "9"?

I changed that value to 0, 1, 4, and 12. Values 4 and 12 seem to behave exactly the same, with eight simultaneous vltg readings being displayed to the serial monitor. Values 0 and 1 cause an endless stream of readings to be displayed (if I recall correctly). Is "9" arbitrary?

Follow up question....Why are eight simultaneous readings being sent to the serial monitor, and why are they not decimal values exactly like the value of voltage, since they are both derived the same way (with the only exception of vltg being converted to a string for use with the u8g.drawStr().

I truly appreciate any insight into this behavior.

(Although I'm certainly not asking for workarounds or alternative solutions, I wouldn't say no to any advice.)

"%d" is used to interpret an int.
"%f" is for float

I was going to ask about the relevance of the "%d" but didn't want to overload the question. It was frustrating trying to search for information about "char" and have almost nothing explaining what formatting "%d" was responsible for.

Thank you...I'll experiment with that when I get home.

textheavy:
I was going to ask about the relevance of the "%d" but didn't want to overload the question. It was frustrating trying to search for information about "char" and have almost nothing explaining what formatting "%d" was responsible for.

Thank you...I'll experiment with that when I get home.

%f, %d, and many others are Format Specifiers for the 'printf' family of functions. Look here:
http://www.cplusplus.com/reference/cstdio/printf/

Delta_G:
It should be noted though before the OP gets much further that by default support for the %f format specifier is disabled in Arduino core to save space. If you use it then it will just print a question mark IIRC.

Thanks for the notification. I recall reading something about Arduino not supporting various usual methods for converting float to string.

Looks like I'm back to not understanding why the "buf" variable is declared as a char array, and what the relevance of the "9" is (not sure what that's called, "index"?).

Also still confused about why eight values are sent to the serial monitor simultaneously every time the loop runs. I assumed it was related to the value "9" but that doesn't seem to be the case.

Is it because the value is determined in the "void draw(void)" section of the code, and not in the loop itself? I tried moving those variable declarations to the loop, and before the void sections, but it caused a error when compiling in both cases.

Also still confused about why eight values are sent to the serial monitor simultaneously every time the loop runs. I assumed it was related to the value "9" but that doesn't seem to be the case.

I don't understand why you are seeing that. Simple testing of sprintf with a float passed in as %d does not show that behaviour.

Use dtostrf() to convert the float to a character string.

If voltage is always 5v or less, and you want it printed x.xx with two places after the dp, then dtostrf() will be

char buf[5];//one leading digit, a decimal point, two digits after the decimal point, and a null terminator
dtostrf(vltg, 4, 2, buf);

Delta_G:
The 9 means that array has enough room for 8 characters plus a terminator. Look up "c style string" for more on how c handles text strings.

Thank you. I'll Google that to learn more. I was having a hard time knowing what search terms to use to find that specific information.

textheavy:
Thank you. I'll Google that to learn more. I was having a hard time knowing what search terms to use to find that specific information.

I'll give you the same suggestion I give everyone: google "C++ tutorial", and do the first half of the tutorial. There are important differences between C on a full computer and C on and arduino, notably there is no stdin and stdout, no main() (well, there is, but not if you are new to programming there isn't), and it's important not to use the C++ String class or dynamic memory in general.

However, the basics of types, declarations, arrays and pointer arithmetic, variable scope and lifetime, calling functions - the C++ language as such - a tutorial should cover them.