在C语言中从数组中删除零元素

3
我有一个值数组 x = {0,0,1,2,3,0,0,7,8},我想使用C语言删除零条目。
尝试:
我正在尝试循环遍历数组中的每个值,并检查该项是否不等于零。如果此条件为真,则我试图使用原始数组值填充新数组。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    int x[] = { 0, 0, 1, 2, 3, 0, 0, 7, 8 };
    int i;
    int x_upd[100];
    for (i = 0; i < 9; i++) {
        if (x[i] != 0) {
            x_upd[i] = x[i]; // if true, populate new array with value
        }
    }
    for (i = 0; i < 9; i++) {
        printf(" Peak updated %d\t", x_upd[i]); //
    }
    return 0;
}

输出结果并不是我期望的 {1,2,3,7,8},而是一些垃圾值代替原来为零的位置。请问我做错了什么?需要加上一个else语句吗?

int i, j = 0; ...x_upd[j++] = x[i];...for(i=0;i<9;i++) --> for(i = 0; i < j; i++) - BLUEPIXY
在第二个循环中,当您打印值时,您认为对于未初始化的 x_upd 元素会打印什么?您还需要跟踪新的大小。 - Some programmer dude
这是我仍然不完全理解的事情,但我会打印一些与变量地址有关的引用吗? - Sjoseph
“我在原本应该为零的位置得到了垃圾值。” --> 你期望在未初始化的x_upd[]部分中有什么值? - chux - Reinstate Monica
12个回答

5

C++中已经有这样的函数了,它被命名为remove_copy。在C语言中,这样的函数可以像下面演示程序中所示的那样写。

#include <stdio.h>

int * remove_copy(const int *in, size_t n, int *out, int value)
{
    for (size_t i = 0; i != n; i++)
    {
        if (in[i] != value) *out++ = in[i];
    }

    return out;
}

int main( void )
{
    int a[] = { 0, 0, 1, 2, 3, 0, 0, 7, 8 };
    int b[sizeof(a) / sizeof(*a)];
    const size_t N = sizeof(a) / sizeof(*a);

    int *last = remove_copy(a, N, b, 0);

    for (int *first = b; first != last; ++first)
    {
        printf("%d ", *first);
    }

    putchar('\n');

    return 0;
}

程序的输出是:
1 2 3 7 8

该函数可以返回已复制的值的数量。

size_t remove_copy(const int *in, size_t n, int *out, int value)
{
    size_t m = 0;

    for (size_t i = 0; i != n; i++)
    {
        if (in[i] != value) out[m++] = in[i];
    }

    return m;
}

关于你的代码,你需要使用一个额外的变量来保存目标数组中的索引。例如:

int m = 0;

for ( i = 0; i < sizeof( x ) / sizeof( *x ); i++ )
{
    if ( x[i] != 0 )
    {
        x_upd[m++] = x[i]; // if true, populate new array with value
    }
}

for ( i = 0; i < m; i++ )
{
    printf(" Peak updated %d\t", x_upd[i] ); //
}

实际上,第一个循环对应于上面展示的第二个函数实现。


remove_copy 中有一件特别的事情 - 你可以将相同的指针传入两个参数,它将会原地操作。 - Antti Haapala -- Слава Україні
@AnttiHaapala 这是错误的。根据C++,范围不应重叠。 - Vlad from Moscow
你写的C版本。我不关心C++ :D - Antti Haapala -- Слава Україні

3
你应该使用单独的计数器变量,否则在将原始数组分配给新数组时,将会“跳过”原始数组中包含零的索引。
#include <stdio.h>

int main() {
    int x[] = { 0, 0, 1, 2, 3, 0, 0, 7, 8 };
    int i;
    int j = 0;
    int x_upd[100];
    for (i = 0; i < 9; i++) {
        if (x[i] != 0) {
            x_upd[j++] = x[i]; // if true, populate new array with value
        }
    }
    for (i = 0; i < j; i++) {
          printf(" Peak updated %d\t", x_upd[i]); //
    }
    return 0;
}

第二个 i<9 --> i<j - BLUEPIXY

3

您需要按照顺序一次经过0-9这些数值,但是会跳过数值为0的,因此您会获得{垃圾, 垃圾, 1, 2, 3, 垃圾, 垃圾, 7, 8}。您需要另外记一个计数器来计数那些不是0的数值:

int position = 0;
for(i = 0; i < 9; i++)
{
    if(x[i] != 0)
    {
        x_upd[position] = x[i]; // if true, populate new array with value
        position++;
    }
}

//loop until you get to counter
for(i = 0; i < position; i++)
{
    printf(" Peak updated %d\t", x_upd[i]); 
}

我认为 position 更有意义,但 counter 也能传达我的意思。当然,我忘记改所有的内容了,现在已经编辑过了。这是对早期评论的回应 - Jakub Dąbek

2
这个问题可以通过使用两个索引来解决:一个用于源数组x),另一个用于目标数组x_upd),在下面的代码中分别表示为ij。请保留html标签。
int i, j;
for(i=0,j=0; i<9; i++) {
  if (!x[i]) // is x[i] zero?
     continue; // then skip this element

  // otherwise copy current element and update destination index
  x_upd[j++] = x[i];       
}

从代码中可以看出,只有在将x的元素复制到x_upd时才会更新索引j(即:增加1),而在每次for循环迭代中都会更新索引i


2

This

for(i=0;i<9;i++)
{
  if(x[i] != 0)
  {
      x_upd[i] = x[i]; // if true, populate new array with value
  }
}

由于i在新数组中没有插入值时仍在增加,因此在x_upd数组中跳过了一些位置。

你应该这样做:

int j = 0;
for(i=0;i<9;i++)
{
  if(x[i] != 0)
  {
      x_upd[j++] = x[i]; // if true, populate new array with value
  }
}

那么,这里。
for(i=0;i<9;i++)
{
  printf(" Peak updated %d\t",x_upd[i]); //
}

你只需要数到j:
for(i=0;i<j;i++)
{
  printf(" Peak updated %d\t",x_upd[i]); //
}

2
不需要创建一个新的数组,可以看到只使用一个数组的工作代码。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    int x[] = { 0, 0, 1, 2, 3, 0, 0, 7, 8 };
    int i, n;

    for (i = 0, n = 0; i<9; i++)
    {
        if (x[i] != 0)
        {
            x[n++] = x[i];
        }
    }

    for (i = 0; i<n; i++)
    {
        printf("%d,", x[i]);
    }
    return 0;
}

输出:

1,2,3,7,8,

也许他需要保留原始数组。 - Barmar
1
他没有明确说他需要什么,考虑到他是初学者,我认为他使用第二个数组只是因为他不知道如何用一个数组实现。 - kocica

2
你应该单独增加x_upd数组的索引。可以这样做:
int y = 0;
for(i=0;i<9;i++)
{
  if(x[i] != 0)
  {
      x_upd[y] = x[i]; // if true, populate new array with value
      y++;
  }
}

2
问题出在这里:
for(i=0;i<9;i++)
{
  if(x[i] != 0)
  {
      x_upd[i] = x[i]; // if true, populate new array with value
  }
}

并且
for(i=0;i<9;i++) {
   printf(" Peak updated %d\t",x_upd[i]); //
}

由于x和x_upd的大小不同(x_upd不含“0”),您需要为它们分别维护单独的索引。

尝试以下方法:

int j;
for(i=0,j=0;i<9;i++) {
  if(x[i] != 0)
  {
      x_upd[j] = x[i]; // if true, populate new array with value
      j++;             // index for values inserted 

  }
}

要打印输出,请使用从上述代码中获取的正确计数:

int k;
for(k=0;k<=j;k++) {
   printf(" Peak updated %d\t",x_upd[k]); //
}

2
在这种情况下的技巧是,使用不同的变量来索引您的另一个数组。因此,不要这样做:
```python array1[index] = array2[index] ```
而应该这样做: ```python array1[i] = array2[j] ```
x_upd[i] = x[i];

你可以再定义一个变量 j,它只在给 x_upd 赋值时增加。

x_upd[j++] = x[i];

1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
int x[] = {0,0,1,2,3,0,0,7,8};
int i;
int count = 0;
int x_upd[100];
for(i=0;i<9;i++)
    {
      if(x[i] != 0)
      {
          x_upd[count] = x[i]; // if true, populate new array with value
          count++;
      }
    }

for(i=0;i<count;i++)
    {
      printf(" Peak updated %d\t",x_upd[i]); //
    }
return 0;
}

输出

Peak updated 1  Peak updated 2  Peak updated 3  Peak updated 7  Peak updated 8 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接