Arrays

Can be fixed or dynamic sized at compile-time

  • T[k] -> fixed size of type T, with k elements

  • T[] -> dynamic size of type T

  • T[][5] -> 5 dynamic-sized arrays of T (read in reversed)

Storage arrays

Can be fixed or dynamic.

For fixed:

  • size must be specified during declaration.

  • Once declared, the array size cannot be changed.

  • Any attempt to reference beyond the last array position will result in an error.

For dynamic:

  • size of the array is not mentioned during the declaration.

  • size of the dynamic array can be changed during the runtime as elements are added/removed.

Methods

  • length

  • delete

  • push/pop (only for dynamic)

In a fixed-size array, we can not insert a new element as it increases the length of an array. To insert a new element in the dynamic size array we use the push method; this increases the length.

push(): append a zero-initialized element

push(X): append X

Init arrays

Fixed arrays:

  • all elements initialize to 0 -> fixedArr1[1] = 0

  • can partially assign, as seen in initializeFixedArr2(). fixedArr2 = [6,0,0]

  • length is 3, as elements are initialized to default values.

Dynamic arrays:

  • have not defined number of elements.

  • therefore no elements or default values exist.

  • cannot call dynArr[0]. will revert.

  • default length of 0.

  • must init w/ values first.

  • When calling get on dynArr it will revert, as no assignment has been done.

  • Can call length on an unassigned array, it will return 0.

Push and Pop

  • dynArr being initialized but unassigned.

  • call push(): this assigns 3 elements to it. its length is now 3.

  • dynArr[2]: returns 13

  • call pop(): removes last element, 13. length is now 2.

    • dynArr[2]: will revert. there is no element there anymore.

    • dynArr[1]: returns 12

Delete

  • call push() -> dynArr = [11, 12, 13]

  • delete dynArr[1] -> dynArr = [11, 0, 13]

  • length remains 3

  • push/pop modify length

  • delete does not modify length

Removing a specific element

  1. Remove array element by shifting elements from right to left

Copy all the elements forward, starting from the specified index. Pop the last element as its repeated.

  1. Remove array element by copying last element into to the place to remove

  • Deleting an element creates a gap in the array.

  • One trick to keep the array compact is to move the last element into the place to delete.

Memory Arrays

Only fixed-size memory array. Dynamic array cannot be created in memory. No push/pop available

  • new keyword is used to initialise arrays in memory.

Bad example

  • you can compile this, but calling test() will revert.

  • you could remove the assignment and the function will no longer revert - but obviously this achieves nothing.

Assignments from memory to memory only create references.

  • y, z and zz are all arrays in memory

  • Changes to one memory variable affect all others referencing the same data.

Layout in storage

Dynamic arrays

  • Storage slot of a dynamic array stores the length of the array; and updates it accordingly.

  • Dynamic array elements are stored elsewhere.

  • Why: compiler has no way of knowing how many elements there would be; cos dynamic, so it cannot store the elements consecutively starting from the storage slot at which the dynamic array is declared. Danger of clashing into the next storage slot which could hold some other state variable.

Location of array elements

hash(slot) = location of the first array element, and the rest follow

Nested dynamic arrays

  • s points to another array, s[0]

  • s[0] points to the series of elements, s[0] = [4,0,6]

example: if s[1] =5 and s[2] = 1
  • s[1] pointer would be stored beside s[0], and so forth

storage layout of dynamic nested arrays: https://www.youtube.com/watch?v=Zi4BANKFNP8

Storage pointers and Data Location Effects

  • myArray is not a separate unique array that is created from x.

  • its a pointer to the location in storage where coders resides.

  • modifying values through the storage pointer will affect both myArray and x.

  • Assignments between storage and memory (or from calldata) always create an independent copy

  • see: uint[] memory memArray = x;

  • Assignments from storage to a local storage variable also only assign a reference

  • see: uint[] storage myArray = x;

Assignments to storage always copy, even if sourcing from reference variables

Dangling references to storage array elements

  1. add(): Create a dynamic array with a single nested dynamic array uint256[][] s, such that s[0] = [4,0,6]

  2. fuckAround(): create a storage pointer to the last element in s, which is a pointer to s[0]; since there is only 1 element.

  3. pop s[0]

  4. push some hex value into the same storage location

Last updated