从 C 中的数组中删除零项

Remove zero entries from an array in C

我有一个值数组 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 语句吗?

这个问题可以通过使用两个索引来解决:一个用于源数组x),另一个用于目标数组 (x_upd),在下面的代码中分别是ij

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];       
}

如您所见,索引 j 仅在 更新 (即:递增 1)时复制来自 x 的元素x_upd,而索引 ifor 循环的每次迭代中更新。

这个

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

正在跳过 x_upd 数组中的位置,因为即使您没有在新数组中插入值,i 仍在递增。

你应该这样做:

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]); //
}

这种情况下的诀窍是使用不同的变量索引到您的其他数组中。

所以不是这个:

x_upd[i] = x[i];

您可以有另一个变量 j,它仅在您为 x_upd

赋值时递增
x_upd[j++] = x[i];

您应该使用单独的计数器变量,否则在分配给新数组时,您将"skip"原始数组包含零的索引。

#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;
}

无需创建新数组,查看一个数组的工作代码。

#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,
#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 

您应该单独递增 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++;
  }
}

您按顺序检查值 0-9 一次,然后跳过 0 的值,因此您得到 {garbage, garbage, 1, 2, 3, garbage, garbage, 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]); 
}

不需要索引

int populate(int *src, int *dest, int size)
//usage: - src - source table
//src - source table
//dest - destination table
//size of the source table - source table
//Return: -1 if pointers are null, -2 if source table has zero elements, or number of non zero elements copied
{
    int result = (src == NULL || dest == NULL) * -1;
    // it an equivalen of:
    // int result;    
    // if(src == NULL || dest == NULL)
    //     result = -1;
    // else
    //     result = 0;
    if(size == 0) result = -2;
    if (!result)
    {
        while(size--)
            if (*src)
            {
                *dest++ = *src;
                result++;
            }
        src++;
    }
    return result;
}



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

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

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

或者函数可以return复制值的个数

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] ); //
}

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

问题出在这里:

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]); //
}