Вывести цифры номера в обратном порядке без массивов или функций - PullRequest
8 голосов
/ 24 декабря 2009

Как домашнее задание, я работаю над чтением десятичного целого числа из stdin, преобразованием его в другую базу (также предоставленное из stdin) и выводом его на экран.

Вот что у меня так далеко:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int num, base, remainder, quotient;
    printf("please enter a positive number to convert: ");
    scanf("%d", &num);
    printf("please enter the base to convert to: ");
    scanf("%d", &base);

    remainder = quotient = 1;

    // validate input
    if (num < 0 || base < 0) {
        printf("Error - all numbers must be positive integers!\n");
        return 1;
    }

    // keep dividing to find remainders
    while (quotient > 0) {
        remainder = num % base;
        quotient = num / base;
        num = quotient;
        if (remainder >= 10) {
            printf("%c", remainder + 55);
        } else {
            printf("%d", remainder);
        }
    }   
    printf("\n");
    return 0;
}   

Это прекрасно работает, только алгоритм, который он использует, вычисляет преобразованные числа от младшей к старшей значащей цифре, таким образом печатая ее в обратном порядке. Так, например, преобразование 1020 в шестнадцатеричное ( 0x3FC ) приведет к печати CF3 .

Есть ли уловка, которую я мог бы использовать, чтобы повернуть эти числа для печати в правильном порядке. Я могу использовать только if-else, while, простые математические операторы и printf () / getchar () / scanf () - без функций, массивов или указателей. спасибо.

Ответы [ 9 ]

3 голосов
/ 24 декабря 2009

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

Ограничения кажутся искусственными. Я полагаю, вы еще не узнали о функциях, массивах, указателях и т. Д. В своем классе, но я думаю, что эта проблема не предназначена для элегантного решения без функций и / или массивов.

В любом случае, вы можете сделать что-то вроде этого:

curr := base
pow := 1
while num / curr >= 1 do:
    curr := curr * base
    pow := pow + 1

while pow >= 1:
    pow := pow - 1
    print floor(num / base ** pow)
    num := mod(num, base ** pow)

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

Некоторые специфические проблемы с вашим кодом. Я понимаю, что это начало класса C, но все же лучше знать о таких проблемах сейчас, чем никогда не осознавать их:

printf("please enter a positive number to convert: ");

Вы должны добавить fflush(stdout) после этого, чтобы убедиться, что вывод появляется до вызова scanf(). По умолчанию stdout является буферизованной строкой во многих системах, поэтому подсказка может не появиться, пока ваша программа не ожидает ввода.

printf("please enter the base to convert to: ");

То же, что и выше.

    if (remainder >= 10) {
        printf("%c", remainder + 55);
    } else {
        printf("%d", remainder);
    }

Вы предполагаете набор символов ASCII. Это не должно быть правдой. Но без массивов или указателей нет простого способа напечатать алфавиты, соответствующие 10.... Кроме того, ваш код может печатать странные символы для base > 36.

Вы также должны знать, что очень трудно безопасно использовать scanf(). Надеюсь, вы узнаете лучшие способы получения информации позже.

3 голосов
/ 24 декабря 2009

(здесь удалена оригинальная часть поста, так как это не решение)

ТО единственное решение, которое я вижу , - это выполнить цикл, который у вас есть сейчас, сколько раз у вас есть цифры.

Итак, сначала вы рассчитываете все цифры до последнего, а затем распечатываете.

Затем вы берете исходное значение + основание и начинаете деление снова, пока не дойдете до второй цифры «наивысшего значения». Распечатайте это.

Это двойной цикл, и вы рассчитываете все дважды, но вы не используете дополнительное хранилище.

1 голос
/ 24 декабря 2009

Эй! Я узнаю известное домашнее задание, которое у меня было на первом курсе моей школы (@Epitech ученики: не копируйте / вставляйте следующий код, попробуйте придумать свое собственное решение, это для вашего же блага ^^)

Решение вашей проблемы - выполнить ее рекурсивно:

void    my_putnbr_base(int num, int base)
{
  int   start;
  int   remainder;

  remainder = num % base;
  start = (num - remainder) / base;
  if (start != 0)
    my_putnbr_base(start, base);
  if (remainder >= 10)
    printf("%c", remainder + 55);
  else
    printf("%d", remainder);
}

Указывает ли ваша домашняя работа, что она должна работать только с положительными числами? Если нет, то легко включить обработку отрицательных чисел:

void    my_putnbr_base(int num, int base)
{
  int   start;
  int   remainder;

  if (num < 0)
    {
      putchar('-');
      my_putnbr_base(-num, base);
    }
  else
    {
      remainder = num % base;
      start = (num - remainder) / base;
      if (start != 0)
        my_putnbr_base(start, base);
      if (remainder >= 10)
        printf("%c", remainder + 55);
      else
        printf("%d", remainder);
    }
}

@ arno: это правда, потому что код примера использует таблицу ASCII. Если мы хотим что-то действительно гибкое, нам нужна база в параметре. Например:

>> my_putnbr_base(4242, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")
39U
>> my_putnbr_base(42, "0123456789ABCDEF")
2A

это реализует пример:

void    my_putnbr_base(int num, char *base)
{
  int   start;
  int   remainder;
  int   len;

  len = strlen(base);
  if (num < 0)
    {
      putchar('-');
      my_putnbr_base(-num, base);
    }
  else
    {
      remainder = num % len;
      start = (num - remainder) / len;
      if (start != 0)
        my_putnbr_base(start, base);
      printf("%c", base[remainder]);
    }
}

Надеюсь, это решит вашу проблему!

edit: я не правильно прочитал ^^ Вам не разрешено использовать функции, поэтому о рекурсии не может быть и речи ... Вот интерактивный способ, вы можете поместить это в main (). Вы можете улучшить этот код, добавив обработку отрицательных чисел и гибкие базы, как я показал вам:)

int     my_putnbr_base_it(int num, int base)
{
  unsigned int  quotient = 1;
  unsigned int  remainder;

  while ((num / quotient) >= base)
    quotient *= base;
  while (quotient)
    {
      if ((remainder = (num / quotient) % base) < 10)
        printf("%d", remainder);
      else
        printf("%c", 55 + remainder);
      quotient /= base;
    }
  return (0);
}

Надеюсь, теперь все решено!

1 голос
/ 24 декабря 2009

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

n = 1020, 3 шестнадцатеричные цифры, big_base = 16 * 16

1st step
1020 / (16 * 16) = 3

2nd step
n = 1020-3 * (16 * 16) = 252
252 / (16) = 15, F

3rd step
n = 252 - 15 * 16 = 12, C

0 голосов
/ 24 декабря 2009

Исходя из того, что было предложено, способ решения этой проблемы состоял в том, чтобы печатать последнее число и повторять цикл для каждой цифры. Я следил за состоянием печати, сохраняя предыдущее частное и печатая каждый раз, когда получал его (затем сбрасывал число и начинал заново), а затем сбрасывал его до предыдущего. Звучит сложно, но изменить код было просто. Мое условие остановки для цикла было, когда у меня было 2 последовательных отпечатка, так как большую часть времени он просто вычислял частное / остаток и ничего не печатал, а когда 2 цифры печатаются подряд, это последние два. Во всяком случае, вот код:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int num, saved, base, remainder;
    int quotient, prev_q, stop_q, just_printed;

    printf("please enter a positive number to convert: ");
    scanf("%d", &num);
    printf("please enter the base to convert to: ");
    scanf("%d", &base);

    saved = num;
    remainder = quotient = prev_q = just_printed = 1;
    stop_q = 0;

    // validate input
    if (num <= 0 || base <= 0) {
        printf("Error - all numbers must be positive integers!\n");
        return 1;
    }

    // divide
    while (1) {
        remainder = num % base;
        quotient = num / base;
        num = quotient;

        // print if it's the last number and reset num to the next 
        if (quotient == stop_q) {
            if (remainder >= 10) { printf("%c", remainder + 55); } 
            else { printf("%d", remainder); }

            // if 2 consecutive printing occur, this means it's time to end this
            if (just_printed) { break; }

            // next time print when hitting the previous quotient
            stop_q = prev_q;

            // reset the number to the original value
            num = saved;


            just_printed = 1;
        } else {
            just_printed = 0;
        }
        prev_q = quotient;
    }   
    printf("\n");
    return 0;
}    

Спасибо всем, кто принял участие!

0 голосов
/ 24 декабря 2009

Интересное задание, у вас есть домашнее задание. Я начинающий программист, и я пытался решить эту задачу.

Следующий код работает (я не много тестировал, по-видимому, работает). Я уверен, что это не самое оптимальное и лучшее решение, но это было единственное, что я мог придумать. Это должно работать с любой базой. К сожалению, он не преобразует 10-> A, 11-> B и т. Д.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(){
        int nr,base,res,tp,tpb,tpbt,r,rnr,lp,lpt,i;
        float baset,rt;

        /** Read number */
        printf("nr=");
        scanf("%d",&nr);

        /** Read base */
        printf("base=");
        scanf("%d",&base);

        /** Returning result */
        res=0;

        /** Test if number is positive
        and base is bigger than 2 */
        if(nr<0||base<2){
                /** Error */
                res=1;
        }
        else{
                /** Determine how many
                digits are necessary */
                lp=0;
                baset=base;
                while(baset>1){
                        lp++;
                        baset/=10;
                }

                /** Determine full power
                of 10 when r has length of lp */
                tpb=1;
                while((lp--)>0){
                        tpb*=10;
                }

                /** Power of ten that will be
                incremented */
                tp=0;

                /** Converted number (will be printed
                as the result) */
                rnr=0;

                /** Algorithm */
                while(nr>0){
                        r=nr%base;
                        nr/=base;
                        rt=r;

                        /** Temporary lp for
                        r */
                        lpt=0;
                        while(rt>1){
                                lpt++;
                                rt/=10;
                        }

                        /** Temporary tpb for
                        lpt */
                        tpbt=tpb;
                        for(i=0;i<lpt;i++){
                                tpbt/=10;
                        }

                        /** Build number */
                        rnr+=r*pow((double)(tpbt),(double)(tp++));
                }
        }

        /** Show number */
        printf("number is: %d \n",rnr);

        return (res);
}
0 голосов
/ 24 декабря 2009

Вы можете попробовать этот подход. Это скорее подтверждение концепции, вам все равно придется разобраться с каким-то особым случаем, но, эй, это ваша домашняя работа:)

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int num, base, remainder, quotient;
    int divider;

    printf("please enter a positive number to convert: ");
    scanf("%d", &num);
    printf("please enter the base to convert to: ");
    scanf("%d", &base);

    remainder = quotient = 1;

    // validate input
    if (num < 0 || base < 0) {
        printf("Error - all numbers must be positive integers!\n");
        return 1;
    }

    // First get the highest divider
    divider = base;

    while ( num / divider > base ) {
      divider *= base;
    }

    do {

      // Get the highest digit
      remainder = num / divider;

      // And update num accordingly
      num -= remainder * divider;
      divider /= base;

      if (remainder >= 10) {
        printf("%c", remainder + 55);
      } else {
        printf("%d", remainder);
      }

    } while ( divider );

    printf("\n");
    return 0;
}
0 голосов
/ 24 декабря 2009

Вы можете использовать две петли. Первый продолжает генерировать мощности базы, пока не найдет мощность, превышающую входное число. Второй начинается отсюда (или, скорее, на одну степень раньше) и возвращается к базе ^ 0 (т.е. 1), чтобы сначала вычислить наиболее значимые выходные цифры.

Неопробованный псевдокод:

// Determine highest power, don't actually need "power" it's just there for illustration
power = 0;
baseraisedtopower = 1;
while (baseraisedtopower <= input)
{
    baseraisedtopower *= base;
    power++;
}
// Go back one step, could have saved previous result
baseraisedtopower /= base;
power--;
// Output
while (input > 0)
{
    // Integer division, truncate
    quotient = input / baseraisedtopower;
    printf("%c", quotient + 55);
    input -= quotient * baseraisedtopower;
    baseraisedtopower /= base;
    power--;
}
0 голосов
/ 24 декабря 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...