Last active
December 26, 2015 15:19
-
-
Save sbogolepov/7172074 to your computer and use it in GitHub Desktop.
For one pretty girl
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "convertor.h" | |
//Converting sign of digit ("A") to digit itself (10); | |
int char_to_value (char ch) { | |
//Первый случай: Буква большая. Тогда возвращаем разницу | |
//между кодами ch и 'A' и прибавляем десятку. | |
//Пример (ch = 'F'): 'F' - 'A' + 10 = 70 - 65 + 10 = 15 | |
if (isupper (ch)) | |
return ch - 'A' + 10; | |
//Аналогично. | |
if (islower (ch)) | |
return ch - 'a' + 10; | |
//Если if'ы не сработали, то ch - цифра. | |
//Просто возвращаем разницу между кодами. | |
return ch - '0'; | |
} | |
//Converting integer value to to it's sign. | |
char digit_to_char (int digit) { | |
//В общем-то, аналогично предыдущей функции. | |
if (digit > 9) | |
return digit + 'A' - 10; | |
return digit + '0'; | |
} | |
//Converting string to array of digits | |
//Звёздочка означает, что возвращаем массив, точнее, указатель на его первый элемент. | |
//В Си мы не можем возвращать/ принимать в качестве параметра массивы, только указатели | |
//На их первые элементы | |
int *number_to_array (char *number) { | |
//Узнаем длину данного массива. | |
size_t size = strlen (number);//size_t аналогичен int. | |
//Новый массив аналогичен по длине данному. Зачем + 1? | |
//В конец нового массива мы запихиваем -1, чтобы использовать как символ конца массива | |
//(Аналогично '\0' в строках) | |
//sizeof() - функция, возвращающая количество байт для хранения такого-то типа данных. | |
//В целом, это аналогично такой записи: | |
// int digits[size+1]. | |
int *digits = malloc (sizeof (int) * (size + 1)); | |
int i; | |
//Переводим поэлементно массив символов в массив цифр. | |
for (i = 0; i < size; i++) { | |
digits[i] = char_to_value (number[i]); | |
} | |
//Добавляем в конец -1 | |
digits[size] = -1; | |
//Возвращаем указатель на первый элемент | |
return digits; | |
} | |
//Protection from dummies. | |
//Проверка корректности ввода (чтобы не было 17 при 16-сс) | |
//base - данное основание. | |
int is_valid_number (int *digits, int base) { | |
int i = 0; | |
//Пока мы не дошли до конца массива... | |
while (digits[i] != -1) { | |
//Если 17 при 16-сс, то возвращаем 0. Пользователь - лох и ввёл некоректные данные | |
if (digits[i] >= base) { | |
return 0; | |
} | |
//Иначе переходим к следующему элементу | |
i++; | |
} | |
return 1; | |
} | |
//Half-step of convertion. | |
//Сначала нужно перевести полученный массив в десятичное число | |
// *err - защита от переполнения. Например, если изначально было дано число | |
// FFFFFFFFFFF, то мы не сможем запихнуть его в одну ячейку памяти. | |
// Почему указатель? Потому что мы изменяем внешнюю переменную. | |
unsigned int convert_to_ten_base (int *digits, int base, int *err) { | |
int length = 0; | |
//unsigned даёт в два раза больше места | |
//диапазон значений как бы смещается вправо | |
unsigned int result = 0; | |
int i = 0; | |
//0 - опереполнения пока нет, всё круто. | |
*err = 0; | |
//Length of array. You know. | |
while (digits[length] != -1) length++; | |
//Суммируем элемнты массива в result. | |
while (i < length) { | |
//UINT_MAX - константа, которая хранит максимальное значение unsigned int. | |
//Находится в <limits.h> | |
//В условии if'a проверка на переполнение | |
// pow - функция, возводящая первый аргумент в степень второго аргумента | |
// pow (2,4) вернёт 16.0 | |
// Да, pow возвращает тип double, а не int. | |
// Если перед pow (2,4) написать (int), то тогда получим 16. | |
// Это называется приведением типов. | |
//Диапазон значений unsigned int - От 0 до 4 294 967 295. В UINT_MAX хранится последнее. | |
//Почему неравентво выглядит так? | |
//Потому что если бы мы написали result + digits[i] * канитель > UINT_MAX, | |
//То в случае слишком большого значения левой части неравенства всегда бы возвращалась ложь, | |
//Так как когда мы достигаем 4 294 967 295, происходит переполнение и сумма становится равна | |
//минимальному значению int (что-то очень маленькое) + разница между максимальным значением int | |
//и значением суммы. | |
if (result > UINT_MAX - digits[i] * (int) pow (base, length - 1 - i)) { | |
//Оп, переполнение. То есть данное значение не влезает в ячейку памяти. | |
//Меняем внешнюю переменную. | |
*err = 1; | |
//Возвращаем -1 (можно любое значение, главное - выйти из функции) | |
return -1; | |
} | |
//Круто, ошибки нет. Добавляем элемент массива в такой-то степени в result | |
// result += x аналогична result = result + x. | |
//Такой алгоритм перевода был в Б-части ЕГЭ, должно быть знакомо | |
result += digits[i] * (int) pow (base, length - 1 - i); | |
//Переход к следующему элементу. | |
i++; | |
} | |
//Возвращаем полученное число. | |
return result; | |
} | |
//Another half-step. We are not calling it if target base is 10. | |
//Финальный рывок. | |
//Возвращаем массив символов | |
//value - полученное в предыдущей функции значение | |
//base - b2 | |
// Эта функция вынесет тебе мозг, да. Но я сделаю всё возможное, чтобы было понятно. | |
char *convert_from_ten_base (unsigned int value, int base) { | |
int i = 0; | |
int length; | |
//Пока что ответ у нас всего лишь единичной длины. | |
char *result = malloc (sizeof (char) * (i + 1)); | |
char *answer; | |
//Этот массив возвращает необходимое число в обратном порядке. | |
//Почему? Потому что я криворукий олень. | |
// Почему do-while, а не while? Потому что я криворукий олень. | |
// do-while отличается только тем, что он сначала выполняет тело цикла, а уже затем проверяет условие. | |
// Сначала делает, потом думает. | |
do { | |
//с каждым проходом цикла result увеличивается на один элемент, | |
//Поэтому нужно заново инициализировать result. | |
result = realloc (result, sizeof (char) * (i + 1)); | |
// % - остаток от деления. | |
// О, придумал метафоту. Представь, что value - наш любимый банан, | |
// А result - коробка с ячейками. Так вот, мы отрезаем заднюю часть банана, | |
// И кладем ее в первую ячейку коробки | |
result[i] = digit_to_char (value % base); | |
//Постепенно переходим к носу банана. | |
// value /= base аналогично value = value / base. | |
// Кстати, это возвращает целую часть от деления. | |
// То есть 10 / 3 = 3. | |
value /= base; | |
//А тут - к следующей ячейке. | |
//Заодно в i накапливается количество ячеек, то есть длина массива. | |
i++; | |
} while (value != 0);// Та-да-дам! Целая часть от деления равна 0. | |
//We need to rotate result. | |
//answer - такая же коробка, но теперь мы перекладываем элементы в обратном порядке | |
//Последний стал первым и так далее. | |
//i у нас меняется в цикле, поэтому сохраням ее значение в length. | |
length = i; | |
answer = malloc (sizeof (char) * length); | |
//i-- аналогично i = i - 1. То есть у нас i меняется прямо в скобках. | |
while (i--) { | |
answer[length - 1 - i] = result[i]; | |
} | |
return answer; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment