First, assumptions: floating point numbers stored in a computer/microprocessor have no standard format. If you KNOW that both ends are always the same type, we can simplify, as example:
There are many ways to code this. Here's one, sending the float as binary data (not text):
float f;
f = 123.456;
rf22.sendtoWait((uint8_t *) &f, sizeof(f), SERVER_ADDRESS)); // sends 4 byte floating point. A double might be 8 bytes.
In the above, the memory address of f is "&f". the (uint8_t *) is a C language cast so that the memory address of f is compatible with the 1st parameter of senttoWait().
On the receiving end you could receive this binary float and convert it as follows:
float f;
rf22.recvfromAckTimeout((uint8_t *) &f, sizeof(f), &len, 2000, &from);
Serial.print(f);
A better and universal way to exchange ints and floats, since they differ among computers and MCUs, it to convert the data to text for transmission purposes. This is machine-type-independent:
float f = 123.456;
sprintf(data, "%f is the value!\n"); // put text in the data buffer. sprintf() is a standard C library function.
Serial.print((char *)data); // display what we will send.
rf22.sendtoWait(data, 1+strlen(char *)data, SERVER_ADDRESS)); // strlen is a C lib function. 1+ is to send the C string's terminating '\0'
On the other end, receiver the text
float f;
rf22.recvfromAckTimeout(buf, &len, 2000, &from));
Serial.print((char *)buf); // show what we got.
sscanf((char *)buf, "%f", &f); // parse and convert from text back to binary (this works on any MCU type.
Serial.print(f);
There are lots of other library tools and techniques.
An intro to C would have more examples. None of this needs to get into the complexity of C++ (yet).