2

Need to implement a function

int* linearSearch(int* array, int num);

That gets a fixed size array of integers with a number and return an array with indices to the occurrences of the searched number. For example array={3,4,5,3,6,8,7,8,3,5} & num=5 will return occArray={2,9}. I've implemented it in c++ with a main function to check the output

#include <iostream>
using namespace std;
int* linearSearch(int* array, int num);

int main()
{
    int array[] = {3,4,5,3,6,8,7,8,3,5}, num=5;
    int* occArray = linearSearch(array, num);
    int i = sizeof(occArray)/sizeof(occArray[0]);
    while (i>0) {
        std::cout<<occArray[i]<<" ";
        i--;
    }
}

int* linearSearch(int* array, int num)
{
    int *occArray= new int[];
    for (int i = 0,j = 0; i < sizeof(array) / sizeof(array[0]); i++) {
        if (array[i] == num) {
            occArray[j] = i;
            j++;
        }
    }
    return occArray;
}

I think the logic is fine but I have a syntax problems with creating a dynamic cell for occArray Also a neater implantation with std::vector will be welcomed

Thank You

Roey
  • 171
  • 12
  • 3
    Use `std::vector` instead of raw owning pointer. – Jarod42 Oct 27 '21 at 10:40
  • 1
    As already said, use `std::vector`. If this is an exercise, then this is a fishy one - How do you know the number of occurrences (hence the size of the returned array)? – Holt Oct 27 '21 at 10:44
  • 3
    `sizeof(array) / sizeof(array[0])` is wrong when array is `int*` – Jarod42 Oct 27 '21 at 10:45
  • @Holt you don't know the number of occurrences you need to find them. the function doesn't get the size of the array to search, I've given an example in main but it should work with any size array of integers. I don't know how to use ```std::vector``` yet it's optional I need a simple implementation that works. and yes this is an exercise. – Roey Oct 27 '21 at 10:52
  • @Roey I was referring to the size of the returned array. As Jarod42 said, the way you try to compute the size of the array is wrong: `sizeof(array) / sizeof(array[0])` will not give you the size of the array unless `array` is an array type (which `int *` isn't). So you either 1) need to pass the size of the array to `linearSearch` AND find a way to return the size of `occArray` or 2) use `std::vector` in both places (parameter and return) so that you do not have to worry about such thing. – Holt Oct 27 '21 at 11:03

1 Answers1

1

At very first I join in the std::vector recommendation in the question's comments (pass it as const reference to avoid unnecessary copy!), that solves all of your issues:

std::vector<size_t> linearSearch(std::vector<int> const& array, int value)
{
    std::vector<size_t> occurrences;
    // to prevent unnecessary re-allocations, which are expensive,
    // one should reserve sufficient space in advance
    occurrences.reserve(array.size());
    // if you expect only few occurrences you might reserve a bit less,
    // maybe half or quarter of array's size, then in general you use
    // less memory but in few cases you still re-allocate

    for(auto i = array.begin(); i != array.end(); ++i)
    {
        if(*i == value)
        {
            // as using iterators, need to calculate the distance:
            occurrences.push_back(i - array.begin());
        }
    }
    return occurences;
}

Alternatively you could iterate with a size_t i variable from 0 to array.size(), compare array[i] == value and push_back(i); – that's equivalent, so select whichever you like better...

If you cannot use std::vector for whatever reason you need to be aware of a few issues:

You indeed can get the length of an array by sizeof(array)/sizeof(*array) – but that only works as long as you have direct access to that array. In most other cases (including passing them to functions) arrays decay to pointers and these do not retain any size information, thus this trick won't work any more, you'd always get sizeOfPointer/sizeOfUnderlyingType, on typical modern 64-bit hardware that would be 8/4 = 2 for int* – no matter how long the array originally was.

So you need to pass the size of the array in an additional parameter, e.g.:

size_t* linearSearch
(
    int* array,
    size_t number, // of elements in the array
    int value      // to search for
);

Similarly you need to return the number of occurrences of the searched value by some means. There are several options for:

  1. Turn num into a reference (size_t& num), then you can modify it inside the function and the change gets visible outside. Usage of the function get's a bit inconvenient, though, as you need to explicitly define a variable for:
size_t num = sizeof(array)/sizeof(*array);
auto occurrences = linearSearch(array, num, 7);
  1. Append a sentinel value to the array, which might be the array size or probably better maximum value for size_t – with all the disadvantages you have with C strings as well (mainly having to iterate over the result array to detect the number of occurences).
  2. Prepend the number of occurrences to the array – somehow ugly as well as you mix different kind of information into one and the same array.
  3. Return result pointer and size in a custom struct of yours or in e.g. a std::pair<size_t, size_t*>. You could even use that in a structured binding expression when calling the function:
auto [num, occurences] = linearSearch(array, sizeof(array)/sizeof(*array), 7);
//                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// here the trick yet works provided the array is declared above the call, too,
// as is in your example

Option 4 would be my personal recommendation out of these.

Side note: I switched to size_t for return values as negative indices into an array are meaningless anyway (unless you intend to use these as sentinel values, e. g. -1 for end of occurrences in option 2).

Aconcagua
  • 24,880
  • 4
  • 34
  • 59
  • I'm forced to use ```int* linearSearch(int* array, int num)``` so calling ```auto occurrences = linearSearch(array, num, 7);``` or ```auto [num, occurences] = linearSearch(array, sizeof(array)/sizeof(*array), 7);``` is not applicable. also for order sake _num_ is the number to search and lets say _length_ is the length of the passed _array_. – Roey Oct 27 '21 at 12:19
  • @Roey This is really bad then! There is *no way* to get back the array size from the pointer only. If that unlucky signature is imposed on you you could: Fall back to option 2 or 3 for one or both of the arrays, have a fixed size input array (not nice) or use global variables to store the size of one or both of the arrays (not nice either...). Maybe you should ask whoever invented that dumb signature how she/he expects to pass array sizes through the function call border... – Aconcagua Oct 27 '21 at 12:35
  • @Roey Oh, and I'm curious about her/his answer, you might want to leave a comment ;) – Aconcagua Oct 27 '21 at 13:19
  • @Aconcague yes I cannot contact the person who wrote this question but it's supposed to be a very simple answer to a basic linear search. Initially I thought to make it more sophisticated with dynamic allocation but eventually I settled for a global parameter which is also the barrier for occurrences array size. very simple. Thanks – Roey Oct 27 '21 at 14:40