How variable length arguments are encoded in calldata
// Example: dynamic length data type sandwiched between two fixed length data types
function threeArgs(
uint256 a,
uint256[] calldata b,
uint256 c
) external {}
calldata for input values of 5, [1,2,3], 7
0xc6f922d0
0000000000000000000000000000000000000000000000000000000000000005 // first input argument
0000000000000000000000000000000000000000000000000000000000000060 // 60 - pointer to location of dynamic array data
0000000000000000000000000000000000000000000000000000000000000007 // third input argument
0000000000000000000000000000000000000000000000000000000000000003 // length of array data to look at
0000000000000000000000000000000000000000000000000000000000000001 // array values
0000000000000000000000000000000000000000000000000000000000000002 // .....
0000000000000000000000000000000000000000000000000000000000000003 // .....
Using a struct instead of an array will encode the variables directly into memory in order, since it knows in advance how big the struct is