Usar a biblioteca SDL_ttf (com SDL 2) não tem segredo.

  1. Você inicializa com TTF_Init()
  2. Carrega uma fonte com TTF_OpenFont()
  3. Cria um texto com TTF_RenderText_Solid()
  4. E desenha na tela com SDL_BlitSurface()

Olha um exemplo aqui neste gist.

Obs.: Para usar os exemplo deste artigo é necessário que o arquivo VT323.ttf esteja na mesma pasta que os códigos.

Você pode baixar esta fonte neste link: https://fonts.google.com/specimen/VT323

Renomeie o arquivo baixado caso seja necessário.

Este tipo de dado muda constantemente e o pior: mistura números e texto!

Como você faria pra escrever, por exemplo, “Your Score: 123”?

Se estivéssemos lidando com printf() e console seria fácil:

printf("Your Score: %d", score);

Então a solução para esse problema é o snprintf().

A diferença do snprintf é que ao invés de imprimir texto na saída padrão, ele armazena o texto gerado em um array.

snprintf(BUFFER, BUFFER_SIZE, "Your Score: %d", 123);

Depois é só fazer o que quiser com o BUFFER. Experimente com:

#include <stdio.h>
#define BUFFER_SIZE 512

int main() {
    char buffer[BUFFER_SIZE] = {0};
    snprintf(buffer, BUFFER_SIZE, "Your Score: %d", 123); // armazena em buffer
    printf(buffer); // imprime o resultado na saida padrão
    return 0;
}

Voltando pro nosso problema em SDL, poderíamos alterar o código mostrado no inicio pro while ficar assim:

int counter = 0;
while (!SDL_QuitRequested()) {
    char buffer[512] = {0};
    SDL_snprintf(buffer, 512, "Your Score: %d", counter++);

    SDL_Surface* text = TTF_RenderText_Solid(font, buffer,
                (SDL_Color) { 255, 255, 255, 255 });

    SDL_FillRect(surface, NULL, 0);
    SDL_BlitSurface(text, NULL, surface, NULL);
    SDL_FreeSurface(text);

    SDL_UpdateWindowSurface(window);
}

Isso resolve o problema e nos permite criar texto como se estivéssemos usando usando printf, mas nós podemos ir um pouco mais além. Que tal criar uma função que nos permita deixar nosso loop assim:

while (!SDL_QuitRequested()) {
    SDL_FillRect(surface, NULL, 0);

    drawText("Your Score: %d", counter++);

    SDL_UpdateWindowSurface(window);
}

Para isso vamos precisar de mais uma função da biblioteca padrão, a vsnprintf(). Ela aceita como último argumento uma va_list, aquela estrutura que usamos quando queremos criar uma função que aceita uma quantidade variável de argumentos.

Com ela podemos criar a seguinte função:

#define MAX_LENGTH 1024
void drawText(const char* fmt, ...) {
    char buffer[MAX_LENGTH] = {0};

    va_list ap;

    va_start (ap, fmt);

    SDL_vsnprintf(buffer, MAX_LENGTH, fmt, ap);

    va_end (ap);

    SDL_Surface* text = TTF_RenderText_Solid(font, buffer,
                    (SDL_Color) { 255, 255, 255, 255 });

    SDL_BlitSurface(text, NULL, surface, NULL);
    SDL_FreeSurface(text);
}

Tem outro gist com o resultado final aqui

UPDATE (12/09/18):
Usei o exemplo anterior para fazer uma versão usando renderer. O gist com o código é este