10 years, 2 months ago.

How to declare and initialize array in a class?

I'm having a problem with a program I'm writing for the mbed. I'm trying to create a class that contains an (const) array that contains integers. The declaration of the array happens in the .h file:

declaring array in h

#ifndef TEST_H
#define TEST_H

class test
{
    public:
        test();
        
    private:
        int* tones_freq[]; //If possible, declare as const?
};
#endif

Next, the array is being initialized in the constructor of the class inside the .cpp file:

initialize array in cpp

#include "test.h"
#include "mbed.h"

test::test()
{
    *this->tones_freq {660,660,660,510,660,770,380,510,380,320,440,480,450,430,380}; 
    //*this->tones_freq = {660,660,660,510,660,770,380,510,380,320,440,480,450,430,380};
    //*this->tones_freq[] = {660,660,660,510,660,770,380,510,380,320,440,480,450,430,380};
}

The code above all give errors (E.g. "Expection a ';'", "Expected an expression...", ...) When I try to declare the array as const inside the header and initialize it there, I get an error that initialization is not allowed there. What I am doing wrong in this simple code?

4 Answers

10 years, 2 months ago.

If it is a const anyway, you might as well make it a static member variable. And then it really is part of your class, only difference with regular variable is that between all objects made of the class, it only exists once. Which isn't an issue since it is a const anyway. See for explanation: http://www.learncpp.com/cpp-tutorial/811-static-member-variables/. Then you can define it in your .h file, while the actual initialization happens in the .cpp.

Accepted Answer
10 years, 2 months ago.

You are not allowed to initialise an array like that. You can use the following declaration:

  int tones_freq[] = {660,660,660,510,660,770,380,510,380,320,440,480,450,430,380}; 

When you want to populate the array later on then you need to define the array size at declaration time and later on use a loop to fill each individual element (or use some memcopy operation).

int tones_freq[15];

tones_freq[0]= 660;
...
tones_freq[14]= 380;

Note that you also use

int* tones_freq[];

That would mean you try to declare an array of pointers to int. Is that really what you want to do?

10 years, 2 months ago.

I've run into the same problem with C++. Unfortunately, C++ doesn't allow initializers like that. That being said, it is something that would be very useful in an embedded application. I'm not sure why there isn't a better mechanism for doing this.

Here is an simple example of how I resolved the problem:

// Make the array of const int's and limit the scope to file scope.
#define SIZE_LIST 3
static const int baseList[SIZE_LIST] = {1, 2, 3};

class Test {
private:
    const int *list; // This pointer to const must be initialized by the constructor.

public:
    Test() { // Very simple constructor.
        list = baseList;
    };
    
    // Some public member functions for accessing the array.
    int size();
    int getListElement(int index);
};

int Test::size() {
        return( SIZE_LIST );
}

int Test::getListElement(int index) {
        if( index >= 0 && index < size() )
            return( list[index] );
        else
            return( NULL );
}

10 years, 2 months ago.

Hi Jeroen,

You're code isn't too far from being correct - it just looks like you're used to managed code. The mbed compiler uses unmanaged code, so memory and garbage collection is left to you :)

You would want to use a pointer to an array of ints for class-member arrays, which is close to what you're already doing here...

class test
{
    public:
        test();
        init_array(int array_size);
    private:
        int* tones_freq; // Take off the [] brackets
};

...

test::test()
{
    tones_freq = 0; // Start out with the pointer as null
}

test::init_array(int array_size) // Once needed, reserve the memory needed for your array
{
    tones_freq = new int[ array_size ]; // The previously undefined pointer now points to an array of ints
/*  tones_freq = new int[ array_size ](); // This does the same as above, but initializes all values in the array to 0  */
}
...
test::some_function()
{

    for(int idx = 0; idx < array_size; idx++) // Using a loop, fill up the array
        tones_freq[idx] = get_some_value();
}

/*Make sure you properly release the array or memory leaks will build up*/
test::~test()
{
    if(tones_freq) // True if tones_freq is not a null pointer
        delete[] tones_freq;

}

...this is good for when you need an array in your class but don't need to use it right away (if at all) because it begins as null pointer.

If the size and values of the array are known, then use this...

class test
{
    public:
        test();
        
    private:
        int* tones_freq; // Take off the [] brackets
};

...

test::test()
{
    tones_freq = new int[ 3 ] { 660, 660, 510 }; // The previously undefined pointer now points to an array of the defined 3 ints
}
test::~test()
{
if(tones_freq) // True if tones_freq is not a null pointer
    delete[] tones_freq; 
}

Take a look at my dynamic array code if you're looking for more example syntax.

Hope that helps :) -Chris

The second code example is exactly what I'm looking for. However, I'm getting an syntax error when I try to compile it: Error: Expected a ";". It says it expects a ";" between "[3]" and "{ 660, 660, 510 };"

posted by Jeroen Behaegel 08 Feb 2014

Doesn't this method create multiple copies of the array for multiple instances of the class? Also, isn't memory allocated in both flash and SRAM. For large arrays, this could eat up SRAM quickly.

posted by David G 08 Feb 2014

Hello again Jeroen,

Sorry about that code - i'm mixing up my C with C++... Dynamic memory reserved with the 'new' operator uses an allocator which simply reserves memory then returns a pointer to the beginning address (e.g. there's no option to assign values while allocating memory). However, there's one very nasty work-around that I can think of off the top of my head, but it's not pretty. I'd recommend going with Erik's idea (he's always right!) and use a static since there's no point in creating an identical array each time you instantiate the class.

That being said, I wouldn't hold it against you if you're only planning on instantiating the class once, not looking to delve head-first into C++, and simply just want your code to compile for test purposes. If that's the case, then there's no shame in trying this work-around:

test::test()
{
    int tempArray[] = {660, 660, 510}; // Allows you to use brackets instead of assigning each value
    tones_freq = new int[3];
    for(int idx = 0; idx < 3; idx++)
        tones_freq[idx] = tempArray[idx]; // Copies each value into the tones_freq array
    delete[] tempArray; // free's the memory used by tempArray
}

This code would make any programmer cry, but it gets the job done with minimal confusion :)

In the end, though, I highly suggest you try out the other solutions using statics. Cheers!

-Chris

posted by Krissi Yan 08 Feb 2014

Thanks for all the help! Erik's solution worked for me.

posted by Jeroen Behaegel 09 Feb 2014