Roman’s answer is not correct. Constant functions still consume gas. However, you don’t pay for the gas usage when it runs in the local EVM. If a constant function is called from a transaction, it is not free. Either way, you are still consuming gas and loops are a good way to consume a lot.
EDIT - Here is an example to illustrate the point
pragma solidity ^0.4.19;
contract LoopExample {
bytes32[] proofs;
function addProof(bytes32 proof) public {
if (!hasProof(proof))
proofs.push(proof);
}
function hasProof(bytes32 proof) public constant returns (bool) {
for (uint256 i = 0; i < proofs.length; i++) {
if (proofs[i] == proof) {
return true;
}
}
return false;
}
}
And here are the gas consumption results for calling addProof
4 times:
addProof("a"): 41226
addProof("b"): 27023
addProof("c"): 27820
addProof("d"): 28617
You kind of have to ignore the very first call. The reason that one is more expense than the rest is because the very first push to proofs
will cost more (no storage slot is used before the 1st call, so the push will cost 20000 gas). So, the relevant part for this question is to look at the cost of addProof("b")
and then the increase with each call afterwards. The more items you add, the more gas the loop will use and eventually you will hit an out of gas exception.
Here is another example where you are only calling a constant function from the client:
pragma solidity ^0.4.19;
contract LoopExample {
function constantLoop(uint256 iterations) public constant {
uint256 someVal;
for (uint256 i = 0; i < iterations; i++) {
someVal = uint256(keccak256(now, i));
}
}
}
Here, if you call this through Remix, you'll see something like this in the output (Notice the comment on gas usage):

Finally, if you try to run this constant method from a client using too many iterations, you will get an error:
$ truffle console
truffle(development)> let contract;
undefined
truffle(development)> LoopExample.deployed().then(function(i) { contract = i; });
undefined
truffle(development)> contract.constantLoop.call(999);
[]
truffle(development)> contract.constantLoop.call(9999);
[]
truffle(development)> contract.constantLoop.call(99999);
Error: VM Exception while processing transaction: out of gas
at Object.InvalidResponse (C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\web3\lib\web3\errors.js:38:1)
at C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\web3\lib\web3\requestmanager.js:86:1
at C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\truffle-provider\wrapper.js:134:1
at XMLHttpRequest.request.onreadystatechange (C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\web3\lib\web3\httpprovider.js:128:1)
at XMLHttpRequestEventTarget.dispatchEvent (C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\xhr2\lib\xhr2.js:64:1)
at XMLHttpRequest._setReadyState (C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\xhr2\lib\xhr2.js:354:1)
at XMLHttpRequest._onHttpResponseEnd (C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\xhr2\lib\xhr2.js:509:1)
at IncomingMessage.<anonymous> (C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\xhr2\lib\xhr2.js:469:1)
at emitNone (events.js:91:20)
at IncomingMessage.emit (events.js:185:7)