C не заботится о строках. На самом деле.
Он рассматривает их как массивы символов. Просто байты в памяти. Чтобы эффективно их использовать, вам нужны указатели. Не потому, что это весело. А потому, что без них вы выполняете лишнюю работу.
Строка в C — это просто char str[100]. Это выглядит как место для 100 символов. Но это не так. Это место для 99 символов плюс терминатор. C использует строки с нуль-терминатором. Каждая строка заканчивается значением ASCII 0. Записывается как '\0'.
Это меняет всё.
Другие языки обрабатывают строки иначе. Pascal использует байт длины. Он точно знает, сколько символов хранится. Спросите длину? Он вернёт этот байт. Мгновенно.
В C приходится считать. Он читает данные, пока не встретит '\0'. Это делает C медленнее в некоторых случаях. Быстрее в других. Всё зависит от того, что вы делаете.
В C нет встроенной поддержки строк. Вы полагаетесь на библиотеки. обрабатывает ввод и вывод, такие функции как gets и puts. обрабатывает манипуляции со строками. Некоторые системы используют . Вы должны управлять памятью самостоятельно. Вы не можете просто присвоить один массив другому.
Вот и всё. Вы копируете элемент за элементом. Или используете strcpy. Функция библиотеки выполняет основную работу.
strcpy повсюду в C. Она инициализирует строки. Копирует данные.
После выполнения этого кода s1 содержит «hello», а s2 также содержит «hello». Массив хранит значения ASCII. Целые числа. h — это 104. e — это 101. C мыслит байтами. Вы мыслите текстом. Машине всё равно.
Сравнение выполняется с помощью strcmp. Она возвращает целое число.
Ноль означает равенство. Отрицательное значение означает, что первая строка меньше. Положительное значение означает, что она больше.
Существуют и другие функции. strlen возвращает длину. strcat выполняет конкатенацию. Если нужно больше информации, прочитайте страницу руководства (man page).
Но как эти функции работают изнутри? Давайте посмотрим на strlen.
Наивный подход выглядит так:
Большинство программистов на C ненавидят этот код. Он кажется неэффективным. Они предпочитают указатели.
Его можно сжать ещё больше.
Настоящий эксперт, вероятно, мог бы сделать его ещё короче.
Я скомпилировал эти варианты на MicroVAX с помощью gcc. Без оптимизации. Каждый вариант выполнялся 20 000 раз на строке длиной 120 символов.
Первый вариант: 12,3 секунды.
Второй вариант: 12,3 секунды.
Третий вариант: 12,9 секунды.
Указатели не всегда побеждают.
Пишите код, который вы понимаете. Читаемость важнее нескольких микросекунд. Если только вы не находитесь в тесном цикле (tight loop). Тогда, возможно, стоит оптимизировать.
strcpy проходит аналогичную эволюцию.
Начнём с очевидного:
Обратите внимание на <=. Он копирует '\0'. Если пропустить его, у строки не будет конца. Неизвестная длина. Баги позже. Их трудно найти.
Эта версия неэффективна. strlen вызывается на каждой итерации. Вызовите её один раз.
Теперь указатели.
Сожмите его.
Чисто. Быстро. Опасно, если не проверять границы.
Вот как работают строки в C. Никакой магии. Просто память и указатели. И много аккуратного подсчёта.
Указатели против производительности в strcpy
Технически вы можете написать while (*s1++ = *s2++); для обработки копирования строк. Разрыв в производительности между наивными реализациями и оптимизированными ошеломляет.
Возьмите strcpy. Первая версия занимает 415 секунд для копирования строки из 120 символов 10 000 раз. Вторая версия? 14,5 секунды. Третья снижается до 9,8 секунды. Четвертая стабилизируется на отметке 10,3 секунды.
Это не незначительная разница. Это огромный прирост скорости. Указатели обеспечивают эту скорость, поскольку они устраняют ненужные накладные расходы.
Типы возвращаемых значений и указатели на строки
Прототип strcpy в библиотеке строк раскрывает его назначение:
Большинство функций работы со строками возвращают указатель на строку. strcpy возвращает значение s1 в качестве результата. Это позволяет выполнять цепочку операций или немедленно использовать скопированную строку без дополнительного поиска.
Удаление ведущих пробелов без перемещения данных
Использование указателей со строками часто приводит к определенному улучшению скорости. Вы можете воспользоваться этим, если немного поразмыслите.
Предположим, вы хотите удалить ведущие пробелы из строки. Инстинкт подсказывает сдвигать символы, перезаписывая пробелы. В C вы можете полностью избежать перемещения.
Это намного быстрее, чем техника сдвига. Особенно для длинных строк. Вы не сдвигаете байты. Вы просто изменяете начальный указатель. Данные остаются на месте. Вывод меняется.
Освоение приемов
Вы освоите множество других приемов со строками по мере продвижения. Вы будете читать другой код. Вы увидите, как другие работают с памятью.
Практика — ключ к успеху. Нет короткого пути для чтения кода. Вам просто нужно смотреть, как это делается, и понимать, почему это работает. Прирост производительности реален. Кривая обучения крутая. Но результаты говорят сами за себя.



























