Как проблема домашней работы, я работаю над чтением десятичного интервала от 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.
Есть ли прием, который я мог использовать для инвертирования этих чисел для печати в правильном порядке. Я могу только использовать если еще, в то время как, простые математические операторы и printf ()/getchar ()/scanf () - никакие функции, массивы или указатели.спасибо.
(здесь удалена оригинальная часть сообщения, так как это не решение)
THen единственное решение, которое я вижу - это выполнить цикл, который у вас есть сейчас количество раз, которое у вас есть цифры.
Итак, сначала вычисляете все цифры, пока не дойдете до последней, а затем распечатываете их.
Затем берете исходное значение + база и снова начинаете делиться, пока не дойдете до второй цифры "наибольшего значения". Выведите его.
Это двойной цикл, и вы вычисляете все дважды, но не используете лишнюю память.
Вы можете переписать кусок кода, вычисляющий каждое число, чтобы вести себя как государственная машина. Он начнется в начальном состоянии и вычислит количество цифр, затем изменит состояние на "печать N-ой цифры", чтобы распечатать самую значащую цифру, затем изменит состояние, чтобы перейти к менее значащим цифрам, и т.д. до тех пор, пока не будет вычислено конечное состояние. Выполняя это внутри цикла, вы будете выводить все цифры в правильном порядке.
.Хорошая попытка, и хорошо сформулированный вопрос. Если бы только у нас было больше людей, задающих вопросы в такой ясной форме!
Ограничения кажутся искусственными. Наверное, в своем классе вы еще не познакомились с функциями, массивами, указателями и т.д., но я думаю, что эта проблема не должна быть элегантно решена без функций и/или массивов.
В любом случае, вы можете сделать что-то вроде этого:
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()
. Надеюсь, что Вы узнаете лучшие способы получения ввода позже.
В одном цикле можно вычислить количество цифр и big_base
.
Во втором цикле можно вывести цифры, начинающиеся с наиболее значимых, например:
n = 1020, 3 гекс-цифры, big_base = 16*16
1-й шаг
1020 /(16*16) = 3
2-й шаг
n = 1020- 3*(16*16) = 252
.
252 / (16) = 15, F
3-й шаг
n = 252 - 15*16 = 12, C
Эй! Я тоже узнаю известное домашнее задание, которое было у меня в первый год обучения (@Ученики Эпитек: не копируйте/вставляйте следующий код, попробуйте придумать свое собственное решение, это для вашего же блага ^^)
Решение вашей проблемы заключается в рекурсивном выполнении задания :
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: I didn't read right ^^ Вы не имеете права использовать функции, поэтому о рекурсии не может быть и речи... Вот интерактивный способ, вы можете поместить это в 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);
}
Надеюсь, теперь он решает все !
.Интересное задание, у тебя как домашнее задание. Я начинающий программист и пытался решить эту задачу.
Следующий код работает (я не много тестировал, видимо, работает). Я уверен, что это не самое оптимальное и лучшее решение, но это единственное, что я смог придумать. Он должен работать с любой базой. К сожалению, он не будет конвертировать 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);
}
Исходя из того, что было предложено, способ решения этой проблемы заключался в том, чтобы сохранить последнее число и повторить цикл для каждой цифры. Я отслеживал состояние печати, сохраняя предыдущий коэффициент и распечатывая его каждый раз, когда приходил к нему (затем сбрасывая номер и начиная заново), затем сбрасывая его на предыдущий. Звучит сложно, но изменение кода было простым. Мое условие остановки цикла было, когда у меня было 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;
}
Спасибо всем, кто встал!
.Вы можете попробовать этот подход. Это скорее доказательство концепции, вам все равно придется разбираться с каким-то особым случаем, но, эй, это ваше домашнее задание :)
#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 (т.е. 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--;
}