Рекурсивно выведите число c записью

Я сделал функцию, которая печатает с записью целого без знака:

ssize_t     putc_fdr(char c, int fd)
{
    return (write(fd, &c, sizeof(char)));
}

ssize_t     putuint_fdr(uintmax_t i, int fd)
{
        return (i != 0 ? putuint_fdr(i / 10, fd) + putc_fdr(i % 10 + '0', fd) : 0);
}

Но это не работает для i = 0, потому что функция ничего не печатает. И если я заменю ': 0' с ': putc_fdr('0', fd)' это не сработает, потому что если i > 10, в конце рекурсии всегда будет напечатано дополнительное "0". (логика.) Но как вывести это 0, только если начало i равно 0?

3 ответа

Вместо того, чтобы останавливаться на нуле, остановитесь, когда наберете одну цифру.

И вы должны исправить проблему секвенирования (обеспечивая тем самым правильный порядок печати), отключив ?: оператор и разрешить вашей функции поведение по умолчанию с меньшим количеством повторений:

ssize_t     putuint_fdr(uintmax_t i, int fd) {
        ssize_t ret1 = 0;

        if(i / 10 != 0)
          ret1 = putuint_fdr(i / 10, fd);

        if (ret1 < 0) 
          return ret1; 

        ssize_t ret2 = putc_fdr(i % 10, fd);

        if (ret2 < 0)
          return ret2;

        return ret1 + ret2;
}

Подумайте, что делает ваше выражение:

(i != 0 ? putuint_fdr(i / 10, fd) + putc_fdr(i % 10 + '0', fd) : 0);

Во-первых, он проверяет состояние i != 0, Тогда, если условие истинно, оно будет:

  • Рекурсивно называть себя с заявлением putuint_fdr(i / 10, fd)

  • Вызов putc_fdr(i % 10 + '0', fd)

  • Суммируйте возвращаемое значение обоих и ничего с этим не делайте.

Обратите внимание, что он может вызывать функции в любом порядке.

В случае, если я = 0, это будет:

  • return 0

Который на самом деле ничего не сделает, а просто число в середине вашего кода. Вам нужно вызвать функцию, чтобы написать 0, а не просто сказать "0"

С двоичным + не является последовательным, вам нужно обеспечить желаемый порядок оценки операндов. В большинстве случаев печать отдельных цифр означает, что вы хотите сначала напечатать MSD, поэтому вы откладываете печать цифр до тех пор, пока не установите MSD. Это означает, что вы хотите сначала выполнить рекурсию, и печатать, возвращаясь после рекурсивных вызовов.

Если вы хотите сохранить текущую структуру кода, вы можете использовать оператор запятой, ,, для последовательности двух вызовов. Чтобы исправить вашу дилемму, мы определяем, когда ввод представляет собой одну цифру.

ssize_t     putuint_fdr(uintmax_t i, int fd)
{
    ssize_t ret = 0;
    return (i / 10 != 0
            ? ret = putuint_fdr(i / 10, fd),
              ret + putc_fdr(i % 10 + '0', fd)
            : putc_fdr(i + '0', fd));
}

Это предполагает write не возвращает ошибку в середине печати вашего номера. Если вы хотите добавить дополнительную надежность, вы должны попытаться учесть и эту ситуацию.


В комментарии к этому ответу вы спросили:

Нет способа не использовать переменную и сохранять последовательные вызовы? (ret ssize_t)

Вам нужна какая-то переменная, чтобы добавить результат двух последовательных вызовов функций. Однако вы можете скрыть назначение, передав результат первого вызова функции в качестве параметра для второго вызова функции.

ssize_t     putc_fdr(char c, int fd, ssize_t ret)
{
    return ret + write(fd, &c, sizeof(char));
}

ssize_t     putuint_fdr(uintmax_t i, int fd)
{
    return putc_fdr(i%10 + '0', fd,
                    i/10 ? putuint_fdr(i/10, fd) : 0);
}
Другие вопросы по тегам