Илья, если в функции void dec_to_bin(int const&num) (1) выражение num / 2 >= 1 упростить до num > 1, избавившись от лишнего деления, и (2) аргумент передавать не по константной ссылке, а по значению, избавившись от лишней косвенной адресации, то получится практически тот вариант рекурсивной функции, который я опубликовал ранее. Наши решения почти совпали.
Второй момент более проблемный и, поскольку задачу ставил не я, адресовать его нужно beginner'у. В условии задачи было ограничение на использование библиотек, и конкретно STL. В твоей программе подзадача «вывести предупреждение и завершить работу, в случае если <вводимое> число превышает кол-во байтов» решается средствами STL. Ибо потоковый ввод-вывод — это фишка чисто из STL.
В других вариантах решения от «различных производителей» (почти во всех) для ввода-вывода тоже используется STL. Но всё-таки делались попытки (разной степени успешности) определить битовый размер вводимого числа. Ты в своём варианте играешь на том, что при вводе числа, превышающего размер переменной-приёмника, функция потокового ввода (из STL) записывает в переменную-приёмник некое магическое значение с установленным старшим битом, которое интерпретируется как отрицательное число, и тут же попадает под нож проверки на отрицательность.
beginner, твоё мнение по данному вопросу?
Фтьiкай
Слухи о том, что <stdio.h> умер, сильно преувеличены ))
Просто сейчас почему-то не модно знать стандартную си-шную библиотеку ввода-вывода. Впрочем плюсовую потоковую библиотеку хорошо тоже мало кто знает. Парадокс однако ;)
Вот вариант решения, полностью удовлетворяющий всем условиям задачи. Без ГМО, то есть STL. Только <stdio.h>, только хардкор ))
#include <stdio.h>
#include <locale.h>
// псевдоним для целочисленного типа с которым будем работать
//typedef char itype;
//typedef short int itype;
//typedef int itype;
//typedef long int itype;
typedef long long int itype;
enum GNENUM { GN_OK = 0, GN_NEG, GN_ILL, GN_LONG };
GNENUM get_num(itype *num) {
*num = 0;
itype prevnum = 0;
int ch;
// анализируем первый символ
ch = getchar();
if (ch == EOF)
return GN_ILL;
if (ch == '-') {
// анализируем второй символ для правильной диагностики ситуации
int ch2 = getchar();
if (ch2 >= '0' && ch2 <= '9')
return GN_NEG;
else
return GN_ILL;
}
if (ch != '+') // игнорируем символ '+'
ungetc(ch, stdin); // возвращаем первый символ обратно в буфер ввода
while ((ch = getchar()) != EOF) { // конец ввода по ошибке файла
if (ch == '\n') // или по символу конца строки
break;
if (ch < '0' || ch > '9') // найден нецифровой символ
return GN_ILL;
*num = *num * 10 + (ch - '0');
if (*num < prevnum) // проверка на переполнение
return GN_LONG;
prevnum = *num;
}
return GN_OK;
}
void toBin(itype n) {
if (n > 1)
toBin(n / 2);
putchar(n % 2 + '0');
}
int main() {
setlocale(LC_ALL, "Russian");
itype number;
printf("Введите целое положительное число длиной не более %u бит: ", (unsigned int)sizeof(itype)* 8);
GNENUM gn_ret = get_num(&number);
if (gn_ret != GN_OK) {
switch (gn_ret)
{
case GN_NEG:
printf("Введено отрицательное число.\n");
break;
case GN_ILL:
printf("Неверный формат числа.\n");
break;
case GN_LONG:
printf("Введено слишком большое число.\n");
break;
default:
printf("Хня какая-то творится...\n");
break;
}
return 1;
}
// вывод в максимально длинном целочисленном типе
printf("Введено\n 10-тичное:\t%lld\n 16-ричное:\t%llX\n двоичное:\t", (long long int)number, (long long int)number);
// вывод двоичного представления
toBin(number);
printf("\n");
return 0;
}
На счет вывода в двоичной форме я не стал напрягаться и адаптировал решение от Cranium'а.
Работает с целыми типами размером от 1 до 8 байт. Если процессор/компилятор поддерживает, то можно и длиннее (хе-хе! ;) ). Длина типа задается typedef'ом в начале программы: нужно раскомментировать только интересующий typedef.
Просто сейчас почему-то не модно знать стандартную си-шную библиотеку ввода-вывода.
Модно ее использовать в C. В плюсах, в большинстве случаев нужно стараться использовать потоковый ввод-вывод и минимализировать использование сишных строк.
Без ГМО, то есть STL.
Если кодишь на плюсах, нужно использовать STL. Это касается как использования контейнера std::string вместо сишных строк, std::vector вместо динамических массивов, new вместо malloc и т. п.
В последней редакции кода (с поправкой на то, что в функции void dec_to_bin(int const&num)все-таки ))) можно обойтись без статических переменных) произошло слияние всяческих штучек (типа безусловного for), рекурсии, проверки goodbit, с последующей синхронизацией потока, в дополнение, с очисткой failbit (но при всей этой грозной защите происходит вылет одного цикла программы при вводе вещественного числа) и апофеоз — это завершение программы вводом нуля и похвалой себя любимого.
selevit, я согласен с тобой (и с Самим), что при программировании на плюсах надо использовать STL и не изобретать велосипед. Но...
Что делать, если библиотека не предоставляет достаточных средств для реализации задачи? IMHO Фтьiкай пошёл правильным путём: придумал свой велосипед на гусеничном ходу.
Далее, использование STL запрещено по условиям задания. Как и использование битовых операций. Меня, кстати, больше удивил второй запрет, поскольку битовые операции всегда входили в базовый набор как C++, так и C.
В C++ стандартную си-шную библиотеку ввода-вывода ни кто не отменял и не запрещал. И знать её необходимо. Кстати, многие вещи из STL являются просто надстройкой над стандартной библиотекой: например, тот же потоковый ввод-вывод, или new/delete.
P.S. Согласен с тобой в том, что нужно знать, как работают более низкоуровневые вещи.
Но воспринимать STL, как какую-то «дополнительную библиотеку» языка не стоит.
Без STL конечно можно кодить на плюсах, как на «C с классами», но это уже для каких-то узких задач.
Snoomru, твоя программа ещё одна вариация на тему, о которой я писал ранее (см. 2-3 абзац). Топикстартер подтвердил, что такое решение не удовлетворяет условию задания.
Пока единственное решение, полностью удовлетворяющее условию задания, представил Фтьiкай.
Я очень давно не писал на чистом C, но мне кажется, что enum там нет. По крайней мере, компиляция на ideone.com и http://www.codechef.com в режиме C даёт ошибку на функцию GNENUM get_num(itype *num). Интересно, что строка enum GNENUM { GN_OK = 0, GN_NEG, GN_ILL, GN_LONG }; не вызывает неприязни у компилятора.
Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.
Cranium, последний вариант правильный
Еще есть вариант, не использовать статической переменной. Тогда можно записать аргумент как константную ссылку
selevit, во-первых, инициатор не я, а beginner )))
А во-вторых, тема ещё активна. Оптимальное решение ищется ;)
Мой код лучший
Три строчки в функции. Три! И не нужны никакие массивы.
Илья, если в функции
void dec_to_bin(int const&num)
(1) выражениеnum / 2 >= 1
упростить доnum > 1
, избавившись от лишнего деления, и (2) аргумент передавать не по константной ссылке, а по значению, избавившись от лишней косвенной адресации, то получится практически тот вариант рекурсивной функции, который я опубликовал ранее. Наши решения почти совпали.Второй момент более проблемный и, поскольку задачу ставил не я, адресовать его нужно beginner'у. В условии задачи было ограничение на использование библиотек, и конкретно STL. В твоей программе подзадача «вывести предупреждение и завершить работу, в случае если <вводимое> число превышает кол-во байтов» решается средствами STL. Ибо потоковый ввод-вывод — это фишка чисто из STL.
В других вариантах решения от «различных производителей» (почти во всех) для ввода-вывода тоже используется STL. Но всё-таки делались попытки (разной степени успешности) определить битовый размер вводимого числа. Ты в своём варианте играешь на том, что при вводе числа, превышающего размер переменной-приёмника, функция потокового ввода (из STL) записывает в переменную-приёмник некое магическое значение с установленным старшим битом, которое интерпретируется как отрицательное число, и тут же попадает под нож проверки на отрицательность.
beginner, твоё мнение по данному вопросу?
Слухи о том, что
<stdio.h>
умер, сильно преувеличены ))Просто сейчас почему-то не модно знать стандартную си-шную библиотеку ввода-вывода. Впрочем плюсовую потоковую библиотеку хорошо тоже мало кто знает. Парадокс однако ;)
Вот вариант решения, полностью удовлетворяющий всем условиям задачи. Без ГМО, то есть STL. Только
<stdio.h>
, только хардкор ))На счет вывода в двоичной форме я не стал напрягаться и адаптировал решение от Cranium'а.
Работает с целыми типами размером от 1 до 8 байт. Если процессор/компилятор поддерживает, то можно и длиннее (хе-хе! ;) ). Длина типа задается
typedef
'ом в начале программы: нужно раскомментировать только интересующий typedef.Модно ее использовать в C. В плюсах, в большинстве случаев нужно стараться использовать потоковый ввод-вывод и минимализировать использование сишных строк.
Если кодишь на плюсах, нужно использовать STL. Это касается как использования контейнера
std::string
вместо сишных строк,std::vector
вместо динамических массивов,new
вместоmalloc
и т. п.Это в общем-то не только моя позиция но и Самого.
Ох, Илья, уморил своей версией онлайн разработки
В последней редакции кода (с поправкой на то, что в функции
void dec_to_bin(int const&num)
все-таки ))) можно обойтись без статических переменных) произошло слияние всяческих штучек (типа безусловногоfor
), рекурсии, проверки goodbit, с последующей синхронизацией потока, в дополнение, с очисткой failbit (но при всей этой грозной защите происходит вылет одного цикла программы при вводе вещественного числа) и апофеоз — это завершение программы вводом нуля и похвалой себя любимого.СУПЕР!!!
А теперь, по существу :|
Илья, вы задание читали?
selevit, я согласен с тобой (и с Самим), что при программировании на плюсах надо использовать STL и не изобретать велосипед. Но...
Что делать, если библиотека не предоставляет достаточных средств для реализации задачи? IMHO Фтьiкай пошёл правильным путём: придумал свой велосипед на гусеничном ходу.
Далее, использование STL запрещено по условиям задания. Как и использование битовых операций. Меня, кстати, больше удивил второй запрет, поскольку битовые операции всегда входили в базовый набор как C++, так и C.
В C++ стандартную си-шную библиотеку ввода-вывода ни кто не отменял и не запрещал. И знать её необходимо. Кстати, многие вещи из STL являются просто надстройкой над стандартной библиотекой: например, тот же потоковый ввод-вывод, или
new
/delete
.Правильнее сказать абстракцией. И это удобно, да. Так-то си — это тоже кроссплатформенная надстройка над машинными командами :)
P.S. Согласен с тобой в том, что нужно знать, как работают более низкоуровневые вещи.
Но воспринимать STL, как какую-то «дополнительную библиотеку» языка не стоит.
Без STL конечно можно кодить на плюсах, как на «C с классами», но это уже для каких-то узких задач.
Вот моя программа, думаю все условие выполнил.
Snoomru, твоя программа ещё одна вариация на тему, о которой я писал ранее (см. 2-3 абзац). Топикстартер подтвердил, что такое решение не удовлетворяет условию задания.
Пока единственное решение, полностью удовлетворяющее условию задания, представил Фтьiкай.
Да, мне тоже решение от Фтьiкай очень понравилось. Настоящий HARD CODE.
Добавил в готовые решения программу Фтыкая:
https://code-live.ru/solutions/c/16/
selevit, я это сделал на 10 дней раньше ))))
Ой да, я слоупок :D
Единственное, что это C, а не C++. И описание с точки зрения конечного решения должно быть более лаконичным.
Я оставил второй вариант, а с твоего сделал перенаправление, чтобы существующие ссылки не ломались.
Я очень давно не писал на чистом C, но мне кажется, что
enum
там нет. По крайней мере, компиляция на ideone.com и http://www.codechef.com в режиме C даёт ошибку на функциюGNENUM get_num(itype *num)
. Интересно, что строкаenum GNENUM { GN_OK = 0, GN_NEG, GN_ILL, GN_LONG };
не вызывает неприязни у компилятора.Так что это код, видимо, всё-таки на C++.
PS. Искать последний стандарт C лень ((