【问题标题】:Remove zero entries from an array in C从 C 中的数组中删除零条目
【发布时间】:2017-08-09 10:46:28
【问题描述】:

我有一个值数组 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&lt;9;i++) --> for(i = 0; i &lt; j; i++)
  • 在第二个循环中,您打印值,您认为您会为未初始化的x_upd 元素打印什么?您还需要跟踪新尺寸。
  • 这是我还没有完全理解的东西,但我会打印一些对变量地址的引用吗?
  • “我在原来的零位置得到垃圾值。” --> 你期望x_upd[] 的未初始化部分有什么值?

标签: c arrays algorithm zero


【解决方案1】:

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 中有一个特殊的地方 - 你可以为两个参数传入 same 指针,它会在原地工作。
  • @AnttiHaapala 这是错误的。根据 C++,范围不应重叠。
  • 您编写的 C 版本。我不关心 C++ :D
【解决方案2】:

您按顺序遍历值 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]); 
}

【讨论】:

  • 我认为position 更有意义,但counter 也传达了我的意思。当然我忘了改变一切,现在编辑。 这是对先前评论的回应
【解决方案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&lt;9 --> i&lt;j
【解决方案4】:

在这种情况下,诀窍是使用不同的变量来索引其他数组。

所以不要这样:

x_upd[i] = x[i];

你可以有另一个变量j,它只会在你给x_upd赋值时增加

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

【讨论】:

    【解决方案5】:

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

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

    【讨论】:

    • 也许他需要保留原来的数组。
    • 他没有明确说明他需要什么,关于他是初学者,我认为他使用第二个数组只是因为他不知道如何使用一个。
    【解决方案6】:

    这个

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

    【讨论】:

      【解决方案7】:

      这个问题可以通过使用两个索引来解决:一个用于源数组 (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];       
      }
      

      如您所见,仅当 x 中的元素被复制到 x_upd 时,索引 j 才会更新(即:加一),而索引 @ 987654329@ 在for 循环的每次迭代中都会更新。

      【讨论】:

        【解决方案8】:

        问题出在这里:

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

        【讨论】:

          【解决方案9】:

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

          【讨论】:

            【解决方案10】:
            #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 
            

            【讨论】:

              【解决方案11】:

              不需要索引

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

              【讨论】:

              • 这个int result = (src == NULL || dest == NULL || size == 0) * -1; 不适合作为教育示例。
              • @alk 我知道你的意思 - 在评论中解释了它:)
              • 通常我认为您应该将 cmets 放在您正在评论的行上方。如果您在 int populate(int *src, int *dest, int size){ 之间添加注释,则函数声明看起来不连贯
              • size == 0 时,为什么不直接返回0?为什么不简单地写:if (src == NULL || dest == NULL) return -1;
              • @chqrlie 我不喜欢返回点超过 1 个的函数,原因有很多,我在这里已经解释过很多次了
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2012-01-21
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多