Я пытаюсь улучшить свое понимание C ++, особенно арифметику указателей. Я часто использую atoi, но я редко задумывался о том, как это работает. Глядя на то, как это делается, я в основном понимаю, но есть одна вещь, которая меня смущает.
Вот пример решения, которое я нашел онлайн:
int atoi( char* pStr )
{
int iRetVal = 0;
if ( pStr )
{
while ( *pStr && *pStr <= '9' && *pStr >= '0' )
{
iRetVal = (iRetVal * 10) + (*pStr - '0');
pStr++;
}
}
return iRetVal;
}
Я думаю, что главная причина, по которой мне было трудно понять, как это делалось в прошлом, — это сравнение персонажей. В то время как заявление говорит пока персонаж существует, а также символ меньше или равен 9, а также больше или равно 0 тогда делай вещи Это утверждение говорит мне о двух вещах:
Прежде чем я изучил это, я предполагал, что знал это подсознательно, но на самом деле я никогда не думал об этом, но символ «5» «меньше», чем символ «6» так же, как 5 меньше 6, так что вы можете сравнить символы как целые числа, по существу (для этого намерения).
Редактировать: я понятия не имею, что * pStr — ‘0’ часть сделает.
Любая помощь в осмыслении этих наблюдений была бы очень … полезной! Спасибо!
Символ в C представлен просто как значение ASCII. Поскольку все цифры являются последовательными в ASCII (то есть 0x30 == ‘0’ и 0x39 == ‘9’ со всеми другими цифрами между ними), вы можете определить, является ли символ цифрой, просто выполнив проверку диапазона, и вы можно получить значение цифры путем вычитания '0'
,
пока персонаж существует
Нет, не совсем. Он говорит: «пока символ не 0 (или '\0'
). В основном, ASCII персонаж '\0'
указывает на конец строки «C». Поскольку вы не хотите проходить через конец массива символов (а точная длина неизвестна), каждый символ проверяется на '\0'
,
Символы можно сравнивать с другими персонажами логически
Вот так. Символ не что иное, как число, ну, по крайней мере, в кодировке ASCII. В ASCII, например, '0'
соответствует десятичному значению 48
, '1'
49, 'Z'
90 (вы можете посмотреть на Таблица ASCII здесь). Так что да, вы можете сравнивать символы так же, как вы сравниваете целые числа.
как-то
while (*sPtr)
а также*sPtr != 0
разные.
Не отличается вообще. Десятичный 0 — это специальный символ ASCII (nul)
это используется для обозначения конца строки «C», как я уже упоминал в начале. Вы не можете видеть или печатать (nul)
, но это там.
* PStr — ‘0’ преобразует символ в его числовое значение ‘1’ — ‘0’ = 1
Цикл while проверяет, не находимся ли мы в конце строки и имеем ли мы правильную цифру.
Обратите внимание, что опубликованная реализация atoi не завершена. Настоящий атой может обрабатывать отрицательные значения.
Каким-то образом while (* sPtr) и * sPtr! = 0 различаются.
Эти два выражения одинаковы. Когда используется как условие, *sPtr
считается истинным, если значение, хранимое по адресу sPtr, не равно нулю, и *sPtr != 0
Значение true, если значение, хранящееся по адресу sPtr, не равно нулю. Разница заключается в том, что при использовании в другом месте второе выражение оценивается как истинное или ложное, а первое — как сохраненное значение.
Струны в стиле C завершающий нуль.
Следовательно:
while ( *pStr && *pStr <= '9' && *pStr >= '0' )
Это тесты:
*pStr
что мы еще не достигли конца строки и эквивалентны записи *pStr != 0
(примечание без одинарных кавычек, значение ASCII 0
, или же NUL
).*pStr >= '0' && *pStr <= '9'
(возможно, более логично), что персонаж в *pStr
находится в диапазоне '0'
(Значение ASCII 48
) чтобы '9'
(Значение ASCII 57
), то есть цифра.Представление '0'
в память о 0x30
и представление '9'
является 0x39
, Это то, что видит компьютер, и когда он сравнивает их с логическими операторами, он использует эти значения. Обнуляемый символ представлен как 0x00
, (иначе ноль). Ключевым моментом здесь является то, что chars
как и любой другой int
к машине.
Следовательно while
Заявление говорит:
Пока исследуемый символ действителен (он же НЕ равен нулю и, следовательно, НЕ является нуль-терминатором), и его значение (как его видит машина) меньше 0x39, а его значение больше 0x30, продолжайте.
Тело while
Затем цикл вычисляет соответствующее значение для добавления к аккумулятору на основе целочисленной позиции в строке. Затем он увеличивает указатель и уходит снова. Как только это сделано, он возвращает накопленное значение.
Этот кусок кода использует значения ascii для накопления целого числа его альфа-эквивалента.
Что касается вашей первой пронумерованной пули, кажется довольно тривиальным, что при сравнении чего-либо результат является логическим. Хотя я чувствую, что вы пытались спросить, понимает ли компилятор «символы». Насколько я понимаю, это сравнение сделано с использованием ascii значений символов. то есть < б интерпретируется как (97 < 98).
(Обратите внимание, что также легко увидеть, что значения ascii используются, когда вы сравниваете «a» и «A», так как «A» меньше, чем «a»)
Что касается вашего второго маркера, то кажется, что цикл while проверяет, что на самом деле существует назначенное значение, которое не равно NULL (ascii значение 0). Оператор and выдает FALSE, как только встречается ложное утверждение, так что вы не будете сравнивать NULL-символ. Что касается остальной части цикла while, он выполняет сравнение ascii, как я уже упоминал о пуле 1. Он просто проверяет, соответствует ли данный символ значению ascii, связанному с числом. то есть между ‘0’ и ‘9’ (или ascii: между 48 и 57)
НАКОНЕЦ
(* ptr-‘0 ‘), на мой взгляд, самая интересная часть. Этот оператор возвращает целое число от 0 до 9 включительно. Если вы посмотрите на таблицу ASCII, вы заметите, что цифры от 0 до 9 находятся рядом друг с другом. Итак, представьте «3» — «0», который равен 51 — 48 и производит 3! : D Таким образом, в более простых сроках, это делает вычитание ascii и возвращает соответствующее целочисленное значение. : D
Ура, и я надеюсь, что это немного объясняет
Давайте разберемся с этим:
if ( pStr )
Если вы передадите Atoi нулевой указатель, pStr
будет 0x00
— и это будет ложным. В противном случае нам есть что разбирать.
while ( *pStr && *pStr <= '9' && *pStr >= '0' )
Хорошо, здесь происходит куча вещей. *pStr
означает, что мы проверяем, если значение pStr указывает на 0x00
или нет. Если вы посмотрите на таблицу ASCII, ASCII для 0x00
имеет значение ‘null’, и в C / C ++ соглашение заключается в том, что строки заканчиваются нулем (в отличие от строк в стиле Pascal и Java, которые сообщают вам, что их длина имеет столько символов). Так когда *pStr
оценивается как ложное, наша строка подошла к концу, и мы должны остановиться.
*pStr <= '9' && *pStr >= '0'
работает, потому что значения символов ASCII ‘0’ ‘1’ ‘2’ ‘3’ ‘4’ ‘5’ ‘6’ ‘7’ ‘8’ ‘9’ являются смежными — ‘0’ — это 0x30
и «9» 0x39
, например. Так что если pStr
указывает на значение вне этого диапазона, тогда мы не анализируем целое число, и мы должны остановиться.
iRetVal = (iRetVal * 10) + (*pStr - '0');
Поскольку свойства чисел ASCII непрерывны в памяти, бывает так, что если мы знаем, что у нас есть число, *pStr - '0'
оценивает к его числовому значению — 0 для ‘0’ (0x30 - 0x30
), 1 для «1» (0x31 - 0x30
) … 9 за «9». Поэтому мы сдвигаем наш номер вверх и скользим на новом месте.
pStr++;
Добавляя единицу к указателю, указатель указывает на следующий адрес в памяти — следующий символ в строке, которую мы преобразуем в целое число.
Обратите внимание, что эта функция испортится, если строка не оканчивается нулем, у нее есть любые цифры (например, ‘-‘) или если она не является ASCII в любом случае. Это не волшебство, оно просто полагается на правду.