Aligning output to the terminal using C++ - c++

I am having a lot of trouble aligning my output to the terminal. I want to print a vector of vectors viz vector< vector<double> > myvec; to the output where myvec[i] occupies the ith row on the terminal. The vectors composing myvec have size 3
This is the way I am trying to print it.
for(unsigned int i=0; i<myvec.size() ; ++i )
{
cout<<myvec[i][0]<<" "
<<myvec[i][1]<<" "
<<myvec[i][2]<<'\n';
}
When I print this to output only the myvec[i][0] column of numbers is aligned properly. The rest of the numbers look messy. Is there a good way to align this output?
(Ignore the 0.7 printed to the right on line 5 of image)

You can use setw() to set the minimum number of characters you want to be written and left to output the data to the left. Like this:
cout << setw(8) << left << myvec[i][0];
This should fill the empty space with spaces but if not, then you can do:
cout << setw(8) << left << setfill(' ') << myvec[i][0];
You will need to #include <iomanip> for this.

Just a couple notes about your code:
Alignment types
quasiverse's answer gives you left justification, i.e. every number starts in the first character position. Drop the left to make it right-justify, i.e. every number starts in the last character position.
Aligning the decimal points is a bit harder. If you want to set a fixed number of digits past the decimal point, then replace the left with fixed and add setprecision(), giving it the number of digits you want past the decimal. For example, to show two digits past the decimal:
cout << setw(8) << fixed << setprecision(2) << myvec[i][0];
2-D Vectors
You're declaring vector< vector<double> > myvec;, but the minor (second) dimension appears hardcoded to 3. This means that you are creating a vector of vectors, where each row is an entire vector object with storage for three doubles.
vectors don't store their data internally; the actual vector object just stores the number of elements, a pointer to the actual data storage, and maybe a couple other things. The actual data is stored in a separate block. This will create a lot of overhead and memory fragmentation (every row allocates a block to store the data).
For example, for a 1000x3 vector, there is the top-level vector object on the stack, an array of 1000 vector objects (one per row) on the heap, and each of those points to a block of three doubles, so you have 1001 objects on the heap and every access has to go through two pointers. Slow and inefficient.
vector is overkill if the length is fixed. So I'd recommend having a vector of structures, with each structure having three doubles:
struct point {
double x, y, z;
};
vector<point> myvec;
This stores all the data in one block, since point is completely self-contained. Then your code is:
for(unsigned int i = 0; i < myvec.size() ; ++i)
{
cout << setw(8) << left << myvec[i].x << ' ' << setw(8) << left << myvec[i].y
<< ' ' << setw(8) << left << myvec[i].z << endl;
}
Or, the C++ iterator way to do it:
for(vector<point>::const_iterator elem = myvec.begin(); elem != myvec.end() ; ++elem)
{
cout << setw(8) << left << elem.x << ' ' << setw(8) << left << elem.y
<< ' ' << setw(8) << left << elem.z << endl;
}
This saves a bunch of calls to operator[]. If your compiler supports the new C++11 standard, you can change the for() line to:
for(auto elem = myvec.begin(); elem != myvec.end() ; ++elem)
where auto tells the compiler to make elem the same type as what myvec.begin() returns. Another C++11 way, less likely to be supported, is the range-based for loop:
for(auto elem: myvec)

Related

Jumping into C++: Ch 5 Problem 7 using vertical bar graph

I am in need of assistance to create an vertical bar graph with required limitations of learning experience. Such as, using only the fundamental basics listed: if statement, boolean, loop, string, arithmetic and comparison operators. Basically giving an idea of how limited my experience is in the language for clarification. Now, I have completed this problem already but the output does not seem to look like a desirable graph in my opinion so this is why posting. I will provide the problem and valid code I used to complete this problem.
Write a program that provides the option of tallying up the results of a poll with 3 possible
values. The first input to the program is the poll question; the next three inputs are the possible
answers. The first answer is indicated by 1, the second by 2, the third by 3. The answers are
tallied until a 0 is entered. The program should then show the results of the poll—try making a
bar graph that shows the results properly scaled to fit on your screen no matter how many
results were entered.
#include<iostream>
int main()
{
bool poll = false;
int Tech = 0, Edu = 0, Agri = 0;
std::cout << "VOTING POLL" << std::endl;
std::cout << "----------------------------" << std::endl;
std::cout << "----------------------------" << std::endl;
while(!poll)
{
std::cout << "Of the year 2022, in the United States of America, what should be the top priority of our concerns?" << std::endl;
std::cout << " 1.Technology\n 2.Education\n 3.Agriculture" << std::endl;
std::cout << "\n";
int pollAnswer;
std::cin >> pollAnswer;
if(pollAnswer == 1)
{
Tech++;
}
else if(pollAnswer == 2)
{
Edu++;
}
else if(pollAnswer == 3)
{
Agri++;
}
else if(pollAnswer == 0)
{
poll = true;
}
else
{
std::cout << "\n" << "Invalid. Please choose an answer from the above listing." << std::endl;
}
}
std::cout << "Technology: ";
while(Tech > 0)
{
std::cout << "* ";
Tech--;
}
std::cout << std::endl;
std::cout << "Education: ";
while(Edu > 0)
{
std::cout << "# ";
Edu--;
}
std::cout << std::endl;
std::cout << "Agriculture: ";
while(Agri > 0)
{
std::cout << "| ";
Agri--;
}
}
using only the fundamental basics listed: if statement, boolean, loop, string, arithmetic and comparison operators.
Those are enough to write a sort of scanline algorithm:
Establish a maximum height for the bars and scale all the (three) values accordingly. This isn't mentioned in your requirements, but it seems better to avoid too high (or too low) bars.
for each line of output (you may initialize a loop variable row at max_height and decrease it down to 0):
print some spaces, so that you can add the labels after this loop.
if the value of the first scaled variable (say, Tech) is less than or equal to row, print a ' ' (a space) otherwise print the character chosen to represent that bar ('*', I think).
repeat for all the other bars and then add a '\n' (newline) to end this row.
Print the labels, like "Technology" and the likes, correctly spaced.
I'll leave all the details of the implementation to the reader.
I think the first thing to do would be to make sure all the labels take up the same amount of space, so the bars in the graph all start from the same location on the left.
The text suggests scaling the graph to fit the screen. To do that we probably want to take the largest of the three counts, and figure out what to multiply that by so it'll be close to (but not greater than) the screen width (e.g., 80 columns), then multiply all three values by that scale factor.
I wouldn't use spaces in the bars, so each bar would look more "solid".
Possible result:
Technology: ****************************************
Education: ##########################
Agriculture: ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
If you want vertical bars instead of horizontal, you'd typically do that by storing the characters into (for one possibility) a 2D array. Then when you're done creating the graph in that 2D array, you scan across the array "sideways" to print out its contents, and scan through the other direction "backwards", so your labels end up at the bottom of the screen. I'd start by filling the array with space characters, then write out the contents of the bars into the array. Then after that's one, you print it out to the screen.

Correctly reading a known number of integer inputs into a vector in C++

I'm new to C++ and wanted to make a small function today which would flip all the elements of an array that was given to it (I had a pretty good idea for it). I started using arrays, but ran into issues since only a pointer to the first element is passed to the function; it was giving some very strange output. It was recommended I use a vector instead, but that started to give me some really odd output, too. I added a cout iterating over the vector values to see what it contains for some sanity-checking, but the outputs are completely bizarre; looks like I'm struggling to work out how to read input into it correctly.
As I mentioned, I first tried an array, which I could read into fine with a range-for loop. I tried that same thing with vectors (solution 1) and found it to be ignoring the first input, and assigning each element the last value that I gave it.
I first tried other Stack overflow threads but I found the solutions far too verbose or not suitable for something as simple as I need.
I thought maybe the vector couldn't be used in the range-for so I did for(auto x : array_size) instead - this gave an error stating there was no suitable "begin" for the function, so I changed this back.
Instead I looked around at the documentation and found .push_back(value) (solution 2) which appeared to put a given value at the end of the vector. Thought I might at least get some input into it correctly, which would be a step in the right direction. Instead, the output seems to show it doubled the number of positions in the vector and just assigned my first input to the furthest position. I imagine this is due to me specifying a size for the vector, and then having push_back grow the vector by that number of inputs (resulting in a double-size vector).
As for the input values themselves, I'm stumped.
Below is the offending bit of code as it stands with solution 2.
int main()
{
int array_size;
auto index_num = 0;
int arr_input = 0;
std::cout << "This program flips an array." << "\n";
std::cout << "Enter how many elements will be in your array: ";
std::cin >> array_size;
std::vector<int> user_array (array_size);
std::cout << "Fill your array with integer values. Press 'Enter' after each: " << std::endl;
for(auto x : user_array)
{
std::cin >> arr_input;
user_array.push_back(arr_input);
}
index_num = sizeof(user_array) / sizeof(user_array[0]); //or just use array_size-1 instead?
std::cout << "Your array, unflipped, contains the values: " << "\n";
for(auto y : user_array)
{
std::cout << "[" << user_array[y] << "] ";
}
Solution 2 provides this output:
Fill your array with integer values. Press 'Enter' after each:
1
2
3
4
5
Your array, unflipped, contains the values:
[0] [0] [0] [0] [0] [0] [0] [0] [0] [1]
Solution 1, where I attempt to input directly into the n-th location of the vector (as I would with an array) provides this output (with the same five 1 - 5 inputs):
Your array, unflipped, contains the values:
[0] [5] [5] [5] [5]
No error messages, everything is perfectly legal, I clearly just don't understand how something simple like a vector is implemented here.
I haven't even got to the taxing bit yet - flipping the array! Any advice appreciated.
std::vector<int> user_array (array_size) creates a vector containing array_size zeros. You then use push_back which adds additional elements to the end. You need to create an empty vector using std::vector<int> user_array, and optionally with a capacity of array_size by calling user_array.reserve(array_size). Since your vector starts out empty now, you'll need to change for(auto x : user_array) to a non-range-based loop such as for (int i = 0; i < array_size; i++).
sizeof(user_array) / sizeof(user_array[0]) only works with plain C arrays, not vectors. Use array_size or user_array.size().
In the last range-based for loop, y is the values in the array, not the indices. So print y, not user_array[y].
You seem to be confusing std::vector with C-style arrays.
std::vector<int> user_array (array_size);
initializes user_array with array_size zeroes.
for(auto x : user_array)
{
std::cin >> arr_input;
user_array.push_back(arr_input);
}
As noticed by Alexander Zhang, this piece modifies the vector while iterating over it, which results in Undefined Behaviour. It could result in anything happeining in your program, including infinite loop, crashing completely, supposingly working correct or demons flying out of your nose
index_num = sizeof(user_array) / sizeof(user_array[0]); //or just use array_size-1 instead?
This line makes no sense. You can get the length of vector using its size() method: user_array.size();, but you don't use that variable anyway.
for(auto y : user_array)
{
std::cout << "[" << user_array[y] << "] ";
}
This loop makes no sense either. y is not an index in the vector, it is a value from that vector. If you have a vector {10, 20, 30}, then in first iteration y is equal to 10, in second iteration y is 20 and in third y is 30.
After fixing the errors, your code should look like this:
std::vector<int> user_array ();
std::cout << "Fill your array with integer values. Press 'Enter' after each: " << std::endl;
for(int i = 0; i < array_size; ++i)
{
std::cin >> arr_input;
user_array.push_back(arr_input);
}
std::cout << "Your array, unflipped, contains the values: " << "\n";
for(auto y : user_array)
{
std::cout << "[" << y << "] ";
}
Or for an (invisible) increase in performance, you can reserve the size of the vector before you read it:
std::vector<int> user_array ();
user_array.reserve(array_size);
std::cout << "Fill your array with integer values. Press 'Enter' after each: " << std::endl;
for(int i = 0; i < array_size; ++i)
{
int x;
std::cin >> x;
user_array.push_back(x);
}

Vector going out of bounds

I'm attempting to iterate through a list of 6 'Chess' pieces. Each round they move a random amount and if they land on another then they 'kill' it.
The problem is that when the last piece in my vector kills another piece I'm getting a vector 'out of range' error. I'm guessing it's because I'm iterating through a vector whilst also removing items from it, but I'm not increasing the count when I erase a piece so I'm not entirely sure. Any help would be greatly appreciated.
Here is my vector:
vector<Piece*> pieces;
pieces.push_back(&b);
pieces.push_back(&r);
pieces.push_back(&q);
pieces.push_back(&b2);
pieces.push_back(&r2);
pieces.push_back(&q2);
and this is the loop I iterate using:
while (pieces.size() > 1) {
cout << "-------------- Round " << round << " --------------" << endl;
round++;
cout << pieces.size() << " pieces left" << endl;
i = 0;
while (i < pieces.size()) {
pieces.at(i)->move(board.getMaxLength());
j = 0;
while (j < pieces.size()) {
if (pieces.at(i) != pieces.at(j) && col.detectCollision(pieces.at(i), pieces.at(j))) {
cout << pieces.at(i)->getName() << " has slain " << pieces.at(j)->getName() << endl << endl;
pieces.at(i)->setKills(pieces.at(i)->getKills() + 1);
pieces.erase(pieces.begin() + j);
}
else {
j++;
}
}
i++;
}
}
Solution
pieces.erase(pieces.begin() + j);
break;
Your logic needs a little refinement.
The way you coded it, it seems the "turn based" nature of chess has been replaced by a kind of "priority list" -- the pieces closer to the start of the vector are allowed to move first and, thus, get the priority into smashing other pieces.
I don't know if you want this logic to be right or wrong. Anyway, the trouble seems to be due to unconditionally executing the line
i++;
It should not be executed if you remove a piece for the same reason 'j++' isn't executed: you will jump over a piece.
I have a very strong feeling that this line of code:
i++;
is your culprit which is missing either a needed break condition or another conditional check that is missing from your loops. As it pertains to your nested while loops' conditions since they are based on the current size of your vector and are not being updated accordingly.
while (pieces.size() > 1) {
// ...
while (i < pieces.size()) {
// ...
while (j < pieces.size()) {
// ...
}
}
}
This is due to the fact that you are calling this within the inner most nested loop:
pieces.erase(pieces.begin() + j);
You are inside of a nested while loop and if a certain condition is met you are then erasing the object at this index location within your vector while you are still inside of the inner while loop that you never break from or check to see if the index is still valid.
Initially you are entering this while loop with a vector that has 6 entries, and you call erase on it within the nested loop and now your vector has 5 entries.
This can reek havoc on your loops because your index counters i & j were set according to the original length of your vector with a size of 6, but now the vector has been reduced to a size of 5 while you are still within the inner most nested loop that you never break from nor check to see if the indices are valid. On the next iteration these values are now invalidated as you never break out of the loops to reset the indices according to the new size of your vector, nor check to see if they are valid.
Try running this simple program that will demonstrate what I mean by the indices being invalidated within your nested loops.
int main() {
std::vector<std::string> words{ "please", "erase", "me" };
std::cout << "Original Size: " << words.size() << '\n';
for (auto& s : words)
std::cout << s << " ";
std::cout << '\n';
words.erase(words.begin() + 2);
std::cout << "New Size: " << words.size() << '\n';
for (auto& s : words)
std::cout << s << " ";
std::cout << '\n';
return 0;
}
-Output-
Original Size: 3
please erase me
New Size: 2
please erase
You should save locally pieces.at(i) and use this local variable everywhere you use pieces.at(i).
To avoid both elements out of bound and logical problems you can use std::list.
As aside, you should use std::vector<Piece*> only if these are non-owning pointers, otherwise you should use smart-pointers, probably unique_ptr.

How to pushback a vector of 3 elements into a vector in C++?

I have a long vector of values, a specified user input of row/column size. I need to assign a set of 3 numbers into a vector, from the long list of vectors. The vector with 3 number set will be pushed back into another vector, with user input row/column size. 1 column = the 3 number vector set and so on, until every column is filled out. I have trouble making this code (it needs to be in a loop). Any help please?
The picture is an example of a 4x4 vector, with each column a vector of 3 numbers
It sounds as if you want nested vectors, where each smaller vector inside your "long vector" represents a column of 3 values. If so you could do so like:
std::vector<int> columnVec = { 1, 2, 3 };
std::vector<std::vector<int>> longVector;
longVector.push_back(columnVec);
In the first line we declare a vector representing our column and place three integers inside it. On line two we declare another vector, but this time containing vectors which themselves contain ints, i.e. a vector full of column vectors. We then used push_back() to push the column vector into our vector of vectors. If you needed to print the values you could do so like:
for(auto& vec : longVector) { //Walk through our vector of vectors.
for(int value : vec) { //Walk through our column vectors of values.
std::cout << value; //Print out each value of the column.
}
std::cout << std::endl; //Add a newline.
}
Note that if you print them, the columns will appear as rows in the console. If you care about the formatting in the console it will take a bit more effort and might be worth asking as a separate question.
One possible approach might look something like this:
#include <iostream>
#include <cstdlib>
#include <vector>
using namespace std;
int main()
{
typedef std::vector<int> VecInt;
typedef VecInt::iterator VecIntIter;
typedef std::vector<VecInt> VecVecInt;
typedef VecVecInt::iterator VecVecIntIter;
VecVecInt rows;
const int maxRows = 10, maxCols = 10;
cout << "Values during creation" << endl;
cout << "----------------------" << endl;
for (int rowNum=0; rowNum<maxRows; rowNum++)
{
VecInt curRow;
for (int colNum=0; colNum<maxCols; colNum++)
{
if (colNum != 0)
cout << " ";
int cellValue = rand() % 32;
cout << cellValue;
curRow.push_back( cellValue );
}
cout << endl;
rows.push_back(curRow);
}
cout << endl;
cout << "Values during retrieval" << endl;
cout << "----------------------" << endl;
for (VecVecIntIter rowIter=rows.begin(); rowIter!=rows.end(); rowIter++)
{
VecInt curRow = (*rowIter);
for (VecIntIter colIter=curRow.begin(); colIter!=curRow.end(); colIter++)
{
if (colIter != curRow.begin())
cout << " ";
cout << (*colIter);
}
cout << endl;
}
}
Though, this will store a collection of rows, rather than a collection of columns. Easy enough to change the for loops.

histogram program gives strange output C++

I have been writing code to produce a horizontal histogram. This program takes user input of any range of numbers into a vector. Then it asks the user for the lowest value they want the histogram to begin at, and how big they want each bin to be. For example:
if lowestValue = 1 and binSize = 20
and vector is filled with values {1, 2, 3, 20, 30, 40, 50} it would print something like:
(bin) (bars) (num)(percent)
[ 1-21) #### 4 57%
[21-41) ## 2 28%
[41-61) ## 2 28%
Here is most of the code that does so:
void printHistogram(int lowestValue, int binSize, vector<double> v)
{
int binFloor = lowestValue, binCeiling = 0;
int numBins = amountOfBins(binSize, (int)range(v));
for (int i = 0; i<=numBins; i++)
{
binCeiling = binFloor+binSize;
int amoInBin = amountInBin(v,binFloor, binSize);
double perInBin = percentInBin(v, amoInBin);
if (binFloor < 10)
{
cout << "[ " << binFloor << '-' << binCeiling << ") " << setw(20) << left << formatBars(perInBin) << ' ' << amoInBin << ' '<< setprecision(4) << perInBin << '%' << endl;
binFloor += binSize;
}
else
{
cout << '[' << binFloor << '-' << binCeiling << ") " << setw(20) << left << formatBars(perInBin) << ' ' << amoInBin << ' '<< setprecision(4) << perInBin << '%' << endl;
binFloor += binSize;
}
}
}
and the function that counts how many terms are in each bin:
int amountInBin(vector<double> v, int lowestBinValue, int binSize)
{
int count = 0;
for (size_t i; i<v.size(); i++)
{
if (v[i] >= lowestBinValue && v[i] < (lowestBinValue+binSize))
count += 1;
}
return count;
}
Now my issue:
For some reason, it is not counting values between 20-40. At least as far as I can see from my testing. Here is an image of a run:
Any help is appreciated.
I would suggest a different approach. Making two passes, first calculating the number of bins, then another pass to add them up, looks fragile, and error-prone. Not really surprise to see you trying to figure out a bug of this kind. I think your original approach is too complicated.
As the saying goes "the more you overthink the plumbing, the easier it is to stop up the drain". Find the simplest way to do something, and it will have the least amount of surprises and gotchas, to deal with.
I think it's simpler to make a single pass over the values, calculating which bin each value belongs to, and counting the number of values seen per bin. Let's use a std::map, keyed by bin number, with the value being the number of values in each bin.
void printHistogram(int lowestValue, int binSize, const std::vector<double> &v)
{
std::map<int, size_t> histogram;
for (auto value:v)
{
int bin_number= value < lowestValue ? 0:(value-lowestValue)/binSize;
++histogram[bin_number];
}
And ...that's it. histogram is now your histogram. histogram[0] is now the number of values in the first bin, [lowestValue, lowestValue+binSize), which also includes all values less than lowestValue. histogram[1] will be the number of values found for the next bin, and so on.
Now, you just have to iterate over the histogram map, and generate your actual histogram.
Now, the tricky part here is that the histogram map will only include keys for which at least 1 value was found. If no value was dropped into the bin, the map will not include the bin number. So, if there were no values in the first bin, histogram[0] won't even exist, the first value in the map will be the bin for the lowest value in the vector.
This isn't such a difficult problem to solve, by iterating over the map with a little bit of extra intelligence:
int next_bin_number=0;
for (auto b=histogram.begin(); b != histogram.end(); b++)
{
while (next_bin_number < b->first)
{
// next_bin_number had 0 values. Print the histogram row
// for bin #next_bin_number, showing 0 values in it.
++next_bin_number;
}
int n_values=b->second;
// Bin #n_next_number, with n_values, print its histogram row
++next_bin_number;
}
The code in the loop doesn't initialize i, so the results are at best unpredictable.