Это не ответ - у Бармара есть - но и этот, и другой вопрос ОП показывают, что они могут по-новому взглянуть на то, как модифицировать массивы символов на месте.
Это написано в надежде, что это будет полезно и другим, изучающим C.
Элементы или последовательности элементов могут быть эффективно удалены из массива, используя простой цикл над егосодержание.
Ключ заключается в том, чтобы сохранить два индекса: один для следующего элемента (или элементов), подлежащего проверке, и один для последнего сохраненного элемента (или следующей позиции для сохранения).
Например, для удаления цифр в массиве можно использовать следующую функцию псевдокода:
Function removedigits(array, length):
Let i = 0 # Index of next element to examine, "input"
Let o = 0 # Position of next element to store, "output"
While (i < length):
If (array[i] is not a digit):
Let array[o] = array[i]
Let o = o + 1
End If
Let i = i + 1
End While
# For a string, we'll also want to terminate the array
# at o, because the rest of it contains garbage (old contents):
Let array[o] = '\0'
End Function
При работе с последовательностями может быть полезно сохранить несколько индексов.Например, чтобы удалить повторяющиеся строки, можно использовать следующую функцию:
Function removeduplicatelines(array):
Let i = 0 # Next position in the array to be examined
Let o = 0 # Next position in the array to store to
Let ostarted = 0 # Index at which the last line stored started at
# Loop over each input line:
While (array[i] != '\0'):
# Find the length of this line. It can end with a newline
# or at the end of the string. The newline is not included.
Let ilen = 0
While (array[i + ilen] != '\n' && array[i + ilen] != '\0'):
Let ilen = ilen + 1
End While
# If the already stored line is of different length
# (the +1 is for the newline, as it is not included in ilen)
# or if it does not match the input line, store input line.
If (ostarted + ilen + 1 != o || memcmp(array + ostarted, array + i, ilen) != 0):
# The lengths or content differs. Store the line.
# Copy ilen characters, starting at array[i],
# to array[o] onwards.
# Because the array parts do not overlap,
# we can safely use memcpy() here.
memcpy(array + o, array + i, ilen)
# It is now the last stored line.
Let ostarted = o
Let o = o + ilen
# If there is a newline following the line,
# store that too.
If (array[i + ilen] == '\n'):
Let array[o] = '\n'
Let o = o + 1
End If
Else:
# It is the same line again. Do not store.
End If
# Proceed to the next input line.
Let i = i + ilen
# Because the newline was not included in ilen,
# skip it if there is one.
If (array[i] == '\n'):
Let i = i + 1
End If
End While
# After index o, the array may contain old contents;
# so terminate the string at index o.
Let array[o] = '\0'
End Function
Обратите внимание, что memcmp()
возвращает ноль, если символы ilen
, начинающиеся с array + ostarted
, совпадают с теми, которые начинаются с array + i
.
Этот подход работает, если мы знаем, что o
никогда не превышает i
;то есть мы никогда не перезаписываем содержимое массива, которое еще не исследовали.Но обратите внимание, что o
допускается равным i
, поскольку это просто означает, что мы перезаписываем тот же символ, который мы только что изучили, не внося никаких изменений в массив.
Если мы хотим изменитьЧтобы пропустить пустые строки, мы добавляем новый цикл while перед существующим, чтобы удалить все начальные символы новой строки:
While (array[i] == '\n'):
Let i = i + 1
End While
и, чтобы удалить все пустые строки, мы изменяем последнюю часть в то время какзацикливание на
# Because the newline was not included in ilen,
# skip it (and any additional newlines) if there is one.
While (array[i] == '\n'):
Let i = i + 1
End While
Наконец, обратите внимание, что вышеприведенный removeduplicatelines()
очень осторожен, чтобы не добавлять символ новой строки после последней строки, если в массиве его нет.