0

How can I push a value into an dynamic sized array within a function?

I have a function which builds an array dynamically to use this as a function argument afterwards:

function autoMintBatch(...) {
    uint32[] xList;
    uint32[] yList;

    // ... y is declared properly ...

    yList.push(y);

    for (uint256 i = 0; i < idList.length; i++) {
        xList.push(x++);
    }

}

I get the following compilation error:

TypeError: Member "push" is not available in uint32[] memory outside of storage.

But when I change the variable declaration to storage like:

uint32[] storage xList;

another error appears:

TypeError: This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour.

Is there any way to build an array dynamically within a function?

delete
  • 18,144
  • 15
  • 48
  • 79
  • I covered this exact topic as a part of [this answer](https://stackoverflow.com/a/68010807/1693192) - see if it helps you. – Petr Hejda Oct 22 '21 at 17:01

3 Answers3

0

Assign the result of "x++" in a variable inside the function and then try to push the variable inside the array. Remember to create a state variable for the array. This worked for me

Item[] public items;

event MarketItem(
    bytes32 title,
    uint8 price,
    bool sold,
    bool published,
    address owner
);

mapping(address => Item) public itemToOwner;

function addItem(bytes32 _title, uint8 _price) public {
    Item memory newItem = Item({
        title: _title,
        price: _price,
        sold: false,
        published: true,
        owner: msg.sender
    });
    items.push(newItem);
}
RainbowWzrd
  • 1
  • 1
  • 1
0

Only dynamic storage arrays can be resized (push/pop).

In your case better implementation could rely on static memory array with fixed size, such as:

function autoMintBatch(...) public virtual returns (uint256[] memory) 
{
    ...
    uint256[] memory xList = new uint[](idList.length);
    for(uint256 i = 0; i< amount ; i++)
    {
        xList[i] = y++;
    }
    return xList;
}
Platinum
  • 68
  • 10
0

As is stated in the first error, you cannot push or pop elements from memory arrays. A dynamic memory array is only dynamic in the sense that you can determine its size at runtime:

uint[] memory dynamicMemArray = new uint[](size);

As for the second error, storage variables must refer to actual storage (i.e., state variables) and state variables cannot be declared in local scope (inside a function).

So you can't do this:

function doesSomethingWithArray(uint x) ... {
    uint[] storage dynamicStorageArray;
    dynamicStorageArray.push(x); // TypeError
    ...
}

but you can do something like this:

uint[][3] public dynamicStorageArrays; // state variable (stored in storage)
function doesSomethingWithArray(uint x) ... {
    // local scope
    uint[] storage dynamicStorageArray = dynamicStorageArrays[1];
    dynamicStorageArray.push(x);
    ...
}

where dynamicStorageArray is essentially a pointer to one of the dynamic arrays defined in the state variable above (hence the error).

So, you have two options, either declare a state variable that you can reference inside the function (which may be expensive since you're now playing with storage) or, as @Petr Hejda mentions in a comment, calculate the desired size of the array first, then declare a dynamic memory array of that size.

Adham
  • 121
  • 7