Основная идея этого кода состоит в том, чтобы работать в два прохода:
- На первом проходе мы получаем указатель на последний символ строки.
- Во втором проходе мы переворачиваем строку, помогая узнать, где заканчивается строка.
Этот первый проход задается следующей логикой:
char *end = str;
while (*end) {
++end;
}
--end;
ThisЦикл while
начинается с указателя end
, указывающего на начало строки.Затем он непрерывно продвигает указатель end
на один шаг вперед, пока условие цикла *end
больше не переходит в истинное значение.Поскольку строки C заканчиваются нулем, условие цикла будет иметь значение true, пока указатель end
указывает где-то в середине строки, а не на нулевой терминатор в конце строки.Таким образом, когда этот цикл завершится, указатель end
пройдёт весь путь до конца строки и остановится на нулевом терминаторе.Затем мы выполняем --end
для резервного копирования указателя на один шаг.На данный момент указатель end
указывает на самый последний символ в строке.Вот пример с «Hello:»
H e l l o
^ ^
| |
str end
Теперь, когда у нас есть этот end
указатель, мы фактически запускаем логику для обращения строки.Это задается этим кодом:
while (str < end) {
tmp = *str;
*str++ = *end;
*end-- = tmp;
}
Идея этого кода состоит в том, что пока начальные и конечные указатели строки не пересекутся друг с другом, мы поменяем значения, на которые они указывают, затем переместим двауказатели внутрь друг к другу.Если мы переписываем это в эквивалент чуть более многословно
while (str < end) {
tmp = *str;
*str = *end;
*end = tmp;
++str;
--end;
}
Тогда, возможно, будет немного легче увидеть, как это работает.Первые три строки этого измененного цикла обмениваются значениями, на которые указывают указатели начала и конца, а следующие две строки перемещают указатели внутрь.Вот пример:
H e l l o
^ ^
| |
str end
o e l l H
^ ^
| |
str end
o l l e H
^
|
str end
На этом этапе два указателя встречаются, и мы правильно перевернули строку.
Обратите внимание, что есть необычный крайний случай, который мы должны принять во внимание здесьи вот что происходит, когда строка является пустой строкой.Если это произойдет, то первый цикл будет вести себя немного странно.В частности, этот код:
char *end = str;
while (*end) {
++end;
}
--end;
никогда не выполнит тело цикла, потому что указатель end
начнет указывать на нулевой терминатор.Следовательно, цикл ничего не делает, и мы заканчиваем резервным копированием end
за один шаг до начала строки! Это неверный указатель, и разыменование его приведет к неопределенным результатам.Но, к счастью, в этом случае ничего не происходит, потому что цикл обращения строки имеет следующее условие:
while (str < end)
Это сразу ложно, если end
- один шаг до начала строки, поэтому ничего не происходит.
Надеюсь, это поможет!