Как видно из опубликованных ответов, это, на удивление, нетривиальная задача. Столкнувшись с такой задачей, может показаться, что многие программисты предпочитают выбрасывать из окна здравый смысл, чтобы создать самый непонятный фрагмент кода, который только можно придумать.
Что нужно учитывать:
- Вы захотите сделать копию строки с удаленными пробелами. Изменение переданной строки - плохая практика, это может быть строковый литерал. Кроме того, иногда есть преимущества обработки строк как неизменных объектов .
- Вы не можете предполагать, что исходная строка не пуста. Он может содержать только один нулевой символ завершения.
- Буфер назначения может содержать любой неинициализированный мусор при вызове функции. Проверка его на нулевое завершение не имеет никакого смысла.
- В документации по исходному коду должно быть указано, что буфер назначения должен быть достаточно большим, чтобы содержать обрезанную строку. Самый простой способ сделать это - сделать его равным строке без полей.
- В целевом буфере должна быть строка с нулевым символом в конце без пробелов после завершения функции.
- Подумайте, хотите ли вы удалить все пробельные символы или только пробелы
' '
.
- Программирование на C - это не соревнование за то, кто может втиснуть как можно больше операторов в одну строку. Скорее наоборот, хорошая программа на C содержит читаемый код (всегда самое важное качество) без ущерба для эффективности программы (что несколько важно).
- По этой причине вы не получаете бонусных баллов за сокрытие вставки нулевого завершения строки назначения, позволяя ему быть частью кода копирования. Вместо этого сделайте явную вставку нулевого завершения, чтобы показать, что вам просто не удалось сделать это случайно.
Что бы я сделал:
void remove_spaces (char* restrict str_trimmed, const char* restrict str_untrimmed)
{
while (*str_untrimmed != '\0')
{
if(!isspace(*str_untrimmed))
{
*str_trimmed = *str_untrimmed;
str_trimmed++;
}
str_untrimmed++;
}
*str_trimmed = '\0';
}
В этом коде исходная строка "str_untrimmed" оставлена нетронутой, что гарантируется использованием правильной константной корректности. Не происходит сбой, если исходная строка не содержит ничего, кроме нулевого завершения. Это всегда нуль заканчивает строку назначения.
Выделение памяти оставлено вызывающей стороне. Алгоритм должен только сосредоточиться на выполнении своей намеченной работы. Удаляет все пробелы.
В коде нет хитрых трюков. Он не пытается втиснуть как можно больше операторов в одну строку. Это сделает очень плохим кандидатом на IOCCC . Тем не менее, он выдаст почти тот же машинный код, что и более неясные однострочные версии.
При копировании чего-либо вы можете немного оптимизировать, объявив оба указателя как restrict
, что является контрактом между программистом и компилятором, где программист гарантирует, что адресат и источник не имеют одинаковый адрес (или, скорее, что данные, на которые они указывают, доступны только через этот самый указатель, а не через какой-либо другой указатель). Это обеспечивает более эффективную оптимизацию, поскольку компилятор может копировать прямо из источника в место назначения без временной памяти между ними.