Solidity – How to Initialize an Empty Array Inside a Struct

arraysmemorysoliditystoragestruct

Is there a mistake in the way I initialize Bar b in the function foobar?

contract Foo {

    struct Bar {
        address owner;
        uint[] x;
    }

    Bar[] public bars;

    function foobar(address a) public {
        Bar storage b = Bar(a, new uint[]) // will that be an array in storage?
        bars.push(b)
    }

}

Best Answer

There is no need to initialize storage arrays in Solidity. Only memory arrays has to be initialized before usage.

So in your case, no need to initialize x inside Bar as long as you are not assigning a value to one of the x indexes inside your foobar. Actually, making initialization in your code will consume gas for no reason.

The following code works well for your case:

function foobar(address a) public {
    Bar memory b;
    b.owner = a;
    //When 'b' is pushed to 'bars' array:
    // (1) 'b' will be converted from memory to storage.
    // (2) And 'x' inside it will be initialized automatically.
    bars.push(b); 
}

However, if you need to access x and push some value you can use push:

function foobar2(address a, uint x0) public {
    Bar memory b;
    b.owner = a;
    bars.push(b);
    //Trying: b.x[0] = x0; will generate error. Since, b.x is a memory array that is not initialized!
    bars[bars.length - 1].x.push(x0); //This will work fine!
}

Actually, you can still initialize your memory array, as an empty one, as follow:

function foobar3(address a) public {
    Bar memory b = Bar(a, new uint[](0)); //Thanks to "James Duffy" for his answer.
    bars.push(b);
}

Last thing to mention is that: If you have multi values, that you need to insert to your x array, then you can do this as follow:

function foobar4(address a, uint[] _x) public {
    Bar memory b = Bar(a, _x);
    bars.push(b);
}

Or as follow. But, this will consume more gas:

function foobar5(address a, uint[] _x) public {
    Bar memory b;
    b.owner = a;
    bars.push(b);

    Bar storage c = bars[bars.length - 1]; // Get the newly added instance of the storage struct
    for (uint i = 0; i < _x.length; i++) {
        c.x.push(_x[i]);
  }

Check full code at the nice EthFiddler: https://ethfiddle.com/fQI6Khgz3E