Let's say I have a file that looks like the following:
|----------------------------------------------|
| |
| |---------| |--------------| |
| |.........| |..............| |
| |.........| |..............| |
| |----+----| |----+---------| |
| # # |
| ################### |
| |
|----------------------------------------------|
(it will be a map file for a game)
In this case, MAX_WIDTH is 48 and MAX_HEIGHT is 10.
I made it so that it does not skip whitespace when reading with
infile.unsetf(ios_base::skipws);
Then I used get() in a loop like following:
char tile[MAX_HEIGHT][MAX_WIDTH];
char c;
for(int i=0; i<MAX_HEIGHT; i++) {
for(int j=0; j<MAX_WIDTH + 1; j++) {
infile.get(c);
if(c == '\n') {
continue;
}
tile[i][j] = c;
}
}
But then after each line, it looked like lines were being pushed when I printed the array.
|--------------------------------------------|
|
|| |--------| |-------------|
|| |........| |.............|
|| |........| |.............|
|| |----+---| |----+--------|
Not exact but something like this.
What could've gone wrong and what can I do about it?
(+) Printing the array goes like the following:
for(int i=0; y<MAX_HEIGHT; y++) {
for(int j=0; x<MAX_WIDTH; x++) {
cout << tile[y][x];
}
cout << endl;
}
If you have windows style linebreaks in your input file you need to read two characters for each linebreak. \r\n. That would explain your corrupted output.
A fix would be to use std::getline style functions instead of get. Or explicitly check for the \r\n combination.
I guess it should be that j < MAX_WIDTH + 1
since your first line is good, probelm start happen in your second row
try remove that + 1
Edit:
remove that +1
you may try to is to add a check on both \r \n when reading
Related
This is the link above of the code of printing the number of words.
It's running properly but sometimes it's showing the error "out of range", I don't know the reason,
can someone please explain why?
#include <iostream>
using namespace std;
int main()
{
string str;
getline(cin, str);
int count = 0;
for (int i = 0; i < str.length(); i++)
{
if (str.at(i) == ' ')
{
i++;
}
else
{
while (str.at(i) != ' ')
{
i++;
if (str.at(i) == str.length())
{
break;
}
}
count++;
}
}
cout << "number of words are : " << count;
}
Online demo
Simple answer is:
while (str.at(i) != ' ')
might go out of bound.
Think what would happen if you enter these lines?
Hello!!!!
Hello world!!!
It will hit that while() loop and loop forever.
Why are you getting error sometimes, and not all the times? Because you are causing undefined behavior.
Your if statement is not doing what you think it is doing. It is comparing characters to str.lenght(). So basically you are comparing H, e, l, l and o against str.lenght().
If we look int ASCII char values we get this:
char | decimal value | str.lenght()
-----+---------------+--------------
H | 72 | 5
e | 102 | 5
l | 108 | 5
l | 108 | 5
o | 111 | 5
! | 33 | 5
! | 33 | 5
! | 33 | 5
Your line:
if (str.at(i) == str.length())
break;
should be:
if (i == str.length())
break;
to compare position in string with string length. Further more you should never use == to check if i against str.lenght() you should use >=, just in case there is a bug in memory somewhere and i skips value of str.lenght().
if (i >= str.length())
break;
Inside the whole loop you are using the expression str.at(i) == str.length(), but I believe it should be I == str.length().
My problem is that I don't understand nested loops well enough to answer this problem. I'm supposed to right-align a stack that I've made on a left alignment using nested for loops, but I can't quite figure out the conditions on the two inner ones.
Correct answer:
Height = 8
.......#
......##
.....###
....####
...#####
..######
.#######
########
My answer:
Height = 8
.......#
.......#......#
.......#......#.....#
.......#......#.....#....#
.......#......#.....#....#...#
.......#......#.....#....#...#..#
.......#......#.....#....#...#..#.#
.......#......#.....#....#...#..#.##
I've played around with it, took it seriously and nothing. I did (k = 7, k > j, k--), (k = 0, k < n-1, k++), k < j+7, I drew tables and i know that the height is pretty much the same as the value of the spaces but inverted on each line. I also know that the value of the hashes and the spaces should be equal to the height input by user.
It's supposed to take in a value from user, but I've worked on it on a separate file with the value n being the height to simplify and work on it without the rest of the program.
#include <stdio.h>
int main(void) {
int n = 8;
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
for(int k = 7; k > j; k--) {
printf(".");
}
printf("#");
}
printf("\n");
}
}
It's actually pretty simple. Write a table with each line and how many spaces and '#' you need to print:
n == 8
| output | line | num_spaces | num_signs |
| -------- | ---- | ---------- | --------- |
| .......# | 1 | 7 | 1 |
| ......## | 2 | 6 | 2 |
| .....### | 3 | 5 | 3 |
| ....#### | 4 | 4 | 4 |
| ...##### | 5 | 3 | 5 |
| ..###### | 6 | 2 | 6 |
| .####### | 7 | 1 | 7 |
| ######## | 8 | 0 | 8 |
For line you can start from 0 or from 1 or from n and go backwards. Pick something that is the easiest. You will see that starting from 1 is the simplest in your example.
Now for each line we need to determine how many num_spaces and num_signs we print. They should depend on line and on n.
For num_spaces it's n - line and for num_signs it's line
So the code should look like this:
// for each line
for (int line = 1; line <= n; ++line)
{
// print n - line spaces
// print line # characters
// print \n
}
With loops the code will look like this:
// for each line
for (int line = 1; line <= n; ++line)
{
// print n - line spaces
for (int i = 0; i < n -line; ++i)
std::cout << ' ';
// print line # characters
for (int i = 0; i < line; ++i)
std::cout << '#';
std::cout << '\n';
}
std::cout.flush();
But that's actually not recommended. You can get rid of those inner loops. One good and easy way is to use strings:
// for each line
for (int line = 1; line <= n; ++line)
{
// print n - line spaces
std::cout << std::string(n - line, ' ');
// print line # characters
std::cout << std::string(line, '#');
std::cout << '\n';
}
std::cout.flush();
And you can go even one step further:
// for each line
for (int line = 1; line <= n; ++line)
{
// print n - line spaces and line # characters
std::cout << std::string(n - line, ' ') << std::string(line, '#') << '\n';
}
std::cout.flush();
I have a 2 dimensional char array char** field. I have a method get_field() which makes a copy of this char array and returns this copy.
char** Game::get_field() {
char** copy = new char*[this->width_field];
for (unsigned int i = 0; i < this->width_field; i++)
copy[i] = new char[this->length_field];
for (unsigned int i = 0; i < this->width_field; i++) {
for (unsigned int j = 0; j < this->length_field; j++)
copy[i][j] = this->field[i][j];
}
return copy;
}
When I output the values of the copy to the console I get some garbage values after each row. However each row of the char array does contain the '\0' character to mark the end of the string. After some investigation with the debugger I found out that in the get_field() method extra garbage values are added outside the dimensions specified when declaring the array.
When length_field equals 52 I got 51 dashes plus the '\0' character like in the image and after that some extra garbage values. Where do these garbage values come from and how do I get rid of them?
[EDIT:]
This is the code that does the output to the console:
char** field = game->get_field();
for (unsigned int i = 0; i < 13; i++) {
cout << field[i] << endl;
}
This is the code how the initial field is setup:
this->field = new char*[this->width_field];
for (unsigned int i = 0; i < this->width_field; i++)
this->field[i] = new char[this->length_field];
this->setup_field();
void Game::setup_field(){
this->field[0] = "---------------------------------------------------\n\0";
this->field[1] = "| | |\n\0";
this->field[2] = "| | |\n\0";
this->field[3] = "| | |\n\0";
this->field[4] = "|---- | ----|\n\0";
this->field[5] = "| | -|- | |\n\0";
this->field[6] = "| | | | | | |\n\0";
this->field[7] = "| | -|- | |\n\0";
this->field[8] = "|---- | ----|\n\0";
this->field[9] = "| | |\n\0";
this->field[10] = "| | |\n\0";
this->field[11] = "| | |\n\0";
this->field[12] = "---------------------------------------------------\n\0";
}
Neither the C++ standard nor the Microsoft implementation gives any guarantees about memory which does not belong to you.
Accessing it for any reason is undefined behavior => anything may happen.
If you hand a char* which does not point to a 0-terminated string to a function expecting one, it will access out-of-bounds memory until it finds a 0 or it crashs in some manner.
That should sufficiently explain your "added garbage".
Sidenote: Is there any reason you cannot allocate all needed memory in one chunk?
As you later added after prompting, your copied lines are not 0-terminated.
Full size of any line: length + 1: 51 printable + 1 newline + 1 terminator
Tip: If you cannot use strdup and / or memdup, define them for yourself.
When length_field equals 52 I got 51 dashes plus the '\0' character
You actually have 54 characters in your Game::setup_field() strings:
51 dashes
One \n
One \0
One implicit \0 to end the string
Thus in your Game::get_field() method when you copy only 52 characters (stopping at the \n) you don't copy the \0 character resulting in an unterminated string.
Better to use a vector<string> or be more careful/explicit of array lengths when you initialize or copy things.
You really don't want to do it that way. Try this:
#include <vector>
#include <string>
std::vector<std::string> Game::get_field() {
std::vector<std::string> copy(this->width_field);
for (unsigned int i = 0; i < this->width_field; i++) {
for (unsigned int j = 0; j < this->length_field; j++) {
copy[i].push_back(this->field[i][j]);
}
}
return copy;
}
I have been trying to write code that determines if a matrix is upper triangular or not, and print it.
I have tried while loops, double for loops, nothing. Here is the mess I currently have:
int i, j;
int count = 0;
bool upper;
while (upper = true;)
{
for (i=1; i<m; i++)
{
for (j=i-1; j<n; j++)
{
if (a[i] > a[j] && a[i][j] == 0.0)
upper = true;
else if (a[i][j] != 0.0)
upper = false;
}
}
}
// cout << "Matrix is upper triangular. " << count << endl;
Look at example:
|0|1|2|3|4|5|
0| | | | | | |
1|X| | | | | |
2|X|X| | | | |
3|X|X|X| | | |
4|X|X|X|X| | |
5|X|X|X|X|X| |
This matrix is upper triangular is cells marked with X are all zero.
For i-th row - the cells {i,0},{i,1}, ... , {i,i-1} must be zero.
So it is easy task:
bool isUpperTriangle = true; // be optimistic!
for (int i = 1; i < SIZE && isUpperTriangle; ++i) // rows
for (int j = 0; j < i && isUpperTriangle; ++j) // columns - see example
if (m[i][j] != 0)
isUpperTriangle = false;
Whether the matrix is upper triangular or not can only be determined by checking the whole lower part. If you encounter a non-zero element along the way, you know it's not upper triangular. You cannot make that determination until you checked the whole lower part. So your:
upper = true;
statement while you're still in the loop has no logical basis.
The problem is similar to a character search inside a string. You need to check the whole string. If you arrived at the end of the string and still didn't find the character you're looking for, then (and only then) do you know that the character isn't in the string. The only difference with the matrix problem is that you've now got one additional dimension. Or, in other words, multiple one-dimensional arrays, each one +1 in size compared to the previous array, and you got to search them all.
I think this will likely do what you're looking for. Note: this assume the matrix is square. If it is not (i.e. m!=n) you should return false immediately:
bool upper = true;
for (i=1; i<m && upper; ++i)
for (j=0; j<i && (upper = (0 == a[i][j])); ++j);
Have you considered using a matrix library that has this function built in? I use the Eigen library quite often and I find the syntax very easy to use - they also have a short and useful tutorial to become familiar rather quickly.
http://eigen.tuxfamily.org/index.php?title=Main_Page
Ok, I'm trying to make a vertical bar graph from the values in a file. The code below works, to a point that is, and prints horizontally, but one asterisk per line, meaning there are spaces (obviously). Not looking for a spoonfed answer, just a push in the right direction.
using namespace std;
int main()
{
int counter;
cout<<"Please enter a number"<< "\n";
counter=0;
char *fname = "C:/Users/Jordan Moffat/Desktop/coursework/problem2.txt";
int x;
ifstream infile(fname);
while (infile >> x)
{
if (x==0 && x<=10){
cout<<"*"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\n";
}
else if (x>=10 && x<=20){
cout<<"\t"<<"*"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\n";
}
else if (x>=20 && x<=30){
cout<<"\t"<<"\t"<<"*"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\n";
}
else if (x>=30 && x<=40){
cout<<"\t"<<"\t"<<"\t"<<"*"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\n";
}
else if (x>= 40 && x<=50){
cout<<"\t"<<"\t"<<"\t"<<"\t"<<"*"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\n";
}
else if (x>=50 && x<=60){
cout<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"*"<<"\t"<<"\t"<<"\t"<<"\t"<<"\n";
}
else if (x>=60 && x<=70){
cout<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"*"<<"\t"<<"\t"<<"\t"<<"\n";
}
else if (x>=70 && x<=80){
cout<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"*"<<"\t"<<"\t"<<"\n";
}
else if (x>=80 && x<=90){
cout<<"*"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"*"<<"\t"<<"\n";
}
else if (x>=90 && x<=100){
cout<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"*"<<"\n";
}
}
cout<<"====================================================================================="<< "\n";
cout<<"0-9"<<"10-19"<<"20-29"<<"30-39"<<"40-49"<<"50-59"<<"60-69"<<"70-79"<<"80-89"<<"90-100"<<"\n";
system("PAUSE");
}
You have two problems. Apparantly you want to build a histogram and you want to visualize this histogram.
Histogram
One approach to build the histogram requires you to pre-specify the number of bins (homogeneous width), the minimum value (inclusive) and the maximum value (non-inclusive). Then you can compute the index of the bin each item should be assigned to.
Here's an (untested) example:
const int nbins = 10;
const double minval = .0, maxval = 100.;
std::vector<int> bins(nbins, 0);
for (double x; infile >> x; ) {
if (x >= minval && x < maxval) {
// note that integer rounding is probably towards zero, not towards -inf
int idx = floor((x-minval)/(maxval-minval)*nbins);
bins[idx]++;
}
else {
// handle outlier
}
}
Visualization
The approach described in this answer seems appropriate. For large bin counts you may need some normalization procedure, i.e. scaling the values to a range of [0,10] or similar.
Have a look at this (untested) example:
const int chart_height = 10;
const int max_count = *std::max_element(bins.begin(), bins.end());
for (int current_height = chart_height; current_height > 0; --current_height) {
for (int count : bins) {
const int bar_height = (count*chart_height)/max_count;
if (bar_height < current_height)
std::cout << " "; // we're still above the bar
else if (bar_height == current_height)
std::cout << " _ "; // reached the top of the bar
else // bar_height > current_height
std::cout << " | | "; // now the rest of the bar ...
}
std::cout << '\n';
}
With a little bit of fiddling and formatting magic you can also extend it to produce a borderline flexible visualization like this:
11 | _______ _______
| | | | |
| | | | |
| | | | |
| | | | | _______
5 | | | | | | |
| | | | | | |
| | | | | | | _______
| _______ | | | | | | _______ | |
| | | | | | | | | | | | |
+------v----------v----------v----------v----------v----------v-----
3.7 - 4.3 4.3 - 4.9 4.9 - 5.6 5.6 - 6.2 6.2 - 6.8 6.8 - 7.4
To make your bars vertically you need:
get all numbers in an array
determine the range, i.e. compute the max and min value of the array
make a loop over range, printing rows, leaving spaces on columns associate to values lower than the current row is 'depicting'.
here I assume steps 1 & 2 as done, just show the loop and gloss over some detail (note the code doesn't use min and loop from 0)
int values[] = {2,5,1,9,3}, cols = 5, max = 9;
for (int r = 0; r < max; ++r) {
for (int c = 0; c < cols; ++c)
cout << (r + values[c] >= max ? '*' : ' ');
cout << endl;
}
here the output
*
*
*
*
* *
* *
* **
** **
*****
You should read your data into an std::vector
Use two nested loops:
Looping over lines you print where first line is "0->10", second line "10->20" etc.
Looping over the vector, if variable is larger than (linecount-linenumber)*10, print " ", else print "*".
If your data goes from 0 to 100, linecount should be 10.
linenumber is the loop variable from first loop
It is not clear to me how your data is organized in the file. If your data file doesn't contain values which say how many *s each column should have, you should calculate that first.
Just having fun and practicing :)
enter any number sequence you want up to 100 numbers and press 0 to stop and make the graph :)
#include <iostream>
#include <limits>
using namespace std;
int main()
{
const int MAX = 100;
int values[MAX];
int input_number;
int total_number =0;
int largest_number = 0;
for (int i = 0; i < MAX; i++)
{
cin >> input_number;
if (input_number != 0)
{
total_number++;
values[i] = input_number;
}
else if (input_number == 0){
for (int t = 0;t<total_number;t++){
if(values[t]>largest_number)
largest_number = values[t];
}
for (int j = 0; j <largest_number; ++j){
for (int i = 0; i <total_number; ++i)
cout << (j+values[i] >= largest_number ? '*' : ' ') ;
cout << endl;
}
break;
}
}
system ("PAUSE");
return 0; // everything ok
}
I guess only one loop for each if condition you have written is sufficient.
And I agree with Kleist that Looping over variables and print * for each variable
(Similar to the answer of Kleist)
Make an array to define the y-axis (or a formula, based on an index)
Read the numbers from a file a save in a container, so you also know the number of values (x-axis)
double loop, 1 for the y-axis, 1 for the x-axis and find out whether an asterisk must be printed, based on 1.
Let the y-axis counter decrement, so your bars are rising.