В чем смысл do while? Как его можно использовать?
do-while удобно применять когда например есть пользовательский ввод и есть реакция на ошибу. Где нужно ввод 
повторить. Например

do {
  s = input("Enter your bidthday: ")
} while(!isValidDate(s));
Еще я использовал для простого I/O когда надо что-то по-символьно читать и проверять
что файл не закончился (результат не отрицательный).

В последних версиях Scala (3.x) мусье Одерский внезапно зобанил оператор цикла с постусловием.
Я уж не помню как он это аргументировал.  

В качестве альтернативы предлагалось делать такой композитный предикат который делает
сначала действие а потом проверяет.

while ({ <body> ; <cond> }) ()

Еще дальше пошел Дейкстра. Он придумал специальный вид do-while для конечных автоматов.
Такой себе гибрид do-switch-case-while. Где можно как в DSL описать исходящие переходы.
Правда я не помню где он его реализовал.

UPD: Ошибочка. Не Вирт а Дейстра. Путаю их.
Например, функции ввода/вывода в POSIX возвращают EINTR, если во время их работы в приложение пришел сигнал.
Сигнал вы можете перехватить, обработать и можно продолжать дальше. Но функция (например write) вернет EINTR. Если эту ситуацию не обрабатывать отдельно, то это может вызвать, например, завершение приложения (из-за ошибки ввода/вывода), тогда как приложение могло бы дальше работать.
В этом случае удобно вызов функции заключать в do while:
int ret;
do {
  ret = write(...);
} while(ret == EINTR);
Это один из вариантов, когда надо выполнить действие, и по результатам действия будет понятно надо ли еще раз его запустить или уже достаточно.
В этот же цикл можно добавить и другой функционал. 
В случае неблокируемых операций ввода/вывода операция может завершится не записав или не прочитав все что нужно или вообще вернуть EAGAIN, если ничего нет. Можно эти проверки добавить в этот же цикл do while вместе с проверкой на EINTR.
Вариантов использования, на самом деле много. Вы это увидите, когда столкнетесь с таким вариантом в своей практике.

Но самый популярный вариант у Си программистов, это использование в макросах:
#define MACRO(x)      do { тут что-то делаем } while(0)
Этот фиктивный цикл служит двум целям:
1. внутри цикла можно объявлять локальные переменные, которые не будут видны вне цикла
2. При использовании макроса можно в конце ставить точку с запятой, не нарываясь на предупреждения компилятора: MACRO(val);. Компилятор в итоге уберет цикл, но все побочные эффекты сохранятся.
В плюсах этот вариант практически не используется, т.к. тут есть шаблоны и т.п. и от макросов в основном отказываются. Но в Си макросы вполне актуальный инструмент.

Но циклы for и while применяются чаще, чем do while.