Solidity Tutorial: Arrays

Solidity Tutorial: Arrays

An average user might wonder why we have so many brackets '{,(,[' but for some of us programmers and engineers it means so much. Today I will be talking about the '[]' brackets, their usage and their importance in solidity programming for blockchain applications.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

contract Array {
    // Initializing an array
    uint[] public ray;
}

This is a primary array in solidity. The first 2 lines are the default way we start a solidity project, identifying our license and version. The contract is called Array and the function unit (Unsigned Integers, maximum value to the power of 256) declares our array by simply adding the [], the public is our visibility modifier and the function is named ray.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

contract Array {
    // Several ways to initialize an array
    uint[] public ray2 = [1, 2, 3];
}

This is another way of declaring an array by directly inputting the elements in our array.

Arrays in Solidity are a powerful tool for storing and manipulating large amounts of data in a smart contract. They allow for the creation of complex data structures that can be used to store information such as user balances, product listings, and more.

In Solidity, there are two types of arrays:

Static Array

In Solidity, a static array is a fixed-size array that is created at the time the contract is deployed and remains the same size throughout the lifetime of the contract. The size of the array is determined at compile time and cannot be changed at runtime.

Let us take a look at an implementation of a static array in solidity.

pragma solidity ^0.8.0;

contract StudentAges {
    // An array to store the ages of students in the class
    uint[] public studentAges;

    constructor() public {
        addStudentAge(18);
        addStudentAge(20);
        addStudentAge(21);
        addStudentAge(24);
        addStudentAge(25);
    }

    /**
     * Function to add a student's age to the array
     * @param age - the age of the student to add
     */
    function addStudentAge(uint age) public {
        // Push the student's age to the end of the array
        studentAges.push(age);
    }

    /**
     * Function to retrieve a student's age from the array
     * @param index - the index of the student in the array
     * @return - the age of the student
     */
    function getStudentAge(uint index) public view returns (uint) {
        // Return the age of the student at the specified index
        return studentAges[index];
    }
}

This is a static array. The array "studentAges" is created at the deployment time of the contract, and it is fixed size which means it can't be resized. The "push()" function is used to add a new element to the end of the array, but it does not resize the array. If the array is full, and we try to push more elements it will throw an error.

The contract, named "StudentAges," creates an array to store the ages of students in a class. It has two functions: "addStudentAge" and "getStudentAge." The "addStudentAge" function takes in an age as a parameter and adds it to the end of the studentAges array. The "getStudentAge" function takes in an index as a parameter and returns the age of the student at that index in the array. Both functions are marked as "public" which means they can be called by any external address. The getStudentAge is also a view function, which means it doesn't change the state of the contract.

Now let us take this code to remix and see what we are actually talking about and to as well interact with our smart contract.

  1. This is where we select which contract we want to deploy. In remix, we can have multiple contracts.

  2. Hit the deploy button.

  3. The transaction report for debugging (more on this later).

  4. We get a dropdown after deploying our contract successfully! We can test and interact with our contract here.

    But what really is all that at number 3?

  • The "from" field shows the address of the account that sent the transaction, which in this case is "0x5B3...eddC4"

  • The "to" field shows the address of the contract that was deployed, in this case the "StudentAges" contract (constructor)

  • The "value" field shows the amount of Ether that was sent with the transaction, which in this case is 0. Transactions on the Ethereum network are calculated in wei which is a much smaller unit of $eth.

  • The "data" field shows the data that was sent with the transaction, which in this case is "0x608...e0033"

  • The "logs" field shows any event logs that were emitted by the contract as a result of the transaction, which in this case is 0.

  • The "hash" field shows the unique transaction hash of the transaction, which in this case is "0x3c8...5e182"

  • The last line is the call to StudentAges.getStudentAge which is a function of the smart contract.

1 We inputted the index 0, and hit the getStudent button at 2 which shows us the age of the student at index 0. Remember the first index of an element in an array is 0 and progresses in that way. In 3 we get the age of the indexed student as 18. At 4 we get our successful transaction and looking at the contract on the right side of the screen we see that the first element studentAge is aged 18 which means our contract works!

Dynamic Array

A dynamic array in Solidity is a type of array that can change its size during runtime. It is created using the "bytes" or "string" data type, and its size can be changed using the built-in "push()" or "pop()" functions.

Here is an example of how you could use a dynamic array to store the ages of students in a class:

pragma solidity ^0.8.0;

// This contract stores and retrieves student ages on the Ethereum blockchain
contract StudentAges {
    // This array will store the student ages
    uint[] public studentAges;

    // This function allows for the addition of a single student age to the "studentAges" array
    function addStudentAge(uint age) public {
        // Pushes the input age to the "studentAges" array
        studentAges.push(age);
    }

    // This function allows for the retrieval of a student age at a specific index in the "studentAges" array
    function getStudentAge(uint index) public view returns (uint) {
        // Returns the age at the specified index in the "studentAges" array
        return studentAges[index];
    }
}

In this example, the studentAges array is a public variable that stores the ages of students in a class. The contract has two functions: addStudentAge which adds a new age to the array, and getStudentAge which returns the age of a student at a specific index in the array.

You can use the addStudentAge(age) function to add student ages and use the getStudentAge(index) function to get the age of students at a specific index in the array. Now let us interact with this contract.

We get an error when we try hitting all 3 buttons on the left, why? Well because there is currently nothing inside our array, naturally our contract call will not run through.

  1. We need to add a student for our array to have an element to work with. Here I inputted a student aged 2.

  2. I clicked the addStudent button then this time we get a successful transaction on the right denoted by the green check mark.

  3. I indexed 0 being the first index in an array.

  4. Clicked the getStudent button. We also immediately get our result which is age 2 just like we inputted in step 1.

  5. Indexed 0 for studentsAge at

  6. for the value of 2 as expected

  7. Showing our transaction and contract calls results.

It is also possible to iterate through the elements of an array using a for loop.

In the example I provided, the "studentAges" dynamic array is defined as a public variable, which means that anyone can access and view its contents. If the array was intended to store sensitive information, such as personal identification numbers, it would be better to define it as private and provide access controls to ensure that only authorized users can view the information.

Another important aspect to consider when using dynamic arrays in Solidity is gas usage. Because the size of a dynamic array can change during runtime, the amount of gas required to execute operations on the array can also change. This can be an issue when the array is large or if the contract is executed by numerous users. In these cases, it may be necessary to implement a mechanism to limit the size of the array or to increase the gas limit of the contract.

It is important to consider the use case and potential security implications when using dynamic arrays in Solidity and to thoroughly test the contract before deploying it to the blockchain.

Solidity arrays - Hints

getLength()

Getting the length means getting the number of elements in an array.

push

Append to array.
This will increase the length of an array by 1.

pop

Remove the last element from array.
Increases array length by 1.

remove

Delete does not change the array length.
Resets the value at index to its default value. Uint to 0, strings to '' '', and false for bool.

slice

Create a new array that is a subset of an existing array.
Used to extract a portion of an array, specified by a starting index and a length.

In Conclusion

In Solidity, an array is a data structure that allows you to store multiple values of the same type. Arrays can be defined with a fixed or dynamic size, and they can be declared as a variable or as a member of a struct or contract. Arrays in Solidity are indexed starting from zero, and they can be accessed using the square bracket notation (e.g. ray[0]). Additionally, Solidity supports multidimensional arrays, mapping and bytes data type, which is a dynamic-sized byte array similar to a string.

It is important to note that arrays stored in smart contract storage are limited and expensive in terms of gas consumption, so it's recommended to use them with caution and only when necessary. I personally say 'avoid dynamic arrays' because I feel it is much safer working with a Fixed Sized array.

Alright, super thanks to you for reading through! I hope you found this article insightful, plus stay tuned as I would be posting more solidity tutorials in this series and also even more Web3 content.