Section 01 · Definition
What is an int array in Solidity?
An int array is a list of whole numbers where each entry can be negative, zero, or positive. Each number sits at a numbered position, and the list can grow as your contract receives new entries.
Quick answer
What is an int array? An int array is an ordered collection where every entry is a signed whole number, meaning negatives are allowed. The default size is int256, so the most common shape in real contracts is int256[]. You add with push, read with index, and count with length, just like a uint array, but the cells can hold values below zero.
The keyword int is short for signed integer. Signed means the number type can represent both negative and positive values. The default size is 256 bits, so int on its own is the same as int256. Wrap any type with square brackets and you turn it into an array. So int256[] is a list of signed integers.
The mental model is the same row of boxes you saw in the uint array post, with one extra rule: each box can also hold a value below zero. The index still starts at zero. The length still grows by one on each push. The only thing that changes is the range of legal values inside.
Section 02 · Real use case
A simple real world example
An IoT contract that records hourly temperature readings in degrees Celsius. Some readings are below zero in winter, some are above in summer. The list grows once an hour.
The contract needs three operations. Append a new reading. Read any past reading by its position. Know how many readings have been captured so far. A uint array cannot represent the winter readings, so an int array is the right choice.
The same shape works for profit and loss tracking on a small DeFi contract, score deltas in a game leaderboard where players can lose points, or signed quantity adjustments in an inventory system. Any time the value can dip below zero, reach for int256[].
Section 03 · Smart contract
A complete int array smart contract
A small TempLog contract with one storage array and four functions. Short enough to read in two minutes, complete enough to deploy in Remix.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract TempLog {
// 1. The storage array. Holds positive and negative readings.
int256[] public readings;
// 2. Append a new temperature reading.
function addReading(int256 value) external {
readings.push(value);
}
// 3. Read a single reading by its index.
function getReading(uint256 i) external view returns (int256) {
require(i < readings.length, "index out of range");
return readings[i];
}
// 4. Return how many readings have been captured.
function totalReadings() external view returns (uint256) {
return readings.length;
}
}Open Remix at remix.ethereum.org, create a new file, paste the contract, compile with the 0.8.20 compiler, and deploy to the JavaScript VM. In the deploy panel you can call addReading with values like 22 and -12 and confirm both work.
Section 04 · Line by line
What every important line does
Walk through the contract one block at a time. Most lines mirror the uint array post, with the small but meaningful change at the type.
int256[] public readings;The type int256[] declares a dynamic array of signed 256 bit integers. Solidity allocates an empty array in storage. The keyword public generates a free getter so off chain code can call readings(i) directly.
function addReading(int256 value) external {
readings.push(value);
}The function takes a single signed integer and appends it to the end of the list. Because the parameter type is int256, the caller can pass -273, 0, or 40 with no extra ceremony. readings.push grows the array by one slot.
function getReading(uint256 i) external view returns (int256) {
require(i < readings.length, "index out of range");
return readings[i];
}Notice that the parameter i is a uint256, not an int256. Indexes are counts, never negative. The return type is int256 because the value at that index can be negative. The require guard reverts before the lookup ever runs when the index is out of range.
function totalReadings() external view returns (uint256) {
return readings.length;
}The length is always reported as a uint256 regardless of the array's element type. Lengths cannot be negative, so the unsigned type is the natural fit.
Section 05 · Reading and writing
Add data, get data, count items
The three operations look identical to the uint array surface area. The only difference is the type of value flowing through them.
Adding data uses readings.push(-12). The minus sign in front of the literal makes it negative. There is no special syntax for signed values; you just type the number you want.
Reading data uses bracket lookup. The first reading is readings[0], the second is readings[1], and the most recent reading sits at readings[readings.length - 1] when the array is non empty.
Counting items uses readings.length. The result is a uint256 that you can compare in a require guard, use as an index bound for the methods in Section 06, or simply return.
Section 06 · Methods
Add the array methods to TempLog, one function at a time
The TempLog contract from Section 03 only has push, indexed read, and length. Here are four more methods every beginner should know, added one function at a time so you can paste each into the same contract and try it in Remix as you go.
Start with the TempLog contract you already have. Each function below goes right after the existing ones inside the contract body. None of them needs a for loop, and each one teaches a distinct rule of Solidity array storage.
Function 1. Remove the last reading with pop
function dropLast() external {
require(readings.length > 0, "empty");
readings.pop();
}readings.pop() drops the last reading and shrinks the length by one. The require guard is critical: calling pop on a zero length array triggers a panic and the transaction reverts. Add the guard whenever the array can be empty at call time.
Function 2. Reset one slot with delete by index
function clearReading(uint256 i) external {
require(i < readings.length, "out of range");
delete readings[i];
}delete readings[i] writes the type default into the targeted slot. For an int the default is plain zero, not the minimum negative number, so the call sets that reading to zero without changing the array length. If your code uses zero as a meaningful reading, mark the slot some other way, for example with a companion mapping that tracks which indexes are live.
Function 3. Wipe the entire array with delete on the variable
function clearLog() external {
delete readings;
}delete readings on the whole array resets every slot to zero and sets the length back to zero in one line. Solidity does this in a single storage operation. After the call, every indexed read goes out of range, and the next push starts a fresh log from index zero.
Function 4. Overwrite a reading with direct assignment
function updateReading(uint256 i, int256 value) external {
require(i < readings.length, "out of range");
readings[i] = value;
}Bracket assignment writes a new signed value into the slot at the given index. The bounds check stops the call early when the index is past the end. The length does not change because the slot already existed, and the new value can be any signed integer including a negative one.
After adding the four functions, your TempLog contract now covers all five basic array operations: push, pop, delete by index, delete on the variable, and bracket assignment. Compile in Remix, redeploy, and try each new function from the deploy panel with both positive and negative inputs.
pop and delete are not the same thing
pop actually removes the last reading and changes the length. delete readings[i] only resets that one slot to plain zero, not to the minimum signed value, and leaves the length unchanged. delete readings resets every slot to zero and sets the length back to zero. Pick pop when you want to shrink, pick delete when you want to reset.
Section 07 · Removal
Function 5. Remove any reading with swap and pop
When you need to drop a reading from the middle of an int array and you do not care about preserving the chronological order, the swap and pop pattern removes it in constant time. Two writes and a pop, no iteration.
Move the last reading into the slot you want to drop, then call pop. The targeted entry disappears, the last entry takes its place, and the length shrinks by one. The trade off is that the chronological order of readings is no longer guaranteed, which can matter for a temperature log. Use this pattern when order is not part of the public contract.
function removeAt(uint256 i) external {
uint256 last = readings.length - 1;
require(i <= last, "out of range");
if (i != last) {
readings[i] = readings[last];
}
readings.pop();
}The if (i != last) guard skips a tiny self assignment when the caller asks for the last slot. After the function returns, the array length is one less than before and the previous last reading sits at the position that was removed. The sign of the moved value does not matter. Solidity treats negative and positive entries identically here.
Section 08 · More patterns
Return the whole array, build memory arrays, declare fixed length
Three more patterns added one at a time. The first goes onto TempLog as Function 6. The other two are reference patterns you will reuse in other contracts.
Function 6. Return the whole array as one value
Returning the whole array works when the log is small and the function is marked as a view. The return type uses the memory location keyword because the caller receives a fresh copy of the data, not a pointer into storage. Add this function next to the rest in TempLog.
function allReadings() external view returns (int256[] memory) {
return readings;
}Pattern 1. Build a temporary memory array
Memory arrays let you build a temporary signed list inside a function without writing to storage. The size is fixed at the moment you create them with new, so you cannot push or pop on a memory array. Set the entries by index after creation. This pattern lives on its own; it does not extend TempLog because the function is pure.
function buildSampleBatch() external pure returns (int256[] memory) {
int256[] memory batch = new int256[](3);
batch[0] = -10;
batch[1] = 0;
batch[2] = 25;
return batch;
}Pattern 2. Declare a fixed length storage array
Fixed length storage arrays declare the size inside the brackets. You cannot push or pop on a fixed length array because the size never changes. Every slot starts at zero and you write into the slots by index. This is a separate state variable on its own contract, not an extension of the dynamic TempLog array.
// Seven slot signed array baked into storage.
int256[7] public weeklyReadings;
function setDay(uint256 i, int256 value) external {
require(i < 7, "out of range");
weeklyReadings[i] = value;
}You cannot resize a dynamic storage array by writing to length
In Solidity 0.5 you could shrink an array with readings.length = newLen. That assignment was removed in 0.6 and the modern compiler rejects it. Grow with push. Shrink with pop or delete. Reset fully with delete readings. The length property is read only in every current Solidity version.
Section 09 · Final contract
The complete TempLog with all six methods together
The original TempLog from Section 03 plus the six methods you have added function by function. One paste ready file you can drop into Remix and try every operation, including signed values, in a single session.
The contract below is the full version. The first three functions are the originals: push wrapped as addReading, indexed read wrapped as getReading, and the length read wrapped as totalReadings. The remaining six are the additions you walked through in Sections 06 to 08, and every one of them accepts negative values the same way it accepts positive ones.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract TempLog {
int256[] public readings;
// Append a new temperature reading.
function addReading(int256 value) external {
readings.push(value);
}
// Read a single reading by index.
function getReading(uint256 i) external view returns (int256) {
require(i < readings.length, "out of range");
return readings[i];
}
// Return how many readings have been captured.
function totalReadings() external view returns (uint256) {
return readings.length;
}
// Function 1. Remove the most recent reading with pop.
function dropLast() external {
require(readings.length > 0, "empty");
readings.pop();
}
// Function 2. Reset one slot to zero with delete by index.
function clearReading(uint256 i) external {
require(i < readings.length, "out of range");
delete readings[i];
}
// Function 3. Wipe the whole log with delete on the variable.
function clearLog() external {
delete readings;
}
// Function 4. Overwrite a reading with direct assignment.
function updateReading(uint256 i, int256 value) external {
require(i < readings.length, "out of range");
readings[i] = value;
}
// Function 5. Remove any reading with swap and pop.
function removeAt(uint256 i) external {
uint256 last = readings.length - 1;
require(i <= last, "out of range");
if (i != last) {
readings[i] = readings[last];
}
readings.pop();
}
// Function 6. Return the whole array as memory.
function allReadings() external view returns (int256[] memory) {
return readings;
}
}Open Remix, paste the contract, compile with the 0.8.20 compiler, and redeploy to the JavaScript VM. The deploy panel now lists nine callable buttons. Push values like 22, -12, and 35 with addReading, then call allReadings and confirm the signs survive the round trip through storage. Every method you have learnt in this post lives in this single file.
Section 10 · Beginner mistakes
Five mistakes new Solidity developers make with int arrays
Using uint when the value can be negative
If your domain has any chance of negatives, pick int from the start. Migrating later is painful because the storage layout is different and existing data does not transfer cleanly.
Trying to use an int as an index
Indexes must be unsigned. readings[-1] does not compile. To grab the most recent value use readings[readings.length minus 1] after checking the length is greater than zero.
Mixing signed and unsigned in arithmetic
Solidity refuses to let you add an int to a uint without an explicit cast. Beginners often see the error and add casts in random places until the code compiles. Read the message and pick the type the value belongs to.
Forgetting the empty array case
Any function that touches readings[0] or pops from the array breaks when the list is empty. The require(readings.length > 0, ...) guard at the top of dropLast is what prevents that panic. Add the same guard whenever your function depends on at least one element.
Assuming int8 saves gas in an array
Smaller signed types only save gas when packed inside a struct. In a plain array each element still consumes one full storage slot, so int8[] uses the same storage as int256[]. Stick with int256 unless you have measured the savings.
Section 11 · Practice task
Try this on your own
A small extension that locks in the push, pop, delete, swap and pop, and bracket assignment operations on a signed array. Try to ship it without copying from the contracts above.
Build a ProfitLoss contract
Add an int256[] dailyPnL array and an int256 runningTotal state variable. record(int256 value) pushes the value and adds it to runningTotal. dropLast() pops the last value and subtracts it from runningTotal with a length guard. clearDay(uint256 i) reads the slot, subtracts it from runningTotal, and then runs delete on that slot. removeAt(uint256 i) does the same subtraction and then uses swap and pop. clearAll() resets both the array and runningTotal with delete. Bonus: emit an event each time a negative day is recorded so a dashboard can flag it.
Deploy the contract in Remix, push three values like 100, -40, and 25, and read runningTotal from the public getter. The expected answer is 85. Then call removeAt(1) and confirm that runningTotal jumps to 125 because the -40 entry has been pulled out. The lesson is the same as the uint highscore drill: aggregates that live next to the array must update on every method that mutates it.
Section 13 · FAQ
Frequently asked questions
What is an int array in Solidity in simple words?
An int array is an ordered list of whole numbers where each entry can be negative, zero, or positive. The default type is int256, so the most common shape is int256[]. The first index is zero, and the array grows by one each time you push a new value.
What is the difference between int and uint arrays in Solidity?
An int array can hold negative values, a uint array cannot. Both default to 256 bits and both share the same operations: push, indexed read, and length. Pick uint when every value is at or above zero. Pick int the moment any value can dip below zero.
How do I add a negative number to a Solidity array?
Declare the array as int256[] and call push with the value. For example readings.push(-12) appends a negative twelve at the end. The minus sign is part of the literal. The same line on a uint array would be a compile error.
Can I use a negative index on a Solidity array?
No. Array indexes are always unsigned in Solidity. To read the last value use readings[readings.length minus one] after checking the length is greater than zero. Trying to use a negative literal as an index produces a compile error.
What is the range of int256 in Solidity?
int256 can hold any whole number from negative two to the power of two hundred fifty five up to two to the power of two hundred fifty five minus one. That is more than enough room for any temperature, profit and loss value, or signed counter you are likely to track on chain.
Does Solidity protect int arrays from overflow?
Yes, since Solidity 0.8 every signed and unsigned arithmetic operation reverts on overflow or underflow by default. You only opt out of that protection by wrapping the math in an unchecked block, and you should only do so when you have proven the math cannot overflow.
How do I remove the last reading from an int array?
Call .pop on the array, for example readings.pop(). The function removes the last reading and shrinks the length by one. pop reverts the transaction when the array is empty, so guard the call with require(readings.length > 0, ...) when the array can be empty at call time.
What does delete do on an int array slot?
delete on a single slot like delete readings[2] resets that slot to plain zero, not to the minimum signed value, and leaves the length unchanged. delete on the whole array like delete readings resets every slot to zero and sets the length to zero in one line. delete never frees the storage itself; it just writes the default value in place.
How do I remove a reading from the middle of an int array without a loop?
Use the swap and pop pattern. Copy the last reading into the slot you want to remove with readings[i] = readings[readings.length - 1], then call readings.pop(). The targeted entry disappears in constant time. The chronological order of the remaining readings is no longer guaranteed.
Can I shrink a Solidity int array by setting its length?
No. Solidity 0.5 allowed readings.length = newLen, but the assignment was removed in 0.6 and the modern compiler rejects it. Grow the array with push, shrink it with pop or delete, and reset it fully with delete readings. The length property is read only in every current Solidity version.