【问题标题】:Why is my function not deleting all numbers?为什么我的函数没有删除所有数字?
【发布时间】:2018-04-26 01:17:41
【问题描述】:

我创建了一个函数,可以在数组中查找任何数字并将其删除。这是我的代码:

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 数组中,则将其删除,没问题。但是,如果数组中有连续的数字,那么只有每隔一个数字会被删除?

如果我的 char 数组有

w12345678

然后数组变为

w2468

而不是

w

有什么想法吗?

【问题讨论】:

  • 我不太喜欢&amp;a[deleteInd] 表示法(不要误会,它是正确的),但我更喜欢a + deleteInd,对我来说它更优雅。对我来说,这个memmove (a + deleteInd, a + deleteInd + 1, strlen (a) - deleteInd); 更容易阅读。
  • 关于跳过,你可以在memmove之后做i--,这意味着你重复相同的索引。
  • 太棒了 :) 谢谢。

标签: c arrays char numbers


【解决方案1】:

在您执行memmove() 之后,下一个元素现在位于您刚刚删除的元素的索引中。但是您的循环将执行i++,因此您不会再次检查该索引。因此,只要一行中有两个数字,您就会跳过第二个。

解决此问题的一种方法是从数组的末尾循环到开头,而不是从开头到结尾。

另一种方法是在执行memmove() 之后执行i--,以抵消循环将执行的i++

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

顺便说一句,您应该使用isdigit() 来测试字符是否为数字。

【讨论】:

    【解决方案2】:

    您是否注意到您正在删除第一个数字然后跳过一个?

    遍历数组时,从位置 0 开始并递增。当你删除一个数字时,你改变了字符串索引。

    i = 0 (char = w) 索引:012345689 字符串:w12345678 i = 1 (char = 1) 索引:012345689 字符串:w2345678 i = 2 (char = 3) 索引:012345689 字符串:w2345678

    本质上,每当你删除你的角色时,你就是在移动字符串。

    删除字符时不要增加 i。

    请注意,您的代码中不需要 deleteInd,您可以直接使用 i。

    【讨论】:

    • 是的,刚刚意识到 :) 感谢您的帮助。
    【解决方案3】:

    这不是答案——Barmar's 是——但这个和 OP 的 other question 都表明他们可以重新审视如何修改字符数组。

    写这篇文章是希望对其他学习 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
    

    请注意,如果以array + ostarted 开头的ilen 字符与以array + i 开头的字符匹配,则memcmp() 返回零。

    如果我们知道o 永远不会超过i,则此方法有效;也就是说,我们永远不会覆盖我们尚未检查的数组内容。但请注意,o 允许等于 i,因为这只是意味着我们会覆盖我们刚刚检查的相同字符,而不会对数组进行实际更改。

    如果我们想修改函数以跳过空行,我们在现有循环之前添加一个新的 while 循环,以删除任何前导换行符:

    While (array[i] == '\n'):
        Let  i = i + 1
    End While
    

    并且,为了删除任何空行,我们将 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() 非常注意不要在最后一行之后添加换行符,如果数组中没有以开头的换行符。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-25
      • 2015-12-10
      • 2020-02-12
      • 2021-04-29
      • 2020-11-16
      相关资源
      最近更新 更多