Я получил от Антона Александровича (преподавателя из НИИТа) несколько замечаний по решению этой задачи:
1. Бесконечный цикл while(1) можно заменить на цикл while(charray [i]).
Известно, что строка (в отличии от массива символов) всегда заканчивается нулевым символом, он же '\0'. Так же известно, что 0 (ноль) в языке Си (да и во многих других ЯП) означает "ложь" (false). Исходя из этих двух фактов становится ясно, что я могу использовать проверку кода i-того символа из строки в условии завершения цикла while().
while('\0' != charray[i]) {
...
i++;
}
Проверку условия можно упростить следующим образом:
а) while('\0' != charray[i]) - цикл выполняется, пока i-й элемент строки не равен символу '\0'
б) while(0 != charray[i]) - цикл выполняется, пока i-й элемент строки не равен нулю
в) while(charray[i]) - цикл выполняется, пока проверка i-го элемента не возвращает значение "false".
Очевидно, что вышеперечисленные варианты равнозначны. Однако, вариант "в" работает не хуже варианта "а", а если нет разницы - то зачем писать больше? Поэтому, в конечном счёте я использовал вариант "в".
Использование вместо бесконечного цикла while(1) цикл с проверкой i-того элемента строки на соответствие нулевому символу позволило избавиться от двух строк в теле цикла:
if(i == len)
break;
Понятно, что теперь эти строки не нужны, т.к. цикл завершится, когда проверка charray[i] вернёт "false".
2. Из функций можно выкинуть переменную len2.
Возьму для примера функцию удаления лишних пробелов.
int remove_n(char *arr, int len, int pos) {
int i;
int len2 = len-1;
for(i = pos; i <= len2; i++)
arr[i] = arr[i+1];
return 0;
}
Я использовал дополнительную переменную len2 для сохранения результата вычисления len-1, чтобы не вычислять это значение при каждой итерации в цикле for(). Как я понимаю, в данном случае использование len2 излишне, и цикл можно переписать следующим образом:
for(i = pos; i <= len-1; i++)
arr[i] = arr[i-1];
Использование промежуточной переменной для хранения результатов вычислений, которые используются в проверке условия завершения цикла или в теле цикла, оправдано в случае, если эти вычисления достаточно сложны. Или же результат вычисления используется несколько раз в теле цикла. Ещё одна цель использования промежуточных переменных - улучшение читаемости программ человеком (если формулы вычислений достаточно сложны).
3. Проверка на наличие лишнего пробела, после работы конечного автомата, не является "костылём"
После размышлений, я понял, почему конечный автомат не может удалить все пробелы в конце строки. Рассмотрим два случая:
_______________________
1. | * | * | * | * | | 0 |
-----------------------
^
_______________________
2. | * | * | * | | | 0 |
-----------------------
^
Конечный автомат находится в состоянии STATE_1, т.е. ждёт появления в строке пробела. В первом случае, теоретически я могу модернизировать программу следующим образом:
while(charray[i])
switch(state) {
case STATE_1:
if(' ' == charray[i]) {
state = STATE_2;
if((0 == i) || !charray[i+1])) // <-- здесь
continue;
}
break;
case STATE_2:
...
break;
}
i++;
}
...
То есть, если символ, находящийся в строке на позиции i+1 является нулём, я перехожу к следующей итерации цикла while(charray[i]) без инкремента i. Таким образом, я могу удалить последний пробел тем же способом, что я удаляю все пробелы в начале строки.
Но если я попробую использовать приведённый выше код для второго варианта (когда пробелов в конце строки больше 1), то опять же получу один лишний пробел в конце строки после работы программы. Почему? А потому, что условие !charray[i+1] никогда не выполнится уже в том случае, если количество пробелов в конце строки будет хотя бы равно двум: элемент строки, находящийся на позиции i+1, так же будет являться пробелом.
Поэтому я согласен с Антоном Александровичем, что проверка на наличие лишнего пробела после работы конечного автомата не является "костылём", а всего лишь дополняет решение задачи.
Тем не менее, я понял, что можно обойтись без дополнительной проверки длины строки, чтобы удалить последний пробел в строке. Ведь переменная i в цикле while() увеличивается до тех пор, пока i-тый элемент в строке не будет равен нулю.
Таким образом, я могу использовать эту переменную и для удаления последнего пробела из строки.
...
while(charray[i]) {
...
i++;
}
if(' ' == charray[i-1])
charray[i-1] = 0;
...
Комментариев нет:
Отправить комментарий