Обрезка строки, почему после цикла while есть точка с запятой?
Поэтому я читал некоторый код из моего курса C-программирования и наткнулся на этот вопрос:
Обрезать строку: " make trim "
в "make trim"
, Это был код:
#include <stdio.h>
#include <string.h>
#define MAX 100
void trim(char *s) {
char *d = s;
while (isspace(*s++))
;
s--;
while (*d++ = *s++)
;
d--;
while (isspace(*--d))
*d = 0;
}
int main() {
char s[MAX];
gets(s);
printf("[%s] -> ", s);
trim(s);
printf("[%s]", s);
return 0;
}
Итак, я хочу спросить, каковы
while (isspace(*s++))
;
s--;
while (*d++ = *s++)
;
d--;
while (isspace(*--d))
*d = 0;
увеличенная строка (*s++)
, ;
после выполнения цикла while(), и как они работают?
заранее спасибо
3 ответа
Пустое тело просто потому, что состояние while
имеет побочный эффект, поэтому весь цикл инкапсулируется в условии, и в теле нет ничего, что можно было бы вставить.
Так:
while (isspace(*s++))
;
Такой же как:
while (isspace(*s)) { s++; }
Они ставят точку с запятой на дополнительной строке, чтобы было понятнее, что цикл пуст (иначе вы можете подумать, что следующий реальный оператор является частью цикла). Другие люди могут также оставить комментарий или даже переписать его, чтобы тело не было пустым.
Код с некоторыми описательными комментариями:
Этот цикл забирает каждый символ по очереди s
указывать на следующее и продолжать делать это до тех пор, пока выбранный нами символ не станет пробелом. Обратите внимание, что, поскольку он увеличивается до теста, он будет увеличиваться s
один раз слишком много, поэтому после окончания цикла есть декремент.
while (isspace(*s));
s--;
Это было бы эквивалентно и не требует отдельного декремента:
while (isspace(*s)) { s++; }
Этот цикл копирует каждый символ из s
поэтому начиная с первого непробельного символа d
который указывает изначально в начале строки. Если не было начальных пробелов, он копирует персонажа прямо поверх себя. Цикл заканчивается после того, как мы скопировали нулевой символ, то есть конец строки. Как и прежде, есть один шаг слишком много, поэтому мы должны уменьшить d
для конечной точки на нулевом символе:
while (*d++ = *s++)
;
d--;
Этот цикл уменьшает d
а затем подбирает любого персонажа, на которого он сейчас указывает. Если это символ пробела, он заменяет его нулевым символом. Обратите внимание, что нет проверки на попадание в начало строки, поэтому, если начальная строка была пустой (т. Е. Один нулевой символ), она с радостью будет работать в обратном направлении через повреждающие память байты вне строки, пока они являются пробелами:
while (isspace(*--d))
*d = 0;
Вы можете переписать:
while (condition);
следующее:
while (condition) { /* empty block */ }
Если condition
содержит операторы, которые должны быть выполнены, они будут выполняться и оцениваться до тех пор, пока выполняется условие, это имеет место в вашем примере.
1. В вашем случае первый цикл while:
while (isspace(*s++));
зацикливается, пока не найдет первый символ без пробела (в данном случае это m make). Поскольку существует постфиксный инкремент, он будет указывать на make:
" make trim \0"
^ ^
d| s|
2. После этого s
уменьшается (s--;
) указывая на начало (м марки).
" make trim \0"
^ ^
d| s|
3. Второй цикл while записывает строку, начинающуюся с make, в начало символьного буфера, потому что d
указывает на начало, потому что оно установлено в начале функции (char *d = s;
). Это делается до нулевого терминатора '\0'
достигается:
while (*d++ = *s++)
может быть переписан как:
while ((*d++ = *s++) != '\0')
и приведет к (обратите внимание, что нулевой терминатор '\0'
тоже написано)
"make trim \0 \0"
^ ^
d| s|
4. Теперь d будет уменьшаться (d--;
) указывая на пробел перед нулевым терминатором '\0'
,
"make trim \0 \0"
^ ^
d| s|
5. Последний цикл while будет искать первый символ без пробела (с d
) но в обратном порядке:
while (isspace(*--d))
*d = 0;
Он будет писать несколько нулевой терминатор '\0'
пока он не найдет персонажа без пробела.
"make trim\0\0\0\0 \0"
Таким образом, полученная строка будет:
"make trim"
Нет необходимости писать несколько нулевых терминаторов '\0'
здесь, но вместо этого один нулевой терминатор '\0'
будет достаточно после м отделки.
while (isspace(*s++))
;
просто равно
while (isspace(*s++));
Не позволяй ;
на новой линии вас смущают. В целом, это просто способ подчеркнуть, что это while
петля не имеет тела. И while
цикл, который не имеет тела, выполняет, пока isspace(*s++)
условие ложное. Также isspace(*s++)
это единственный расчет, который должен быть выполнен для этого цикла, поэтому нет необходимости иметь тело для этого цикла.
Когда вы читаете такой код, это легко пропустить ;
и тогда вы можете сделать неверное предположение, что выражение непосредственно под циклом является телом цикла, но не окружено {}
:
while (isspace(*s++));
s--;
while (isspace(*s++))
s--;
Увидеть разницу? Во втором примере s--
это while
тело петли. Для привлечения внимания программист может написать:
while (isspace(*s++))
;
s--;
уточнить и подчеркнуть его настоящие намерения.