1

I want to pass an array into an instance of a class to be used within it. However, I can't get sizeof() the array. I get the warning "Sizeof on array function parameter will return size of 'float *' instead of 'float []'. "

int main() {
float info[]={1.0f,2.3f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,67.8f};
Store test(info);
test.showArrayContents();
{

Class I want to pass array to

class Store{
float array[]; 
public:
Store(float temp[]){
    std::cout<<"\n"<<sizeof(temp); //can't get sizeof 
    for(int i=0;i<9;i++){
        array[i]=temp[i];
    };
}
void showArrayContents(){
   for(int i=0;i<9;i++){
       std::cout<<array[i];
    }
 }
};

How can I fix to get sizeof() correctly?

EDIT: I'm not trying to find how many elements are in the array but the amount of memory it takes up, which should be 40 bytes.

Juroza
  • 17
  • 5
  • 1
    Does this answer your question? [Finding length of array inside a function](https://stackoverflow.com/questions/17590226/finding-length-of-array-inside-a-function) Different language, same problem. – Yunnosch Jul 24 '21 at 11:45
  • Does this answer your question? [C sizeof a passed array](https://stackoverflow.com/questions/5493281/c-sizeof-a-passed-array) – IS4 Jul 24 '21 at 11:46
  • https://stackoverflow.com/a/16148073/4944425 There probably are other dupes around. – Bob__ Jul 24 '21 at 11:48
  • 1
    There is nothing wrong with c style code ... but C++ does this differently. For instance, consider declaring your float array using std:;array ... the object will have a method 'size' which reports the number of elements. I prefer std::vector, which also has a method 'size'. – 2785528 Jul 24 '21 at 11:53
  • Please note that your code doesn't allocate any memory to store `array` elements. Save yourself some trouble and use a `std::vector` (or `std::array`, if the size is a compile time constant). – Bob__ Jul 24 '21 at 11:55
  • Despite the way it's written, `float temp[]` is a **pointer** to `float`. There's no way to get the size of the array that it points at, because it doesn't have to point at an element of an array. – Pete Becker Jul 24 '21 at 11:58
  • The code screams to me "use `std::vector`". – Eljay Jul 24 '21 at 12:46

4 Answers4

3

I want to pass an array into an instance of a class to be used within it.

Ok, there are several ways to do that, I'll show you some of those later.

However, I can't get sizeof() the array.

You can't get it inside the function, after the array decayed to a pointer.

Store(float temp[]){
//          ^^^^^^    This is a pointer to float, not an array
}

Other than explicitly passing the size as a function argument, you could pass a reference to an array, using a template parameter to store the size (1).

#include <vector>
#include <iostream>

class Store
{
    std::vector<float> values_;
public:
    template< std::size_t N >
    Store(float const (&temp)[N]) : values_{temp, temp + N}
    {}//              ^^^^^^^^^^
 
    void showArrayContents() const noexcept
    {
        for(auto i : values_)
        {
            std::cout << ' ' << i;
        }
        std::cout << '\n';
    }
};

int main()
{
    float info[]={1.0f,2.3f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,67.8f};
    
    Store test(info);
    test.showArrayContents();
}

Get rid of the source array and use a std::initializer_list (2).

#include <vector>
#include <iostream>
#include <initializer_list>

class Store
{
    std::vector<float> values_; 
public:
    Store(std::initializer_list<float> src) : values_{src}
    {}
 
    //...
};

int main()
{
    Store test{1.0f,2.3f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,67.8f};
    test.showArrayContents();
}

If the size never has to change during the lifetime of Store, you can use a std::array (3).

#include <algorithm>
#include <array>
#include <iostream>

template< class T, std::size_t N >
class Store
{
    std::array<T, N> values_; 
public:
    Store(T const (&src)[N]) 
    {
        std::copy(src, src + N, values_.begin());
    }
 
    //...
};

//deduction guide
template<class T, std::size_t N> Store( T (&src)[N] ) -> Store<T, N>;

int main()
{
    float info[]={1.0f,2.3f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,67.8f};
    
    Store test(info);
    test.showArrayContents();
}

You can also avoid the source array and initialize the class with a constructor accepting a template parameter pack (4).

#include <algorithm>
#include <array>
#include <iostream>
#include <type_traits>

template< class T, std::size_t N >
class Store
{
    std::array<T, N> values_; 
public:
    template< class... Args >
    Store(Args... args) : values_{args...}
    {}
 
    //...
};

//deduction guide
template< class... Args >
Store(Args &&... ) -> Store<std::common_type_t<Args...>, sizeof...(Args)>;

int main()
{
    Store test{1.0f,2.3f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,67.8f};
    test.showArrayContents();
}
Bob__
  • 12,361
  • 3
  • 28
  • 42
2

For a static C-style array it is possible to infer its size using the expression

sizeof(info) / sizeof(*info)

This is also commonly implemented via a macro ARRAY_SIZE. Beware however that in the above code there is no check that the actual array is a static one.

Conversely, for a dynamically allocated C-style array, there is no possibility to infer its size, since the variable itself is nothing but a pointer.

In the class constructor, even if you knew the size of the array (for instance by passing the size as parameter), or if you assume that only a static array is used (and you employ the code above to infer its size), your code has a serious bug here:

for(int i=0;i<9;i++){
    array[i]=temp[i];
};

You are copying the elements of temp into array, but did you reserve memory for that? Again, array is merely a pointer to float, and if you do not explicitly allocate memory, in the above code you are writing into a part of memory which does not pertain to array. Hence you have UB.

If you know at compile time the size of the array, the right type to use is std::array. For instance

std::array<float, 10> info = {1.0f,2.3f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,67.8f};

And then you can pass it to the class with something like

class Store{
std::array<float, 10> array;
public:
Store(std::array<float, 10> temp) : array{temp} { }

...

With a std::array you can always know its size with std::array::size.

francesco
  • 7,189
  • 7
  • 22
  • 49
  • `info` is an array of 10 `float`. The compiler infers the number of elements from the initializer, which has 10 elements. Try looking at `sizeof(info)/sizeof(*info)` to see that. You're on the right track, though: `float temp[]` as an argument defines `temp` as a pointer. – Pete Becker Jul 24 '21 at 12:34
1

How can I fix to get sizeof() correctly?

Option #1: you could pass in the size of the array.

#include <array>
#include <cstddef>
#include <iostream>

using std::cout;
using std::size;
using std::size_t;

namespace {

class Store {
    size_t array_size;
    float* array;
public:
    ~Store() {
        delete[] array;
    }
    Store(float temp[], size_t temp_size) : array_size{temp_size} {
        cout << "temp_size:" << temp_size << "\n";
        array = new float[temp_size];
        for (size_t i = 0; i < temp_size; ++i) {
            array[i] = temp[i];
        }
    }
    Store(Store const&) = delete;
    auto operator=(Store const&) -> Store& = delete;
    void showArrayContents() {
        auto sep = "";
        for (size_t i = 0; i < array_size; ++i) {
            cout << sep << array[i];
            sep = " ";
        }
        cout << "\n";
    }
};

} // anon

int main() {
    float info[] = { 1.0f, 2.3f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 67.8f };
    Store test(info, size(info));
    test.showArrayContents();
}

Option #2: you could use a template constructor for the array.

#include <cstddef>
#include <iostream>

using std::cout;
using std::size_t;

namespace {

class Store {
    size_t array_size;
    float* array;
public:
    ~Store() {
        delete[] array;
    }
    template <size_t N>
    Store(float (&temp)[N]) : array_size{N} {
        cout << "N:" << N << "\n";
        array = new float[N];
        for (size_t i = 0; i < N; ++i) {
            array[i] = temp[i];
        }
    }
    Store(Store const&) = delete;
    auto operator=(Store const&) -> Store& = delete;
    void showArrayContents() {
        auto sep = "";
        for (size_t i = 0; i < array_size; ++i) {
            cout << sep << array[i];
            sep = " ";
        }
        cout << "\n";
    }
};

} // anon

int main() {
    float info[] = { 1.0f, 2.3f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 67.8f };
    Store test(info);
    test.showArrayContents();
}

Option #3 (best option): you could use std::vector.

#include <cstddef>
#include <iostream>
#include <vector>
#include <utility>

using std::cout;
using std::move;
using std::ostream;
using std::size_t;
using std::vector;

namespace {

class Store {
    vector<float> array;
public:
    Store(vector<float> temp) : array{move(temp)} {
        cout << "temp size:" << temp.size() << "\n";
    }
    void showArrayContents(ostream& out) const {
        auto sep = "";
        for (auto&& e : array) {
            out << sep << e;
            sep = " ";
        }
        out << "\n";
    }
};

} // anon

int main() {
    auto info = vector<float>{ 1.0f, 2.3f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 67.8f };
    auto test = Store{info};
    test.showArrayContents(cout);
}
Eljay
  • 4,648
  • 3
  • 16
  • 27
0

You should pass the array length as an argument also, when you pass an array to function what you actually pass is a pointer to start location of array i.e. float* in your case, so when you ask for size it simply gives you size of pointer . So either pass the size explicitly, or use std::vector which will give you the length.

other than that if class Store is the owner of array, why not define it inside class?

hessam hedieh
  • 780
  • 5
  • 18