3

How to initialize an array inside the function and push items into it? I'm not gonna initialize outside the function.

Here's my code:

function tokenOfOwner(address owner) public virtual returns (uint256[] memory) 
{
    uint256[] storage _ownerAmount;
    uint256 amount = ERC721.balanceOf(owner);
    for(uint256 i = 0; i< amount ; i++)
    {
        _ownerAmount.push(_ownedTokens[owner][i]);
    }
    return _ownerAmount;
}

The error message shows:

TypeError: This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour.
1
  • Could you maybe add comments to your code, as there are functions and the entire contract being called inside of it? I am sure we will be able to find a quick solution here. As there should be no obsticale to initializing an array inside the function and push values inside of it.
    – Sky
    Commented Jan 19, 2022 at 11:17

2 Answers 2

5

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

Is perfectly normal as uint256[] storage _ownerAmount; is not initialized, meaning that it defaults to slot 0 possibly overwriting whatever is already occupying that slot.

However, looking at your code you probably don't need a dynamic storage array. Only dynamic storage arrays can be resized (pushed to / popped from), this makes sense when the number of elements in unknown, but that is not your case due to :

uint256 amount = ERC721.balanceOf(owner);

A more gas efficient implementation could rely only on static memory arrays with fixed size, such as :

function tokenOfOwner(address owner) public virtual returns (uint256[] memory) 
{
    uint256 amount = ERC721.balanceOf(owner);
    uint256[] memory _ownerAmount = new uint[](amount);
    for(uint256 i = 0; i< amount ; i++)
    {
        _ownerAmount[i] = _ownedTokens[owner][i];
    }
    return _ownerAmount;
}
4
  • Isn't _ownerAmount a dynamic array in your example? Commented May 4, 2023 at 8:48
  • 1
    No because it's a memory array and therefore has a fixed size , you cannot push or pop it as you would for a storage array.
    – hroussille
    Commented May 4, 2023 at 10:23
  • So, all memory arrays are static/fixed-size? Commented May 4, 2023 at 10:39
  • 1
    Yes, sorry for the confusion as the docs states that uint[] is dynamic and uint[K] is static, I use static / dynamic to refer to the possibility of changing the size of the array at execution time using .push() or .pop , for this the documentation is quite clear : > Dynamically-sized arrays can only be resized in storage. In memory, such arrays can be of arbitrary size but the size cannot be changed once an array is allocated.
    – hroussille
    Commented May 5, 2023 at 12:22
2

I am not sure about the end-functionality of your code in the terms of what you are looking to accomplish (Gater all the values of all the tokens owner has?)

But this commented code should help, I tried to make it as simple as possible.

pragma solidity ^0.7.0;

contract Function{
 
 function tokenOfOwner(address owner) public virtual returns (uint256[] memory) 
{

    uint256 amount = ERC721.balanceOf(owner);
    _ownerAmount = new uint256[](amount); //Creates an array of "amount" length
    
    for(uint256 i = 0; i< amount ; i++)
    {  
        _ownerAmount[i] = //Plug in the value you wish to record;
    }
    return _ownerAmount;
}
  
   
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.