Почему моя функция не удаляет все числа? - PullRequest
0 голосов
/ 26 апреля 2018

Я сделал функцию, которая найдет любые цифры в массиве и удалит их.Вот мой код:

int noNums (char *a) {
  int i;
  int deleteInd;
  for (i = 0; (i < MAX_NAME_SZ) && (a[i] != '\0'); i++) {
      if ((a[i] >= '0') && (a[i] <= '9')) {
      deleteInd = i;
      memmove (&a[deleteInd], &a[deleteInd + 1], strlen (a) - deleteInd);
      }
  }
}

Если число находится само в массиве char, то оно удаляется, нет проблем.Однако, если в массиве есть последовательные числа, будут удалены только все остальные цифры?

Если мой массив символов имеет

w12345678

затем массив изменяется на

w2468

вместо

w

Есть идеи?

Ответы [ 3 ]

0 голосов
/ 26 апреля 2018

Заметили ли вы, что вы удаляете первую цифру, а затем пропускаете одну?

При переборе массива вы начинаете с позиции 0 и увеличиваете ее.Когда вы удаляете цифру, вы изменяете индекс строки.

i = 0 (char = w)
Index:  012345689
string: w12345678

i = 1 (char = 1)
Index:  012345689
string: w2345678

i = 2 (char = 3)
Index:  012345689
string: w2345678

По сути, вы сдвигаете строку всякий раз, когда удаляете свой символ.

Не увеличивайте i при удалениисимвол.

Обратите внимание, что deleteInd не нужен в вашем коде, вы можете использовать i напрямую.

0 голосов
/ 26 апреля 2018

Это не ответ - у Бармара есть - но и этот, и другой вопрос ОП показывают, что они могут по-новому взглянуть на то, как модифицировать массивы символов на месте.

Это написано в надежде, что это будет полезно и другим, изучающим 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() очень осторожен, чтобы не добавлять символ новой строки после последней строки, если в массиве его нет.

0 голосов
/ 26 апреля 2018

После того, как вы выполните memmove(), следующий элемент будет теперь в индексе элемента, который вы только что удалили.Но ваш цикл будет делать i++, поэтому вы больше не будете проверять этот индекс.В результате, когда в строке есть две цифры, вы пропускаете вторую.

Один из способов исправить это - выполнить цикл от конца массива к началу, а не от начала доend.

Другой способ - сделать i-- после выполнения memmove(), чтобы противодействовать i++, который будет делать цикл.

  if (isdigit(a[i]) {
      deleteInd = i;
      memmove (&a[deleteInd], &a[deleteInd + 1], strlen (a) - deleteInd);
      i--;
  }

Кстати, вы должны использовать isdigit(), чтобы проверить, является ли символ цифрой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...