Data Location

In Solidity, data location refers to the location where a variable or function argument is stored. There are three data locations in Solidity: calldata, memory, and storage.

Calldata

calldata is a read-only data location that stores the function arguments passed by an external function call. Function arguments stored in calldata can only be read, but not modified.
Here's an example of using calldata:
function foo(uint[] calldata _data) external {
// do something with the _data array
}
In this example, _data is a uint array passed as an argument to the foo function. The calldata keyword indicates that the argument is stored in the calldata data location.
When we broadcast a transaction from an EOA, we include bytecode for the EVM to run. This bytecode is the calldata which includes an identifier for the function we're targeting and the arguments we're sending.
When we take an array as a parameter in an external function, it must be labeled as calldata. It is a read-only reference to the argument data. Other than being read-only, it behaves quite like memory.
calldata is not reserved for certain data types, but rather used for input parameters in external functions, and any data type that can be passed by reference can be used with it.

Memory

memory is a temporary data location that stores values during the execution of a function. Values stored in memory can be read and modified within the function, but are not persistent and are deleted when the function execution completes.
Here's an example of using memory:
function bar(string memory _str) external {
bytes memory strBytes = bytes(_str);
// do something with strBytes
}
In this example, _str is a string argument passed to the bar function. The memory keyword indicates that the argument is stored in the memory data location. The function converts the string argument to bytes and stores them in a bytes variable strBytes, which is also stored in memory.
the memory keyword is reserved for certain data types in Solidity. Specifically, it is used for value types such as uint, bool, bytes, and structs. When a value type is passed to a function as an argument, it is copied into memory.
On the other hand, reference types such as arrays, mappings, and strings are stored in storage by default, unless the calldata keyword is used.

Storage

storage is a persistent data location that is used to store state variables of a contract. Values stored in storage are written to and read from the blockchain and are persistent across function calls.
Here's an example of using storage:
contract MyContract {
uint myVar;
function setMyVar(uint _newValue) external {
myVar = _newValue;
}
function getMyVar() external view returns (uint) {
return myVar;
}
}
In this example, myVar is a state variable of the MyContract contract, and is stored in the storage data location. The setMyVar function writes a new value to myVar, which is then persisted to the blockchain. The getMyVar function reads the current value of myVar from storage and returns it.
It's important to use the correct data location for variables and function arguments in Solidity to ensure correct behavior and avoid errors in your smart contract code.