Skip to content

Instantly share code, notes, and snippets.

@sbogolepov
Last active December 26, 2015 15:19
Show Gist options
  • Save sbogolepov/7172074 to your computer and use it in GitHub Desktop.
Save sbogolepov/7172074 to your computer and use it in GitHub Desktop.
For one pretty girl
#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