What's better in that context - `for` or `while` - c++

I've read somewhere that one should use a for loop when you are iterating over some sort of array/sequence/list/whatever you call it and a while loop when your loop needs to stop at a certain condition.
So, what if I have something like this
int len = 0;
for(; s[len] != '\n'; ++len) {
// some processing
if (someCondition) {
return len;
}
}
// if done iterating, return len
return len;
Is this okay to use the for loop in this context or would a while loop be preferable?

I'd probably write it this way:
int len;
for (len = 0; s[len] != '\n'; ++len) {
...
}
return len;
Just because then I say in the for statement what the range is I'm interested in (index 0 up to the first newline character).
I generally choose between for and while on the basis of what the code looks like, rather than on where I stand in the hairsplitting semantics argument what the difference is between "some kind of range" vs "the period from now until some condition is false". I don't think it's a problem to play around a bit with for. The third part of the statement is "specially visible" in the way that an increment at the end of a while loop isn't, and I think that's enough to justify using it with a minor contortion like your empty first part.

The for loop is OK. You have the increment ++len at the place of loop control, which I find preferable. You don't forget it somewhere at the end of the loop body. And it even works well when you use continue.

Well, a for loop is the only one that's going to accept that kind of syntax so that's what I'd say you should use. Besides that...it actually doesn't really matter in the slightest. Do what is easy to read.

Given your quoted code, I'd use a for loop, but I would put the initializer inside the for statement as an assignment:
int len; // <== Not here
for (len = 0; s[len] != '\n'; ++len) { // <== Here
// some processing
if (someCondition) {
return len;
}
}
This is exactly what the for structure is for: An initialization, test, and increment.

I would use a While and put the len incrementation inside the condition verification s[++len] != '\n' :D
But I guess it's what flavour you prefer really :)

You're iterating, and a for loop is more compact. You can achieve the same thing in either case anyway, but for this I prefer to use for because you have all the loop drivers (condition, counter increase) in the beginning.
int len = 0;
while (s[len] != '\n')
{
// do stuff
if (something) return len;
++len;
}
return len;
vs.
int len;
for (len = 0; s[len] != '\n'; ++len)
{
// do stuff
if (something) return len;
}
return len;

It is a matter of taste. Both are equivalent.
But with years I have happend to really prefer the while loop over for loop. I prefer when lines are short, and the for has a tendency to put 3 different steps in the same line.
int i=0;
while(s[i] != '\n')
{
// some processing
if (someCondition)
{
return i;
}
++i;
}
but as i said, it's a matter of taste.

Personally, I'd go with this:
int len = 0;
for (; s[len] != '\n'; ++len) {
// some processing
if (someCondition) {
break;
}
}
// if done iterating, return len
return len;
But really, it's all down to readability, as there's no real semantic difference between for and while loops. Use whatever format you feel conveys the meaning of your code the best. In the above case I chose for because of the len loop variable, if that wasn't there I would have went with while.

It really doesn't matter. They are equivalent in terms of efficiency. You could do either of the following:
for(; s[len] != '\n'; len++) { ... }
while(s[len] != '\n') { ... len++; }
The for loop is perhaps more easily readable in this case, and the while is perhaps a bit more clever, but they're really functionally equivalent.
EDIT: True, the for doesn't increment the counter until after the first loop. Fixed it.

I see majority of the post are using for.
This post here will give you idea in case you want to pursue with while.
#include <stdio.h>
main ()
{
int counter=0;
while(somecondition) {
if (s[counter]!='\n')
{
//some processing
}
++counter;
}
}
return len;

What about foreach!
int len = 0;
for each (char& c : s) {
// some processing
if (someCondition || c=='\n') break;
len++;
}
// if done iterating, return len
return len;

Related

Error: Char 34: runtime error: addition of unsigned offset to 0x603000000070 overflowed to 0x60300000006c (stl_vector.h) (C++)

I have been trying to solve the sorted Squares leetcode problem (https://leetcode.com/explore/learn/card/fun-with-arrays/521/introduction/3240/), and I am mostly through it. However, I get the above error. Following is my code
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int start = 0;
int end = nums.size()-1;
vector<int> final(nums.size());
int finalIdx = final.size()-1;
int sqr = 0;
while(start<=end){
if (abs(nums[start])<abs(nums[end])){
sqr = nums[end]*nums[end];
final[finalIdx] = sqr;
finalIdx--;
end--;
}
if (abs(nums[start])>abs(nums[end])){
sqr = nums[start]*nums[start];
final[finalIdx] = sqr;
finalIdx--;
start++;
}
else if(abs(nums[start])==abs(nums[end])){
sqr = nums[end]*nums[end];
final[finalIdx] = sqr;
finalIdx--;
final[finalIdx] = sqr;
finalIdx--;
start++;
end--;
}
return final;
}
}
};
The issue lies in my loop condition I believe. When I change the condition to start<end, I have no compile error, but the first element of the output array (final) is always 0, which I assume is by default. However, when I try to do start<=end in order to add a condition that handles the start==end case, I get the above error. I would like to understand why this is happening so I can rectify the issue. Thanks!
First, that's not a "compile error" ; it's a runtime error (and the error message reported says as much.
That said, the issue stems from the condition of start <= end landing on the = part of that condition. Eventually that is guaranteed to happen, save for one very specific set of circumstances:
start = (end-1)
abs(num[start]) == abs(num[end])
When that happens, your code will dump two values to the output vector, and both increment start and decrement end. The start and end indexes effectively swap values, the while condition is no longer true, and the loop will now cleanly exit.
In all other circumstances start and end will eventually land on the same index. When that happens your dual-push logic will dump the same value twice into the target vector, and that is where the issue manifests. There is only one value left to push (and start and end both reference it by index). Therefore you're going to push one more value into your target vector than you have space for, and the runtime exception ensues.
The fix is simple. Stop trying to be smart about short circuiting in three different conditions when in reality you only need one and a master-else. The computational requirements are the same no matter what, and in the end all you need is this:
class Solution
{
public:
std::vector<int> sortedSquares(std::vector<int> const &nums)
{
std::vector<int> final(nums.size());
int start = 0;
int end = nums.size()-1;
int finalIdx = final.size()-1;
while(start<=end)
{
if (abs(nums[end]) < abs(nums[start]))
{
final[finalIdx--] = nums[start]*nums[start];
++start;
}
else
{
final[finalIdx--] = nums[end]*nums[end];
--end;
}
}
return final;
}
};
If you really want all three conditions in your code, it is possible, but not warranted, and the special case circumstances don't justify doing it. Regardless, see below:
class Solution
{
public:
std::vector<int> sortedSquares(std::vector<int> const &nums)
{
std::vector<int> final(nums.size());
int start = 0;
int end = nums.size() - 1;
int finalIdx = final.size() - 1;
while (start <= end)
{
if (abs(nums[start]) < abs(nums[end]))
{
final[finalIdx--] = nums[end] * nums[end];
end--;
}
else if (abs(nums[end]) < abs(nums[start]))
{
final[finalIdx--] = nums[start] * nums[start];
start++;
}
else // !(a<b || b<0) implies (a == b)
{
int sqr = final[finalIdx--] = nums[end] * nums[end];
if (end != start)
{
final[finalIdx--] = sqr;
}
--end;
++start;
}
}
return final;
}
};

Is there are truly neat way to do 'if none in collection' test?

so you have a collection and you want to see if NONE of the items in it pass a test. doing the if ANY pass test is easy, and would look something like this:
for (int i = 0; i < collectionSize; i++)
{
if(ItemPasses(collection[i]))
{
// do code for if any pass
break;
}
}
but to do the opposite, if NONE pass test, I cant think of a truly neat way to do it, here are the ways I can come up with:
// nice to look at but uses an unecessary variable 'anItemPassed'
bool anItemPassed = false;
for (int i = 0; i < collectionSize; i++)
{
if(ItemPasses(collection[i]))
{
anItemPassed = true;
break;
}
}
if (!anItemPassed)
{
//...
}
//---------------------------------------------------------------------------------
// as efficient as possible but uses gotos.. nobody likes gotos.. lable stuff really isnt that neat.
for (int i = 0; i < collectionSize; i++)
{
if (ItemPasses(collection[i]))
{
goto ItemPassed;
}
}
//...
ItemPassed: { }
//-------------------------------------------------------------------------
// as efficient as possible and doesnt use the rarely used (and usually poorly supported in IDEs) goto/lable stuff, but doesnt use any nice loop construct, does it all manually
int i = 0;
for (; ; )
{
if (i >= collectionSize)
{
//...
break;
}
if (ItemPasses(collection[i]))
{
break;
}
i++;
}
I dont really like any of those, I've always wondered why there was never a construct like:
for (int i = 0; i < collectionSize; i++)
{
if (ItemPasses(collection[i]))
{
break;
}
}
finally //executed if the loop terminates normally, not via breaks.
{
//...
}
so in short my question is: Is there are truly neat way to do 'if none in collection' test? if not, is there a reason why the above wouldn't be a good language feature?
EDIT:
I instantly regret putting c++ in the tags. I know there are nice functions to do this, but assuming the boost libraries or whatnot, were also written in c/c++ presumably they encountered the same problem I have. even if these functions are built in to the language, saying 'just call this function' isn't the answer I was looking for in this case.
so maybe I will focus on the last part of my question: Is there a reason why the above wouldn't be a good language feature?
in my view not having it would be like not having the 'else' keyword to go with 'if'
For C++ it's pretty trivial (C++11 with none_of, C++14 with the auto lambda)
bool noneExist = std::none_of(std::begin(collection), std::end(collection), [](auto &item){
return item.matchesCondition(); // any evaluation can go here, or you could just supply an existing functor instead of a lambda
});
I assign to a bool here, but you could as easily wrap it in an if statement (this assumes an existing function or functor object named MatchCondition, a lambda would work, but that's a lot to read in an if condition):
if(std::none_of(std::begin(collection), std::end(collection), MatchCondition)){
//run your "if none of the above matched" code here.
}
And the old C++98 method for completion:
if(std::find_if(collection.begin(), collection.end(), MatchCondition) == collection.end()){
//run your "if none of the above matched" code here.
}
"Truly neat" sounds a bit opinion based but here are a few options:
#include <iostream>
#include <algorithm>
#include <vector>
bool itemPasses(int i) {
return i > 10;
}
void printIfNonePass1(const std::vector<int>& collection) {
if (std::none_of(collection.cbegin(), collection.cend(), itemPasses))
std::cout << "None pass\n";
}
void printIfNonePass2(const std::vector<int>& collection) {
auto iter = collection.cbegin();
for(; iter != collection.cend(); ++iter) {
if (itemPasses(*iter))
break;
}
if (iter == collection.cend())
std::cout << "None pass\n";
}
void printIfNonePass3(const std::vector<int>& collection) {
size_t i = 0;
for(; i != collection.size(); ++i) {
if (itemPasses(collection[i]))
break;
}
if (i == collection.size())
std::cout << "None pass\n";
}
bool checkIfNonePass(const std::vector<int>& collection) {
for(int item : collection) {
if (itemPasses(item))
return false;
}
return true;
}
void printIfNonePass4(const std::vector<int>& collection) {
if (checkIfNonePass(collection))
std::cout << "None pass\n";
}
int main() {
std::vector<int> collection{4,2,10,3};
printIfNonePass1(collection);
printIfNonePass2(collection);
printIfNonePass3(collection);
printIfNonePass4(collection);
}
I like to achieve this by performing the no-match scenario by comparing the iterator against the max.
int i;
for (i = 0; i < collectionSize; i++)
{
if (ItemPasses(collection[i]))
{
// do code for if any pass
break;
}
}
if (i == collectionSize)
{
// perform no-match operations
}
There is no need for c++14, or c++11. Something like this should do what you want.
if (find_if(collection.begin(), collection.end(), ItemPasses) == collection.end()) {
//code if none passes
}
edit: Adding c++11 solution as response to comment.
if (none_of(collection.begin(), collection.end(), ItemPasses)) {
//code if none passes
}
2:nd edit: Answer the question.
I think you are interested the internal realization of the algorithm but not applying standard algorithms.
Usually the loop is written the following way
CollectionType::size_type i = 0;
while ( i < collectionSize && !ItemPasses(collection[i]) ) ++i;
return ( i == collectionSize );
The same can be written with iterators
while ( first != last && !ItemPasses( *first ) ) ++first;
return ( first == last );
This approach can be applied also in C programs.
In my opinion, there is no orthgonality in control structures in many languages C included.
The need is obvious, and the language should simplify the work of the programmer, albeit no much will for work and/or change is done in that direction on the side of control structures.
In 1992, I had done a complete proposal and implementation of an orthogonal set of control structures, that could be used in many languages, and the construct you request was included, that is just to confirm the recurrency of the argument and the validity of the need.
The functions of C++ while permit an elegant solution, do not solve the need any way.
An alternative solution to what you already presented is to put the code you need inside the for construct. So the code would become as bellow while the function finalizationCode() should return false.
for (int i = 0; i < collectionSize ? true : finalizationCode(); i++)
It may be better to put the || construct instead of the if ( ? : ).
So in that case:
for(int i=0 ; i < collectionSize || finalizationCode() ;i++)
It is anyway guaranted that finalizationCode will be executed only when the condition i<collectionSize
is false.

Taking in array of unknown size in c++

Ok I am extremely new to programming, and I am taking a c++ class. Basically for the current project I have to take in an array of unknown size, resize it, and output a bunch of statistics like average, Q1, Q3, etc. I am having trouble taking in the array from the user. I need to quit taking in variables once they enter 0. Here is what I have:
int i = 1; //When I first posted this I didn't mean to comment out the '= 1' part
do {
cin >> array[i];
if (array[i] != 0)
return true;
} while (true);
What am I doing wrong? the program stops after I enter 1 number every time no matter what number I enter.
I am using vector class btw.
Do the following:
// change int to your type
int val;
std::vector<int> vec;
while(std::cin >> val) {
if(val == 0) break;
vec.push_back(val);
}
Reason: Stating a return clause causes to exit the loop.
use of std::vector ensures the arbitrary size condition.
Update after #nonsensickle's constructive remark:
The following piece of code also ensures the only 0 terminates input process condition:
// change int to your type
int val;
std::vector<int> vec;
do {
if(std::cin >> val) {
if(val == 0) break;
vec.push_back(val);
} else { // fix broken input stream in case of bad input
std::cin.clear();
std::cin.ignore(1,'\n');
}
} while(true);
and a more sophisticated way, although overkill but what the hell :), with templates and type traits:
template <typename T>
struct zero_traits
{
static T getzero() { return T(0); }
};
template <>
struct zero_traits<std::string>
{
static std::string getzero() { return "0"; }
};
template <>
struct zero_traits<char>
{
static char getzero() { return '0'; }
};
template <typename T>
std::vector<T> read_values()
{
T val;
std::vector<T> vec;
do {
if(std::cin >> val) {
if(val == zero_traits<T>::getzero()) break;
vec.push_back(val);
} else {
std::cin.clear();
std::cin.ignore(1,'\n');
}
} while(true);
return vec;
}
int main()
{
// change int to your type
std::vector<int> vec = read_values<int>();
for(auto i : vec) std::cout << i << std::endl;
}
First of all i will never increment.
Second of all, if (array[i] != 0) will return if that array's value doesn't equal 0.
You need to read into how do { ... } while() loops work as well as what return statements do. Might as well throw in how to increment an array while you're at it.
I will not try to answer your question directly. What you have is a small logic error and a misunderstanding of the do {...} while () looping construct. What you need is to learn how to step through your code.
Let's go through your code line by line (there are only 6 lines here so it should be really easy):
int i; - Ok, so we are declaring an integer i here but are not giving it a value. As such, i can have a random value.
do { - This is where we will come back to when we evaluate the while clause. But only if the result of the while clause is true.
cin >> array[i] - Store a value that the user enters in the array at the position i. Here we ask ourselves a question, what is i? We should know its value without having to run the program. Hint: there's a problem here because of i
if (array[i] != 0) - If the number entered by the user is not zero return true (exit this function with the result true).
} while (true); - Go back to the do { line and redo all the steps until you get here. There is no condition here so it will keep happening until we exit this function.
Hint: The only exit point of your loop is at step 4.
With this, you should be able to figure out your problem. Trying to break down the problem for yourself should be your first step.
I recommend reading this blog post on debugging small programs. It should be informative.
Though code posted by others (in particular #DimitriosBouzas) will work, and is the better choice, I strongly recommend fixing your code and learning why it failed. This will help you in the long run more than #DimitriosBouzas' elegant solution.
Before answering your question.
Initialize your variables int i=0; .You assign i to be zero because arrays are zero indexed.
You have to incerement i. If do not increment it, i will point at the first "bucket" in your array the whole time. Use i++ or i = i + 1 after every iteration of the do while loop to move "forward" in your array.
You want your program to run until zero is entered so you have to write your condition like this if (array[i] == 0) return true;. This condition is true when the last number entered was zero and it will cause your method to return. It would be more elegant for you to check for it in the while clause.
Putting it all together, your code should look like this
int i=0;
do {
cin >> array[i];
if (array[i] != 0) break;
i++;
} while (i < maxSize);
//do stuff with filled array

Multiple return value method fails with goto statements

The following code:
#include <cstdlib>
#include <iostream>
using namespace std;
int function(void)
{
static int i,state=0;
switch(state)
{
case 0: goto labeL0;
case 1 :goto labeL1;
}
labeL0:
for (i = 0; i < 10; i++)
{
state=1;
return i;
labeL1:;
}
}
int main(int argc, char *argv[])
{
cout << function() << endl;
system("PAUSE");
return EXIT_SUCCESS;
}
fails. I mean it returns only 0 instead of 0,1,2,...
I wanted just use label and goto statements to implement such functions. It is for practice (let's say homework), but I can't get it to work. Is this even possible?
How can I use goto and label statements so that this function prints 0 1 2... so on?
It's not clear to me exactly what you're trying to do. If your goal is
jsut to use goto, the simplest solution is to implement the algorithm
exactly as you'ld normally do, replacing looping constructs wit goto;
i.e. instead of:
for ( int i = 0; i < 10; ++ i ) {
std::cout << i << std::endl
}
you could write:
int i = 0;
goto label1:
label2:
std::cout << i << std::endl;
++ i;
label1:
if ( i < 10 ) goto label2;
Back in the old days, with Fortran IV, this is what we actually did.
There's absolutely no reason to do it today (except maybe obfuscation).
I wonder, however, given the static variables, if you're not trying to
implement some sort of co-routine; that each time you call the function,
you output one higher than the previous time. In this case, I'd
recommend maintaining the state in a class, rather than using static
variables. In addition the function will need some sort of return value
so that the caller will know when it's finished, and the caller will
have to loop. Something like the following should do the trick:
class CoRoutine
{
int i;
public:
CoRoutine() : i( 0 ) {}
bool function()
{
if ( i < 10 ) {
std::cout << i <<std::endl;
++ i;
}
return i < 10;
}
};
int
main()
{
CoRoutine c;
while ( c.function() ) {
}
return 0;
}
(There's still no need for goto, of course.)
This won't work since after the return statement, the compiler leaves the function ignoring all statements after it.
Also, using labels is ugly, horrible and unmaintainable. Why are you using them? Do you want the maintenance guy arriving at your house with a chain-saw?
After executing the return statement the execution returns from function().....
So initially when i=0, "return i" returns 0 and it is displayed on screen
You should use recursive call to function to get it executed and more over your use of GOTO is a typical example of why we should avoid using goto.
void function(void)
{
static int i=0;
for(;i<10;)
{
cout<<i;
i++;
function();
}
}
void main()
{
function();
}
but if you still want to use goto statements then use this
void function(void)
{
static int i =0;
lablelA:
cout<<i;
i++;
if(i == 10)
return;
goto lablelA;
}
Jumping to labeL1 is jumping in a loop with uninitialized variable i. How could this go right? This is only 1 of the reasons to avoid goto.
EDIT: actually, it should probably work as some sort of poor man's generator (because of the static local variables), but still the case of i >= 10 should be handled. Now it is returning nothing. So your main concern in the code is that you need a loop in main to call function maximum 10 times.
Still, this is not a construct I would want to see in real code.
The code reminds me of Coroutines in C.
To print 0, 1, etc you should call the function several times. That's the whole point.

Indexing my while loop with count parameter in an array

My function takes an array of ifstream ofjects and the number of ifstream objects as seen below:
void MergeAndDisplay(ifstream files[], size_t count)
My problem is I want to use a while loop to read from the file(s) as long as one of them is open. When I get to eof, I close the file. So I thought I could do something like
int fileNum = 0;
while(files[fileNum].is_open() || something here) {
//do stuff
}
But I am not really sure how to put the correct amount of parameters in my while loop...
You will have to compute the logic of "is any file in this set open" separately. I suggest making it its own function so that the while loop can be clean and natural, e.g.
bool isAnyOpen(ifstream files[], size_t count) {
for (size_t i = 0; i < count; ++i) {
if (files[i].is_open()) return true;
}
return false;
}
Then you can write
while(isAnyOpen(files, count)) {
// Your code here
}
Edit: This is a more general case solution than what R Samuel Klatchko posted. If your problem is as simple as wanting to just read all the data out of all the files, then use his method since it is more direct.
You probably want
while (fileNum < count && files[fileNum].is_open())
with the condition that you increment fileNum whenever you open a new file in your loop.
Try something like this:
void ProcessStream(std::istream& input_file)
{
//...
}
// Your loop
bool a_file_is_open = true;
do
{
a_file_is_open = false;
for (unsigned int i = 0; i < MAX_FILES; ++i)
{
if (files[i].is_open())
{
a_file_is_open = true;
ProcessStream(files[i]);
break;
}
}
} while (a_file_is_open);