• Advertisement
Sign in to follow this  

Why is this crashing?

This topic is 3955 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

#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.

Share this post


Link to post
Share on other sites
Advertisement
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

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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)

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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;
}

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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:


#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.)

Share this post


Link to post
Share on other sites
man, so much production over a simple learning C++ mistake.

All index based operations in C++ are 0 based, and run from 0 to size - 1.

So your for loop was going 1 too many (as mentioned above).

In C++ the norm for all index comparisons is i < size(), which is the same as i <= last index (since size will always be 1 bigger than last index). The norm for most other standard comparisons in loops is != (as in != end()).

Simple mistake, we've all done it, and people will do it again tommorow.

Share this post


Link to post
Share on other sites
Quote:
Original post by Xai
man, so much production over a simple learning C++ mistake.

...

we've all done it, and people will do it again tommorow.


That's exactly why there's "so much production over" it. Why waste time fixing uses of an error-prone construct, when you could replace the construct? :)

Share this post


Link to post
Share on other sites
Quote:
Original post by Noobis
I know that a string would be "S,T,R,I,N,G,/0"


That isn't necessarily true. Indeed, character array literals are null-terminated strings, but the std::basic_string class is not required to have a sentinel (it keeps a count of characters, which among other things, makes getting the string size O(1) instead of O(n)).

Share this post


Link to post
Share on other sites
Quote:
Original post by jflanglois
Quote:
Original post by Noobis
I know that a string would be "S,T,R,I,N,G,/0"


That isn't necessarily true. Indeed, character array literals are null-terminated strings, but the std::basic_string class is not required to have a sentinel (it keeps a count of characters, which among other things, makes getting the string size O(1) instead of O(n)).


This is true
Pascal strings use the first byte to indicate the length and C++ strings use an attribute of the object. However C++ strings are easily converted to C strings (using myString.c_str();)

in the case of the OP:s ability to read out of bounds on a C++ string it could be that the [] operator does boundschecking .

Edit:
i just tested a simple std:string myString = "1234"; for(int i=0;i<8;i++) cout << myString[i]; with g++ and it works without any problems, (it doesn't print any junk data)

Share this post


Link to post
Share on other sites
Wow... I can't say that I understood most or any of that...

Umm.. yah... I know now to use != because thats what the book said but I just didn't read that far. I was just doing some self experimenting... Also.. I tried doing one of the exercises in the book. I just want to know if I did this right.

The only headers I was allowed to use were:

<iostream> ; <cctype> ; <string> ; <vector>

because thats all I learned about so far...

also only able to use for, while, if loops

and basically all that I have learned so far from this book : C++ Primer 4ed


Here was the problem:

Exercise 3.13: Read a set of integers into a vector. Calculate and print the sum of each pair of adjecent elements in the vector. If there is an odd number, tell the user and print the value of the last element without summing it. Now change your program so that it prints the sum of the first and last elements, followed by the sum of the second and second-to-last and so on.


Well my program worked... But I don't know if I did it the best way. Does it matter though as long as it works? There are no errors right?

My code:

#include <iostream>
#include <string>
#include <vector>
#include <cctype>

using namespace std;

int main(){
/*
string word;
vector<string> text;

//Asks for a set of strings until 'break'
cout << "Type some words, type to end" << endl;
while (cin >> word){
if(word == "break"){ cout << "breaking loop" << endl; break;}
else {text.push_back(word);}
}

//Prints string elements in vector
for(vector<string>::size_type ix = 0; ix != text.size(); ++ix){
cout << text[ix] << endl;}

*/

//Asks for a set of numbers until '0'
int num;
vector<int> numvec;
cout << "Type some numbers" << endl;
while(cin >> num){
if(num == 0){ cout << "breaking loop" << endl; break;}
else {numvec.push_back(num);}
}

//Sums and Prints adjactent vector Elements
cout << "sum of adjacent" << endl;
for(vector<int>::size_type ixx = 0; ixx != (numvec.size()); ++ixx){
if(ixx == numvec.size()-1){
if(numvec.size() %2){cout << "This number is odd: "
<< numvec[numvec.size()-1]
<< endl;}
}
else {cout << numvec[ixx] + numvec[ixx+1] <<endl;}
}

//Sums and Prints first and last values of vector elements
cout << "first and last sum:" << endl;
for(vector<int>::size_type ixx = 0; ixx != (numvec.size()/2); ++ixx){
cout << numvec[ixx] + numvec[(-1 - ixx) + numvec.size()] <<endl;
if(numvec.size() %2 && (ixx == (numvec.size()/2 -1)))
{cout << "This number is odd: "
<< numvec[numvec.size() %2 + 1] << endl;}
}



//Pauses and waits for character before exiting
char a;
cin >> a;
return 0;
}


Share this post


Link to post
Share on other sites
"Well my program worked... But I don't know if I did it the best way. Does it matter though as long as it works? There are no errors right?"
That's why programming is considered an Art by some since there are so many different ways to write your programs.
You should be safe with the book you have since it's one of the only C++ books that shows you the new and correct way to write C++ programs.
If you pick up any old/outdated/or bad C++ books you'll know what I mean.
It doesn't matter at this point as long as your compiler didn't give you any errors or warnings since you are just starting out.
The only thing to really watch out for is "logic" errors which your compiler can't /won't catch.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement