Why is this crashing?
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main(){
string word;
vector<string> text;
while (cin >> word){
if(word == "break"){ cout << "breaking loop" << endl; break;}
else {text.push_back(word);}
}
for(vector<string>::size_type ix = 0; ix <= text.size(); ++ix){
cout << text[ix] << endl;}
char a;
cin >> a;
return 0;
}
Ok thats the full code. Im doing some practice and experiments with vectors because I have come farther in my book. It crashes after the for loop.
To me it doesn't make sense why it would crash...
I use the Bloodshed dev-c++ compiler.
Quote:Original post by Noobis
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main(){
string word;
vector<string> text;
while (cin >> word){
if(word == "break"){ cout << "breaking loop" << endl; break;}
else {text.push_back(word);}
}
for(vector<string>::size_type ix = 0; ix <= text.size(); ++ix){
cout << text[ix] << endl;}
char a;
cin >> a;
return 0;
}
Ok thats the full code. Im doing some practice and experiments with vectors because I have come farther in my book. It crashes after the for loop.
To me it doesn't make sense why it would crash...
I use the Bloodshed dev-c++ compiler.
shouldn't it be:
for(vector<string>::size_type ix = 0; ix < text.size(); ++ix){
cout << text[ix] << endl;}
with say 5 strings in the vector the last string would be stored in text[4] thus you want < text.size() instead of <= text.size()
unless im missing something... (its late (or early) so i probably shouldn't be posting
No I start at 0 so it should only go to 4 even if it has 5 strings right?
If it only went to < size then it wouldn't get the last string right?
I did it with a string and it only goes to the last character so why doesn't it work with a vector?
It might just be my computer but I don't know I get a "Just-in-Time debugger" error if I run it. Or if I run it through the debugger stopping just after char a; I get a Access violation (segmentation fault) raised.
Edit: well it worked.. I just don't understand why... does it have something to do with break maybe?
If it only went to < size then it wouldn't get the last string right?
I did it with a string and it only goes to the last character so why doesn't it work with a vector?
It might just be my computer but I don't know I get a "Just-in-Time debugger" error if I run it. Or if I run it through the debugger stopping just after char a; I get a Access violation (segmentation fault) raised.
Edit: well it worked.. I just don't understand why... does it have something to do with break maybe?
Quote:Original post by Noobis
No I start at 0 so it should only go to 4 even if it has 5 strings right?
If it only went to < size then it wouldn't get the last string right?
I did it with a string and it only goes to the last character so why doesn't it work with a vector?
It might just be my computer but I don't know I get a "Just-in-Time debugger" error if I run it. Or if I run it through the debugger stopping just after char a; I get a Access violation (segmentation fault) raised.
Edit: well it worked.. I just don't understand why... does it have something to do with break maybe?
your loop ran like this:
ix=0;
start:
if (ix<=5) goto end;
cout <<text[ix]<<endl;
++i;
goto start;
end:
thus it will run cout << text[5] at the end.
strings contain one character more than their length (the last character in a C string is always 0)
Quote:Original post by Noobis
No I start at 0 so it should only go to 4 even if it has 5 strings right?
If it only went to < size then it wouldn't get the last string right?
if 'text' contains 5 strings text.size() will be 5, and 0-4 are valid indecies.
with a for loop like: "ix = 0; ix <= text.size(); ++ix" then ix will count 0-5 (thats 6 numbers).
with a for loop like: "ix = 0; ix < text.size(); ++ix" then ix will count 0-4 correctly.
Well its a vector not a string? Do vectors contain an extra space?
I know that a string would be "S,T,R,I,N,G,/0" but don't vector only go, "Object, Object, Object" with no null positions?
Because I can use:
for(string::size_type ix=0; ix <= s.size(); ix++){
cout << s[ix] << endl;}
but not the same loop for vectors without a crash? Thats why I am not sure what is going on. In the book it says nothing about vectors containing a null position and I never even heard of a vector having a null position.
OHHHH holy crap.. I get why it should only be < size
There isn't a null position.
x=0
size =5
it will loop 0,1,2,3,4,5
while x <= 5
Vector size is 5 but lists only to 4... ok. Thank you for the help now I understand. 0,1,2,3,4 = 5 total positions
Edit: Yah, it didn't click at first I had to write it out, Thank you guys.
I know that a string would be "S,T,R,I,N,G,/0" but don't vector only go, "Object, Object, Object" with no null positions?
Because I can use:
for(string::size_type ix=0; ix <= s.size(); ix++){
cout << s[ix] << endl;}
but not the same loop for vectors without a crash? Thats why I am not sure what is going on. In the book it says nothing about vectors containing a null position and I never even heard of a vector having a null position.
OHHHH holy crap.. I get why it should only be < size
There isn't a null position.
x=0
size =5
it will loop 0,1,2,3,4,5
while x <= 5
Vector size is 5 but lists only to 4... ok. Thank you for the help now I understand. 0,1,2,3,4 = 5 total positions
Edit: Yah, it didn't click at first I had to write it out, Thank you guys.
you could use an iterator to traverse a vector. This built and ran fine.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main(){
string word;
vector<string> text;
while (cin >> word){
if(word == "break"){ cout << "breaking loop" << endl; break;}
else {text.push_back(word);}
}
for(vector<string>::iterator ix = text.begin(); ix != text.end(); ++ix){
cout << (*ix) << endl;
}
char a;
cin >> a;
return 0;
}
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main(){
string word;
vector<string> text;
while (cin >> word){
if(word == "break"){ cout << "breaking loop" << endl; break;}
else {text.push_back(word);}
}
for(vector<string>::iterator ix = text.begin(); ix != text.end(); ++ix){
cout << (*ix) << endl;
}
char a;
cin >> a;
return 0;
}
I just got to that part in my book.
Introducing Iterators
lol.
I will have to take a look at that code after i read this. Thanks
This is off topic but: Anyone know where I can get source to a fully built tetris clone using c++ and opengl?
Introducing Iterators
lol.
I will have to take a look at that code after i read this. Thanks
This is off topic but: Anyone know where I can get source to a fully built tetris clone using c++ and opengl?
ALWAYS use != when comparing with the end() iterator in a for loop!
Do not use < or <= (lesson learn't I'm sure)
Even better, use std::for_each[grin]
Also, use a const_iterator if you don't modify the elements.[cool]
Do not use < or <= (lesson learn't I'm sure)
Even better, use std::for_each[grin]
Also, use a const_iterator if you don't modify the elements.[cool]
A few assorted notes.
Writing for loops "manually" is kind of unintuitive in C and C++. This is one of the reasons these languages aren't really suited for beginners. These loops are low level constructs, thin wrappers around what you'd have to do with while-loops to get the same effect. The construct is much more powerful than is normally "useful" (because you could do anything instead of just incrementing, and you don't have to use the same variable in each "clause", and you could work with more than one counter variable, and...), and because of that, it becomes easy to make mistakes.
To get around that, we can use standard library algorithms, such as the std::for_each that iMalc mentioned. Unfortunately, the C++ language design makes this a little tricky to use, because you have to wrap up the loop body into some kind of function (or function object) - but the idea is that the algorithm accepts the range of elements and "something to do to" an element, and does the something-to-do to each element in the range. This also makes sure that the .end() (or .size(), for the version of a loop using indices) function is evaluated only once for the loop.
It would look something like:
But in our particular situation, we can use a more specific tool ;)
The std::ostream_iterator is a tool that lets use treat an output stream as if it were a container: it is an object that behaves like an iterator, but writes "elements" to an ostream. (Because the ostream is a stream and not a container, the ostream_iterator is a very restricted form of iterator: it can only be advanced forwards, and has no random access.) The std::copy algorithm copies stuff from one range to another (the destination range is implied: you specify just the beginning point, and the endpoint is assumed to be whereever it needs to be in order to hold everything from the source range).
These tools are very powerful. We avoid having to mess around with loop counters, and we also don't have to worry about figuring out the types of a bunch of temporary variables. (You'll notice there are no variable declarations in the above use of std::copy; that means I don't have to worry about what type 'text.begin()' returns, for example.)
Also as iMalc said, you should use != rather than < for testing iterators. The reason is that while it works for a vector's iterators (and for pointers, which are "iterators" for an array), it doesn't necessarily work for all kinds of iterators - the concept of an "iterator" doesn't require that they are "ordered" (i.e. that you can consistently say that one is less than another, and that this property is transitive), only that they are "comparable" (i.e. that you can consistenly say whether two iterators are equal, i.e. referring to the same element). Requesting a const_iterator is useful too, so that if you don't intend to change elements, you can tell the compiler "I don't intend to change elements", and then it will warn you if the code might actually do so (const correctness). Note that a "const iterator" is an iterator which cannot change (i.e. be set to refer to a different element), which is different from a "const_iterator", which is an iterator to a const element (i.e. you promise not to change the element accessed via that iterator).
Of course, the original code doesn't use the container's iterators at all, but just plain old indices. This is restrictive in a similar fashion. For example, if we later wanted to change the container to be a std::list, the code would break, because there is no operator[] for a std::list - it's not a random access container, so treating it that way doesn't make sense. With iterators, however (as in MrRage's code), it would work. (And with std::copy or std::for_each it will certainly work, because those will be implemented in terms of iterators behind the scenes.)
Writing for loops "manually" is kind of unintuitive in C and C++. This is one of the reasons these languages aren't really suited for beginners. These loops are low level constructs, thin wrappers around what you'd have to do with while-loops to get the same effect. The construct is much more powerful than is normally "useful" (because you could do anything instead of just incrementing, and you don't have to use the same variable in each "clause", and you could work with more than one counter variable, and...), and because of that, it becomes easy to make mistakes.
To get around that, we can use standard library algorithms, such as the std::for_each that iMalc mentioned. Unfortunately, the C++ language design makes this a little tricky to use, because you have to wrap up the loop body into some kind of function (or function object) - but the idea is that the algorithm accepts the range of elements and "something to do to" an element, and does the something-to-do to each element in the range. This also makes sure that the .end() (or .size(), for the version of a loop using indices) function is evaluated only once for the loop.
It would look something like:
#include <algorithm>void output(const std::string& s) { cout << s << endl;}// ...std::for_each(text.begin(), text.end(), output);
But in our particular situation, we can use a more specific tool ;)
#include <algorithm>#include <iterator>// ...std::copy(text.begin(), text.end(), std::ostream_iterator<std::string>(cout, "\n");
The std::ostream_iterator is a tool that lets use treat an output stream as if it were a container: it is an object that behaves like an iterator, but writes "elements" to an ostream. (Because the ostream is a stream and not a container, the ostream_iterator is a very restricted form of iterator: it can only be advanced forwards, and has no random access.) The std::copy algorithm copies stuff from one range to another (the destination range is implied: you specify just the beginning point, and the endpoint is assumed to be whereever it needs to be in order to hold everything from the source range).
These tools are very powerful. We avoid having to mess around with loop counters, and we also don't have to worry about figuring out the types of a bunch of temporary variables. (You'll notice there are no variable declarations in the above use of std::copy; that means I don't have to worry about what type 'text.begin()' returns, for example.)
Also as iMalc said, you should use != rather than < for testing iterators. The reason is that while it works for a vector's iterators (and for pointers, which are "iterators" for an array), it doesn't necessarily work for all kinds of iterators - the concept of an "iterator" doesn't require that they are "ordered" (i.e. that you can consistently say that one is less than another, and that this property is transitive), only that they are "comparable" (i.e. that you can consistenly say whether two iterators are equal, i.e. referring to the same element). Requesting a const_iterator is useful too, so that if you don't intend to change elements, you can tell the compiler "I don't intend to change elements", and then it will warn you if the code might actually do so (const correctness). Note that a "const iterator" is an iterator which cannot change (i.e. be set to refer to a different element), which is different from a "const_iterator", which is an iterator to a const element (i.e. you promise not to change the element accessed via that iterator).
Of course, the original code doesn't use the container's iterators at all, but just plain old indices. This is restrictive in a similar fashion. For example, if we later wanted to change the container to be a std::list, the code would break, because there is no operator[] for a std::list - it's not a random access container, so treating it that way doesn't make sense. With iterators, however (as in MrRage's code), it would work. (And with std::copy or std::for_each it will certainly work, because those will be implemented in terms of iterators behind the scenes.)
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement