2

I found the same question for PHP and I tried to do the same in C++.

I tried following:

// returns new array with numbers lower then "number", len is set to
// new length.
int * filter(int array[], int &len, int number) {
    int cnt = 0;
    for (int i = 0; i < len; i++) {
        if (array[i] < number) {
            cnt++;
        }
    }
    int *ret = new int[cnt];
    cnt = 0;
    for (int i = 0; i < len; i++) {
        if (array[i] < number) {
            ret[cnt] = array[i];
            cnt++;
        }
    }
    len = cnt;
    return ret;
}

This function will create a new array with the integers that are lower than the integer number. I tried to bypass the problem that I don't know how long the new array should be.

Is there any better way to solve this problem?

Biffen
  • 6,249
  • 6
  • 28
  • 36
Dennis M.
  • 107
  • 1
  • 2
  • 7
  • 4
    `std::vector` (or `std::set` if more appropriate) + `std::remove_if` – Biffen Feb 26 '18 at 12:55
  • 2
    Possible duplicate of [Modern way to filter STL container?](https://stackoverflow.com/questions/21204676/modern-way-to-filter-stl-container) – Joris Timmermans Feb 26 '18 at 12:56
  • 1
    Is there a reason you are not using STL's vector class? You're returning a pointer created in a local scope, which is a great way to cause a memory leak. If you really want to do it this way, at least use smart pointers. – Scott Mudge Feb 26 '18 at 12:57
  • Yes, I try to solve this problem with arrays in specific. I know it is easier to solve it with vectors. :) – Dennis M. Feb 26 '18 at 13:01
  • 1
    @DennisM. It's generally recommended to avoid manual array allocation in C++, but if you need it, count elements that don't meet your condition before creating new array. – Konrad Borowski Feb 26 '18 at 13:03
  • 2
    _Is there any better way to solve this problem?_ Use, use `std::vector` and `std::remove_if`. _I try to solve this problem with arrays in specific._ Don't do it that way. – Eljay Feb 26 '18 at 13:03
  • 1
    To clarify, arrays in C++ are a very low level concept unlike arrays in PHP, and unless you want to write a low level abstraction (like `std::vector` itself) you shouldn't use them - they are very very limited, prone to security vulnerabilities when misused and don't get deallocated when they go out of scope. – Konrad Borowski Feb 26 '18 at 13:07
  • @xfix I guess you are right. In C++ arrays don't bring many advantages. I was just curious if I could fix this problems with arrays, but why make it harder than it is? :) – Dennis M. Feb 26 '18 at 13:13
  • 1
    @DennisM. However, I will give you a hint if you really want to use arrays, just go through the array twice. Once to determine the allocation size, once to copy elements. – Konrad Borowski Feb 26 '18 at 13:16

2 Answers2

5

Yes, use std::vector type. It will automatically handles allocations for you each time you push value to it (using push_back method).

Example

#include <iostream>
#include <vector>

int main() {
    std::vector<int> a;
    a.push_back(1);
    a.push_back(2);
    for (int value : a) {
        std::cout << value << '\n';
    }
}

It's also a good idea to avoid new syntax, as it doesn't automatically deallocate, unlike std::vector.

Also, while this is unrelated to question, C++ provides a function that does what you want already called std::copy_if.

Konrad Borowski
  • 11,584
  • 3
  • 57
  • 71
  • Thanks for the fast answer, but I intend to fix this problem with an array. I know it would be possible to solve it via vectors, but I want to try it with arrays. – Dennis M. Feb 26 '18 at 13:02
0

std::remove is the algorithm you're looking for.

#include <iterator>
#include <algorithm>

int main()
{
    int array[4] = {1, 42, 314, 42};
    // If you only know `array` as a pointer, and `len`, then
    // `std::begin(array)` becomes `array`, and
    // `std::end(array)` becomes `array + len`.
    auto end = std::remove(std::begin(array), std::end(array), 42);
    // Now `end` points to the "new end" of the array.
    // And `std::distance(std::begin(array), end)` is the "new length".
}

It moves all matched elements (42 in the example) to the end of the array. When inspecting array after std::remove runs, you get {1, 314, 42, 42}, and end points past the last nonmatching element (the first 42 in this case).

It's also possible to copy the nonmatching elements to another array using std::remove_copy, or std::copy_if, but in order to do this, you'll have to allocate another array of elements. At this point, you're better off using a dynamic growing array such as std::vector. In that case, use std::vector::erase like here in the answers with std::remove.

Mário Feroldi
  • 3,463
  • 2
  • 24
  • 49
  • But you haven't actually removed them from the array. – NathanOliver Feb 26 '18 at 15:00
  • @NathanOliver as long as you use iterators, it doens't matter. I also provide another (unelaborated) solution that does get an array with only the wanted elements, but then the other answer already did the same. – Mário Feroldi Feb 26 '18 at 15:16