Trying to set index to start at 1

I’m going back over the Ethereum smart contract 101 to really get it in my head.
This compiles.

I’m wanting to be able to enter the array/struct position +1
to call items, so the index will start at 1.

This bit works for the first item:

(people.length += 1)
… When I call index 1 I get the first entry. Index 2 results null.
I’m thinking I need to set a counter somewhere.

This is the contract:

pragma solidity 0.5.12;
import "./Ownable.sol";

contract HelloWorld is Ownable {

    struct Person {
      uint id;
      string name;
      uint age;
      uint height;
      
    }

    Person[] public people;
    
    
    function createPerson(string memory name, uint age, uint height) public payable {
        
        people.push(Person((people.length), name, age, height));
        /*(people.length +1) adds 1 to ID, so ID starts at 1.
        (people.length += 1) ... When I call index 1 I get the first entry. Index 2 results null tho.*/
       
       
    }
    
}

The Ownable:

pragma solidity 0.5.12;

contract Ownable {
    
    address public owner;
    
    modifier onlyOwner(){
        require( msg.sender == owner);
        _;
        
    }    
    
    constructor() public {
        owner = msg.sender;
        
    }   
    
    
}

You have created a person array, remember that array indexes always start at ZERO. In this case person.id is unrelated to the array index. people.push() will just add the new person to the next array index- which starts at zero.

If you really want to reference people by ID then you need to use a mapping like mapping (uint => Person). Try that. If you’re still stuck take a look at my solution below:

People using mapping
pragma solidity 0.5.12;
import "./Ownable.sol";

contract HelloWorld is Ownable {

    struct Person {
      uint id;
      string name;
      uint age;
      uint height;
      
    }

    // Person[] public people;
    uint256 numPeople;
    mapping (uint256 => Person) public people;
    
    
    function createPerson(string memory name, uint age, uint height) public payable {
        numPeople++;
        people[numPeople] = Person({
            id: numPeople,
            name: name,
            age: age,
            height: height
        });
        
        // people.push(Person((people.length), name, age, height));
        /*(people.length +1) adds 1 to ID, so ID starts at 1.
        (people.length += 1) ... When I call index 1 I get the first entry. Index 2 results null tho.*/
    }
}
2 Likes

I need it to be in order.
Yes index starts at 0,
but I should be able to +=1 the .length
and get registration numbers
starting at 1 somehow.

Mapping won’t help because
mapping isn’t ordered.

Thank you for providing
a solution so quickly tho.
I really appreciate it.

:thinking:

  • If you use a mapping indexed by ID then it would be in order as you can control what the ID’s are (see solution above)
    • As long as you keep track of the total number of people the entire collection could be iterated over in order with a simple loop
  • If you want to make arrays work but still have people accessed by an ID that starts at 1, then the code will need to translate ID’s into array indexes under the hood
    • I.e createPerson() would assign a new person an ID of people.length + 1 (not +=)
    • Can create a getter function that takes an ID and returns the Person for that ID (at array index ID-1)
Array solution
pragma solidity 0.5.12;
import "./Ownable.sol";

contract HelloWorld is Ownable {

    struct Person {
      uint id;
      string name;
      uint age;
      uint height;
      
    }
    
    Person[] public people;
    
    function getPerson(uint id) public view returns (string memory name, uint age, uint height) {
        require(id > 0 && id <= people.length, "invalid ID");
        Person memory p = people[id - 1];
        return (p.name, p.age, p.height);
    }
    
    function createPerson(string memory name, uint age, uint height) public payable {
        people.push(Person({
            id: people.length + 1,
            name: name,
            age: age,
            height: height
        }));
        
        // people.push(Person((people.length), name, age, height));
        /*(people.length +1) adds 1 to ID, so ID starts at 1.
        (people.length += 1) ... When I call index 1 I get the first entry. Index 2 results null tho.*/
    }
}
2 Likes

I.e createPerson() would assign a new person an ID of people.length + 1 ( **not +=** )

Ohhhhhh duuuuuuuhhhhh.

THANK-YOU!