Sjoseph
Sjoseph

Reputation: 873

Remove zero entries from an array in C

I have an array of values x = {0,0,1,2,3,0,0,7,8} and I want to remove the zero entries using C.

Attempt:

I am attempting to loop through each value in the array and check if the entry is not equal to zero. If this condition is true, then I am attempting to populate a new array with original array value.

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

The output is not giving me the values {1,2,3,7,8} as desired. Instead, I am getting garbage values at the location where the zeros used to be.

Any advice on what I am doing wrong here? Do I need an else statement?

Upvotes: 3

Views: 12957

Answers (12)

essassi
essassi

Reputation: 1

First, we must know the index of the "first non-zero" value in the array:

idx = 0;
while((idx < arrySize) & (arry[idx] == 0)) idx++;

and from here we can:

  • Consider idx as "zero" in the subsequent loops involving the array, OR
  • Constructing a new array holding only effective elements of the old array:
for ( j = 0; j < arrySize-idx; j++) newarry[j] = arry[j+idx];

Upvotes: 0

0___________
0___________

Reputation: 68089

no indexes needed

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

Upvotes: 1

LLDevLab
LLDevLab

Reputation: 56

You should increment x_upd array index separately. Something like:

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

Upvotes: 2

urielSilva
urielSilva

Reputation: 410

You should use separate counter variables, otherwise you will "skip" the indexes where the original array contains zeroes when assigning to the new array.

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

Upvotes: 3

xerocool
xerocool

Reputation: 113

The problem lies here:

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

and

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

You need to maintain separate index for x and x_upd, since they will be of different size(x_upd wont have the '0').

Try this:

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 

  }
}

and to print, use the correct count, obtained from the above code:

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

Upvotes: 2

Vlad from Moscow
Vlad from Moscow

Reputation: 311166

There is already such a function in C++. It is named remove_copy. In C such a function can look the following way as it is shown in the demonstrative program below.

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

The program output is

1 2 3 7 8

Or the function can return the number of the copied values

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

As for your code then you need to use an additional variable that will keep the index in the destination array. For example

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

In fact the first loop corresponds to the second function implementation shown above.

Upvotes: 5

Jakub Dąbek
Jakub Dąbek

Reputation: 1044

You go through the values 0-9 once, in order, and you skip values that are 0, so you get {garbage, garbage, 1, 2, 3, garbage, garbage, 7, 8}. You'd have to keep a separate counter for the number of values that aren't 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]); 
}

Upvotes: 3

jfMR
jfMR

Reputation: 24788

This problem can be solved by using two indexes: one for the source array (x) and another for the destination array (x_upd), which are i and j, respectively, in the code below.

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

As you can see, the index j is only being updated (i.e.: incremented by one) when an element from x is being copied to x_upd, whereas the index i is being updated in each iteration of the for loop.

Upvotes: 2

Federico klez Culloca
Federico klez Culloca

Reputation: 27159

This

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

is skipping places in the x_upd array, since i is still being incremented even when you don't insert values in your new array.

You should do this:

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

Then, here

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

You should just count till j:

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

Upvotes: 2

Farhan Yaseen
Farhan Yaseen

Reputation: 2707

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

Output

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

Upvotes: 1

kocica
kocica

Reputation: 6465

No need to create a new array, see the working code with one array.

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

OUTPUT:

1,2,3,7,8,

Upvotes: 2

Chris Turner
Chris Turner

Reputation: 8142

The trick in this situation, is to use a different variable to index into your other array.

So instead of this:

x_upd[i] = x[i];

You could have another variable j that only increments when you assign a value to x_upd

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

Upvotes: 2

Related Questions