Я столкнулся с вопросом программирования, на который я знал только часть ответа.
int f( char *p )
{
int n = 0 ;
while ( *p != 0 )
n = 10*n + *p++ - '0' ;
return n ;
}
Это то, что я думаю, что программа делает.
p — указатель, а цикл while — DE-повторное сопоставление значений указателя, пока он не станет равным 0. Однако я не понимаю строку присваивания n, что делает ‘0’? Я предполагаю, что значение p изначально отрицательно, это единственный способ, которым оно достигнет 0 после приращения.
Вы путаете число ноль (нет, ничего) с символом 0
(круг, возможно, с косой чертой). Обратите внимание, что ноль находится в отметках, поэтому это символ «0», а не ноль.
«0» — «0» = 0
«1» — «0» = 1
‘2’ — ‘0’ = 2
…
Таким образом, вычитая персонаж ноль от цифры, вы получите число, соответствующее этой цифре.
Итак, скажем, у вас есть эта последовательность цифр: «4», «2», «1». Как вы получаете число четыреста двадцать один из этого? Вы превращаете «4» в четыре. Затем вы умножаете на десять. Теперь у вас есть сорок. Преобразуйте «2» в два и добавьте. Теперь у вас есть сорок два. Умножьте на десять. Преобразуйте «1» в один и добавьте, теперь у вас есть четыреста двадцать один.
Вот как вы преобразуете последовательность цифр в число.
n
Локальная переменная накапливает значение десятичного числа, которое передается этой функции в строке. Это реализация atoi
, без проверки действительности.
Вот работа тела цикла:
n = 10*n + *p++ - ‘0';
Назначить на n
результат умножения предыдущего значения n
на десять плюс текущий код символа у указателя p
меньше кода ноль; приращение p
после разыменования.
Поскольку цифровые символы кодируются последовательно, *p-'0'
выражение представляет собой десятичное значение цифры.
Допустим, вы разбираете строку "987"
, Как вы проходите через цикл, n
начинается с нуля; тогда ему присваиваются следующие значения:
n = 10*0 + 9; // That's 9
n = 10*9 + 8; // That's 98
n = 10*98 + 7; // That's 987
Это плохо написано, если не сказать больше.
0) Используйте форматирование !:
int f(char* p)
{
int n = 0;
while (*p != 0)
n = 10*n + *p++ - ‘0?;
return n;
}
1) ?
там синтаксически неверно. Это должно быть '
как отметил Крис (и ваши существующие ‘
тоже неправильно, но это, вероятно, потому что вы скопировали его с веб-сайта, а не из исходного файла), давая:
int f(char* p)
{
int n = 0;
while (*p != 0)
n = 10 * n + *p++ - '0';
return n;
}
2) Тип параметра не так ограничен, как должно быть. Так как *p
никогда не изменяется (в соответствии с нашими целями), мы должны обеспечить это, чтобы убедиться, что мы не делаем ошибок:
int f(const char* p)
{
int n = 0;
while (*p != 0)
n = 10 * n + *p++ - '0';
return n;
}
3) У оригинального программиста была явно аллергия на читаемый код. Давайте разделим наши операции:
int f(const char* p)
{
int n = 0;
for (; *p != 0; ++p)
{
const int digit = *p - '0';
n = 10 * n + digit;
}
return n;
}
4) Теперь, когда операции немного более заметны, мы можем увидеть некоторые независимый функциональность, встроенная в эту функцию; это должно быть выделено (это называется реагированием) в отдельную функцию.
А именно, мы видим операцию преобразование символа в цифру:
int todigit(const char c)
{
// this works because the literals '0', '1', '2', etc. are
// all guaranteed to be in order. Ergo '0' - '0' will be 0,
// '1' - '0' will be 1, '2' - '0' will be 2, and so on.
return c - '0';
}
int f(const char* p)
{
int n = 0;
for (; *p != 0; ++p)
n = 10 * n + todigit(*p);
return n;
}
5) Итак, теперь ясно, что функция читает строку символ за символом и генерирует число цифра за цифрой. Этот функционал уже существует под именем atoi
и эта функция небезопасна:
int todigit(const char c)
{
// this works because the literals '0', '1', '2', etc. are
// all guaranteed to be in order. Ergo '0' - '0' will be 0,
// '1' - '0' will be 1, '2' - '0' will be 2, and so on.
return c - '0';
}
int atoi_unsafe(const char* p)
{
int n = 0;
for (; *p != 0; ++p)
n = 10 * n + todigit(*p);
return n;
}
Это оставлено в качестве упражнения для чтения для проверки на переполнение, недопустимые символы (те, которые не являются цифрами) и так далее. Но это должно прояснить, что происходит, и то, как такая функция должна была быть написана с самого начала.
Это функция преобразования строки в число. Похожий на atoi.
Строка — это последовательность символов. Так что «123» в памяти будет:
‘1’, ‘2’, ‘3’, NULL,
р указывает на это.
Теперь, согласно ASCII, цифры кодируются от «0» до «9». «0» присваивается значение 48, а «9» присваивается значение 57. Таким образом, «1», «2», «3», NULL в памяти на самом деле: 49, 50, 51, 0
Если вы хотите преобразовать из символа «0» в целое число 0, вам придется вычесть 48 из значения в памяти. Вы видите, куда это идет?
Теперь вместо вычитания числа 48 вы вычитаете «0», что облегчает чтение кода.