Absence of loop is rendering code useless? - c++

First of all, this is NOT homework. I'm using a book I bought for myself to learn the beginning of C++ at home, and it contains an exercise I'm stuck with. It asks me what is wrong with the following code, but I can't seem to find it. First I thought that it had to do with the fact that there wasn't a while or for loop and thus it couldn't repeat itself rendering the 'i' useless, but I'm not sure if that's the true issue here.
for (int i = 0; i <= phrase.size(); ++i)
{
cout << "Character at position " << i << " is: " << phrase[i] << endl;
}

The condition is wrong: i <= phrase.size() should be i < phrase.size(). Say phrase is a vector of 10 elements. size() will return 10, but in last iteration of the loop, phrase[10] is accessing an element which isn't there. Dereferencing out of bounds is undefined behaviour, which by C++ standard makes the whole program ill-formed.

i < phrase.size() // Given that you are starting from 0th index, I assume
// that the valid array indexes are 0 to N-1

I suspect it is the <= size() that is the problem, on the last loop the phrase[i] will actually be one past the end of the array causing a bad reference, so should be:
for (int i = 0; i < phrase.size(); ++i)
{
cout << "Character at position " << i << " is: " << phrase[i] << endl;
}

The problem is on this line:
for (int i = 0; i <= phrase.size(); ++i)
The value of i will get at one point equal to phrase.size(), which, when indexed later by phrase[i] is out of bounds, as indixing in C++ is zero-based.

It's mostly a good guideline to always include the start bound and exclude the last.
So write:
for (int i = 0; i < phrase.size(); i++)
That way i starts with 0 and ends with the last item.

<= phrase.size() should be < phrase.size(). The last iteration of the loop will have an i equal to phraze.size() which is out of bounds since whatever you're iterating starts with an index of 0.

Imagine you have 10 items, but counting numbers for them will be look like 0, 1 .., 8, 9. So you should check it by "strictly less" operator. This fact is confusing first time, but then you will see how is it comfortable.

Related

Program not running with Array during Initialization

I'm just practicing using arrays. So my program consist of inputting numbers of data type double into the array and have them print out. Simple.
I only limited the numbers down to 4. So the array, num_List[3] is in the code. I've made sure to use the for loops properly for reading and printing out the result.
The first few times I tested the code. I realized that the 4th number in the array was in scientific notation, telling me that I forgot to initialize the array to 0, in this case 0.0, since I'm using double. So I put in this code.
for (index = 0; index <= 3; index++)
num_List[index] = 0.0;
This code should have initialized the arrays of num_List to 0.0. However, when I tested this, nothing came up, after I inputted the 4 numbers. So I made a logical error here or it's something else with the for loop that's causing it to be trapped and not continue the execution.
I've read in the books about this particular way to initialize.
#include <iostream>
using namespace std;
int main() {
double num_List[3]; // These are my variables
int index;
//double num; // Ignore these two for now, for they are to be modified later on.
//double result;
cout << "This program will summarize the numbers you've inputted print out the result. \n";
cout << "And also print out the address of the 1st and 4th address in the array." << endl;
cout << "Please enter the four numbers to be summarized.";
for (index = 0; index <= 3; index++) { // I put this in after I realized my mistake of not initializing my arrays to 0.0.
num_List[index] = 0.0;} // This is where the problem is, I think.
for (index = 0; index <= 3; index++) // This reads in the user the input
cin >> num_List[index];
cout << "The numbers you have inputted is:\n";
for (index = 0; index <= 3; index++) // This prints out the array.
cout << num_List[index] << ", " << endl;
return 0;
}
If you focus on the aforementioned code, and try to compile it, you'll see that my code unfortunately doesn't continue on from there after you input 4 numbers, regardless of whether or type a number and space it up to 4 numbers, or input a number, press the enter key for those numbers. Most likely I've made a obvious mistake, but I'm having some trouble seeing it.
I use Code Blocks, so things are a little different compared to the Bloodshed C++ compiler I used to use to practice codes on.
double num_List[3];
This declares an array with 3 elements, indexed 0 through 2.
for (index = 0; index <= 3; index++)
This loops through 4 indices, 0 through 3. When you do something with num_List[3], you get undefined behavior. In your trial, the undefined behavior fortunately resulted in just some garbage output.

Issue when looping through a vector<string>, and keeping "count" of each element

first of all this is my first question on the site. I've done a lot of research and I don't think I found quite a specific issue as this, but if I'm wrong, feel free to correct me in an answer and link said topic to me.
Onto the problem itself, the assignment consists of a console application that will display each distinct word entered to it, as well as the number of occurrences for each unique word. I decided that the way to solve this would be through the use of a vector<string> and then use a nested loop structure where the outer loop would represent each unique word, and where the inner loop would be used to compare the word from the outer loop to each existing word in the vector.
However. I've ran across a problem.
With this basic setup:
//Sort vector into alphabetical order
sort(words.begin(), words.end()); //this only sorts them alphabetically, but equal strings are "next" to each other
//Find unique values
for(string::size_type i=0; i != words.size(); i++) {
int count = 0;
for(string::size_type j=0; j != words.size(); j++) {
if(words[i] == words[j]){
count++;
}
}
cout << words[i] << " appeared: " << count << " times." << endl;
}
Everything works fine as far as functionality is concerned; 2+ instances of a word are correctly spotted but they are displayed 2+ times as their own rows, because the instance repeats itself whenever that duplicate element is encountered on the outer loop.
Here's a picture:
Basic Result Promblem, Duplicate Output
I thought I'd solve it with the following code:
//Sort vector into alphabetical order
sort(words.begin(), words.end()); //this only sorts them alphabetically, but equal strings are "next" to each other
//Find unique values
for(string::size_type i=0; i != words.size(); i++) {
int count = 0;
for(string::size_type j=0; j != words.size(); j++) {
if(words[i] == words[j]){
count++;
if(i != j){ //replacement: delete duplicate values from the vector (aka if the indexes don't match)
words.erase(words.begin() + j); //delete element at index "j"
}
}
}
cout << words[i] << " appeared: " << count << " times." << endl;
}
A new problem arises with this: the word that appears 2+ times now throws an error. The index itself would work fine, i.e if I were to add cout << words[i] << endl; right after deleting the element it displays the correct word. However, the word that appears 2+ times does not show up at all, and returns an error.
Here's a picture: Updated problem, now duplicate values throw an error
Anyone would be nice enough to explain why this happens, and how to fix it?
Let's look at where your example case fails:
for(string::size_type j=0; j != words.size(); j++) { // i: 1, j: 2, size(words): 3
if(words[i] == words[j]){ // words[i] matches words[j]
count++;
if(i != j){ // i doesn't match j
words.erase(words.begin() + j); // i: 1, j: 2, size(words): 2
}
}
} // Upon rexecuting the iteration expression i: 1, j: 3, size(words): 2 thus `j` will be greater than `size(words)` and will be used to continue the loop even though it is an invalid index
There have been several solutions presented to solve this problem using your current code. But I would suggest that the simplest method for solving this would be the multiset:
const multiset<string> words{istream_iterator<string>(cin), istream_iterator<string>()};
auto it = cbegin(words);
while(it != cend(words)) {
auto i = words.upper_bound(*it);
cout << *it << " appeared: " << distance(it, i) << " times\n";
it = i;
}
You can see a live example of this here: http://ideone.com/Nhicos Note that this code does away with the need for an input sequence termination word, "-end" in your case, and instead depends upon EOF. which is automatically appended to the http://ideone.com input: Read cin till EOF
Your code is correct, you just need to check for < on the loops instead of !=.
Because reducing the size of the vector within the loop can cause an invalid index, which is beyond the size of the vector to occur, but the loop may still progress with != while < will always consider only valid indices.
Change only != to < in the loops and it works.
Here is the Output.
Edit:
You also need to reset j to check for next element at the same position from where you erase an element, because now the next element is in that position instead of j + 1.
Just add j--; after erasing the element and it works.
Here is the new Output.
Corrected code:
//Sort vector into alphabetical order
sort(words.begin(), words.end()); //this only sorts them alphabetically, but equal strings are "next" to each other
//Find unique values
for(string::size_type i=0; i < words.size(); i++) {
int count = 0;
for(string::size_type j=0; j < words.size(); j++) {
if(words[i] == words[j]){
count++;
if(i != j){ //replacement: delete duplicate values from the vector (aka if the indexes don't match)
words.erase(words.begin() + j); //delete element at index "j"
j--; // Re-run iteration for j
}
}
}
cout << words[i] << " appeared: " << count << " times." << endl;
}
i think you shoud check if i!=j;if i==j it compare to itself.
//Find unique values
for(string::size_type i=0; i != words.size(); i++) {
int count = 0;
for(string::size_type j=0; j != words.size(); j++) {
if(words[i] == words[j]&&i!=j){
count++;
}
}
cout << words[i] << " appeared: " << count << " times." << endl;
}
This problem can be easily solved using a data structure called a hash table. The hash table is an associative array which holds a key-value pair. Basically the "key", which can be a word, is used to calculate the index of the array where the "value" is held, which in your instance can be the number of times it's been counted. C++ has the
std::unordered_map
which is a hash table. Take a look here for the theory behind hash tables: https://en.wikipedia.org/wiki/Hash_table
and look here for the C++ version:
http://www.cplusplus.com/reference/unordered_map/unordered_map/
This should make your program much easier to write. You can just add words to your hash table when they are entered with a value of 1. When you see the word again, increment it's associated value.
Update:
The simple change of operator != to < in the loop condition was not enough. Yes, two cases worked fine, but if there were 3+ instances of a specific word, then the output would be split into several lines. The explanation I can offer with my so far limited knowledge is that the inner loop was checking for the condition "is the index from the outer loop equal to the index from the inner loop", which should in theory work right. However, since in 2+ instance cases at least 1 element from the array is removed, the condition would be evaluated separately, instead of all together.
After some reasoning, I was able to come up with this for a final solution:
//Sort vector into alphabetical order
sort(words.begin(), words.end()); //this only sorts them alphabetically, but equal strings are "next" to each other
//Find unique values
for(string::size_type i=0; i < words.size(); i++) {
int count = 0;
//duplicate vector, and use it for the inner loop
vector<string> duplicate = words;
for(string::size_type j=0; j < duplicate.size(); j++) {
if(words[i] == words[j]){
count++;
if(i != j){ //replacement: delete duplicate values from the vector (aka if the indexes don't match)
words.erase(words.begin() + j); //delete element at index "j"
}
}
}
cout << words[i] << " appeared: " << count << " times." << endl;
}
This does in fact work with any sort of instance cases, be it 2, 3, 5, etc.
I wanted to solve the problem this way (with vectors themselves) because the textbook "Accelerated C++" had only covered vectors and strings up to that point.
Please keep the following points in mind:
Being a novice programmer, further optimization will most likely be a choice
If you are interested in what looks like the most accurate/simple/efficient answer so far, please take a look at #Jonathan Mee's answer, it should still be voted as the correct answer.
Thanks for the help to all who posted here!

How would I know if the counter increments are at the correct place to keep track the # of comparisons ~ C++?

// Question solved. I am confused on where to add the counters at to report the number of
comparisons. It always stay at a fixed number and never changes. Assume the vector contain two-digit random numbers every time the program runs. //
Edit: New question. I'm not sure if the counter increments are at the correct place or not for insertion sort and selection sort.
Code pasted at a safe link: http://ideone.com/Bk90du
int insertionSort(vector<int> &v)
{
// Variables
int temp, i, j, counter;
counter = 0;
for (i = 1; i < v.size(); i++)
{
temp = v[i];
j = i-1;
while(temp < v[j] && j >= 0)
{
v[j+1]=v[j];
j--;
counter++; // tracking # of comparisons.
}
v[j+1]=temp;
}
return counter; // return counter
}
According to the (now deleted) comment, this is main():
int main() {
int numCount;
vector<int> myVector2(myVector);
insertionSort(myVector2);
cout << endl << endl;
cout << "Vector after Insertion Sort: ";
printVector(myVector2);
cout << endl << endl;
numCount = insertionSort(myVector2);
cout << "Number of comparisons: " << numCount;
You sort the same vector two times, and print the comparision count of the second sort run. When the vector is already sorted, the number of comparisons is equal to the number of elements in the vector, because no work has to be done.
To get the true number of comparisons, change your main() to:
int main() {
int numCount;
vector<int> myVector2(myVector);
numCount = insertionSort(myVector2);
cout << endl << endl;
cout << "Vector after Insertion Sort: ";
printVector(myVector2);
cout << endl << endl;
cout << "Number of comparisons: " << numCount;
Without knowing what your test cases are, it's not possible to comment on number of comparisons they perform. If all cases have similar attributes, it is quite possible the code is behaving as it should.
EDIT: the following added in response to claim by OP in comments that the test cases are vectors with 100 randomly generated two-digit elements.
If, as you have said in comments, your test cases involve vectors with 100 random two-digit values, then the value of counter will depend on how "unsorted" the elements are (with the minimum value possible related to the number of elements). Assuming all of your test cases are the same size, then the only way the value of counter will be the same is if the vectors are sorted similarly BEFORE calling your function. For example, if all your vectors are pre-sorted in ascending order and the same size, every test case will give the exact same return value. Similarly, if all your vectors are pre-sorted in descending order and the same size, every test case will give the exact same return value (albeit different from the value returned if they are initially in ascending order).
For that reason, I do not believe your comment that the test cases are random. They are probably presorted (or maybe partially sorted) in some way. For example, you might be calling your function twice for each test case, and only printing out the value of count after the second call ..... when the vector is (if your code behaves as it should) already pre-sorted.
End Edit
That said, the variable counter in your code is accumulating the number of times the body of the while loop is executed. That has nothing to do with number of comparisons being performed, as there is no comparison performed in the body of that loop. It is related to the number of insertions, not the number of comparisons.
If, by "comparison", you want mean evaluating the expression temp < v[j] (as distinct from other expressions, like i < v.size() or j >= 0, which could also be called comparisons in your code) then you might consider doing something like
while (++counter && temp < v[j] && j >= 0)
and removing incrementing of counter from the loop body.
Since counter is initialised to zero, this will count the number of times temp < v[j] is evaluated (++counter will always produce a non-zero result). Note that, since temp < v[j] can be false, it will not count the number of times j >= 0 is computed.

Homework: Array's for C++

Write a program to input a series of 12 integers from the keyboard and store them in a one-dimensional array, x[12], then displayed them on the computer screen in reverse order.
I have a basic understanding that:
My numbers in the array will go from {0 to 11}
I am using a for loop (which I don't currently know how to do)
Now... How do I write this program?
You would do this:
loop from 0 to 11 using a for loop (for(size_t i = 0; i < 12; i++))
for each i, std::cin into the item at index i std::cin >> array[i];
To print them out you can use a while loop with i--. It will stop when i is zero and it will be backwards.
Because this is a homework question, I won't give you the full code but I hope this answer helps.
Learn about loops: while for do, while etcetera and you just might find the solution that you have been looking for
Example:
for(i = 0; i < 10; i++){
cout << i;
}
Since you know the quantity of numbers, you could insert them into the array in reverse order:
cin >> x[11]; cin >> x[10]; cin >> x[09]; //...
Next you would display the array in normal order:
cout << x[0]; cout << x[1]; cin << x[02]; //...
Since I didn't use a for loop, that's not going to help, is it?
The key concept is the 3rd parameter of the for loop, which can control the direction of a loop.
Let us investigate some examples:
for (unsigned int i = 0; i < 10; i += 2) {cout << i << endl; }
The above loop skips items because the variable is incremented by 2. That is 2 is added to index variable. This shows that loops don't always have to use ++.
So, what would happen if the index were set to the end value and then subtracted each time?
for (int i = 10; i >= 0; i -= 2) {cout << i << endl;}
This is for you to figure out.
Now, you will need to either ask questions in class, ask the professor after class or get a book that you will read and can understand easily (in addition to the one you have).

c++ vector not updating in nested for loop

So I create and initialize a vector (of size nmask+3) to 0, and I assign an initial value to one of the elements. I then make a for loop that goes through the first nmask elements of the vector and assigns to each element an average of 26 other elements in the vector (defined by the 4D int array voxt, which contains vector addresses).
My problem is that when I check the values of nonzero elements in my vector (phi) within the nested loop (the first cout), the values are fine and what I expect. However, when the loop finishes going through all nmask elements (for (int i= 0; i<nmask; i++) exits), I check the nonzero elements of phi again, and they are all lost (reset to 0) except for the last non-zero element (and element tvox which is manually set to 1).
I feel that since phi is initialized outside of all the loops, there should be no resetting of values going on, and that any updated elements within the nested loop should remain updated upon exit of the loop. Any ideas as to what is going on / how to fix this? Code is below; I tried to comment in a sense of the outputs I'm getting. Thanks in advance.
vector<double> phi(nmask+3, 0); //vector with nmask+3 elements all set to 0 (nmask = 13622)
phi[tvox]= 1; //tvox is predefined address (7666)
for (int n= 0; n<1; n++)
{
vector<double> tempPhi(phi); //copy phi to tempPhi
for (int i= 0; i<nmask; i++)
{
for (int a= -1; a<=1; a++)
{
for (int b= -1; b<=1; b++)
{
for (int c= -1; c<=1; c++)
{
if (!(a==0 && b==0 && c==0))
{
//oneD26 is just (double) 1/26
phi[i]= tempPhi[i]+oneD26*tempPhi[voxt[i][1+a][1+b][1+c]];
if (phi[i]!=0)
{
//this gives expected results: 27 nonzero elements (including tvox)
cout << n << " " << i << " " << a << b << c << " " << phi[i] << endl;
}
}
}
}
}
}
phi[svox]= 0; //svox = 7681
phi[tvox]= 1;
for (int q= 0; q<nmask; q++)
{
//this gives only 2 nonzero values: phi[tvox] and phi[9642], which was the last nonzero value from 1st cout
if (phi[q]!=0)
cout << q << " " << phi[q] << endl;
}
}
Difficult to tell just what is going on, but the easiest explanation is that after phi[i] gets set to non-zero and displayed to cout, it gets set to zero again in one of the later iterations through the inner loops.
If you do some tracing and check phi[i] just before updating you'll see that you often overwrite a non-zero element with zero.
Note: I have no idea what your code does, this is pure Sherlock Holmes reasoning.. if after the loops you find only 2 non-zero elements then the only logical consequence is that after updating something to non-zero later in the loop you update it to zero.
phi[i]= tempPhi[i]+oneD26*tempPhi[voxt[i][1+a][1+b][1+c]];
The nested for-loops using a, b, and c run for a combined 9 iterations with the same value of i. Since you overwrite phi[i] to a new value every time, you only retain the value from the last iteration where a, and c are all 1. If that last iteration happens to produce zero values, then phi[i] will have lots of zeroes. Perhaps you meant to do something like phi[i] += ... instead of phi[i] = ...?
I do suggest to replace the meat of the loop with something like
const boost::irange domain(-1,2);
for (int i: boost::irange(0, nmask)) for (int a: domain) for (int b: domain) for (int c: domain)
{
if (a==0 && b==0 && c==0)
continue;
//oneD26 is just (double) 1/26
phi[i]= tempPhi[i]+oneD26*tempPhi[voxt[i][1+a][1+b][1+c]];
if (phi[i]!=0)
{
//this gives expected results: 27 nonzero elements (including tvox)
cout << n << " " << i << " " << a << b << c << " " << phi[i] << endl;
}
}
Of course, for brevity I assume both boost/range.hpp and c++0x compiler. However, with trivial macro's you can achieve the same. That is without writing/using a proper combinations algorithm (why is that not in the standard, anyway).