Assign values to a 2D vector from a file on c++ - c++

Im trying to assign values to a 2d vector, this is the way that i defined the vector, and also its important to say that rows and columns, are ints previously defined
vector < vector <int>> vec(rows , vector <int> (columns,0));
i want to assign to this vector, each char of a pbm file, this file only have '1' and '0', so this is the way im reading it
char i;
FILE* fp;
fp = fopen("file.pbm", "r");
on this way im assigning values to the vector
for (int h=0; h<rows; h++){
for (int j=0; j<columns; j++){
while((i=fgetc(fp))!=EOF){
vec[h][j] = i;
}
}
}
but when i try to print all the vector content, this one, only have '0'
for (int h=0; h<rows; h++){
for (int j=0; j<columns; j++)
cout << vec[h][j];
cout <<endl;
}
fclose(fp);
If anyone could tell me where im failing when i make this assignment, thanks!
vec[h][j] = i;

for (int h=0; h<rows; h++){
for (int j=0; j<columns; j++){
while((i=fgetc(fp))!=EOF){
vec[h][j] = i;
}
}
}
The while loop runs through the entire file without ever incrementing h and j so you are reading the whole file into the first element. And you are doing this (rows*columns) times.
You'll need to redesign your code to read the code in correctly.

Related

Troubles displaying 2d array read from txt file (C++)

I'm having troubles doing a loop for a really basic console game that uses ASCII characters. I want to store the txt file (the map) into a 2d array and then I want to output the 2d array on the console.
You can see 2 loops under here, one for inputting the txt file into a 2d array and the other for outputting the 2d array on the screen.
void Level::load_level() {
Level gameLevel;
ifstream inFile;
gameLevel.map;
inFile.open("level1.txt");
if (inFile.fail()) {
perror("level1.txt");
system("PAUSE");
}
for (int i = 0; i < 20; i++) {
for (int j = 0; j < 74; j++) {
inFile >> map[i][j];
}
}
for (int i = 0; i < 20; i++) {
for (int j = 0; j < 74; j++) {
printf("%c", map[i][j]);
}
printf("\n");
}
inFile.close();
}
So, here is what my txt file looks like:
And here is what my console displays:
It seems like the data in the 2d array isn't store correctly, what should I do in order to keep one loop reading data from the file into a 2d array and another loop displaying the 2d array correctly? I don't know if I made that clear.
Thanks and sorry for my lack of skill(I'm a beginner).

How would i return a dynamic 2d vector or chars?

I have a 2d vector of chars that is declared by user input. but, how would i return this 2d vector of chars?
I know i need 2 for loops, but how would i, first get the size of how many vectors there are. second, find the size of one of the vectors in the 2d vector.
For example, lets say the user inputs:
.........
.........
....x....
.........
.........
how would i get the height and the width of this 2d vector and print it out?
what i have so far is this:
for (int i = 0; i < data.size(); i ++) {
for (int j = 0; j < data<data.size()>>; j++) {
}
}
Also, the user is allowed to input files that are larger than the one mentioned. Thats why i cant use an already declared variable.
I think a better question would be " how do i get the length of the 2d vector, and the height of one of the vectors to print out the entire thing? "
You mean:
for (int j = 0; j < data[i].size(); j++) {
You can get the height/rows with data.size() and the columns for each row with data[row].size().
for(i = 0; i < vec2d.size(); ++i) {
for(j = 0; j < vec2d[i].size(); ++j) {
// do whatever with vec2d
}
}

Reading values from file into 2D vector results in all values being zero

I'm trying to read a file of integer values and push each value into a 2D vector. For whatever reason, my resulting vector is full of zeros, rather than the values that I just read out of the file. Why is this and how do I fix it?
void populateVector(string file, vector<vector<int>>& v, int rows, int cols){
ifstream read(file);
int val;
if (!read.is_open()) {
throw runtime_error("Output file is not open.");
} else {
//Populate 2D vector with values from file
while (read >> val) {
cout << val << endl; //Prints each value being processed. Prints proper value.
for (int i = 0; i < rows; i++) {
vector<int> newCol;
v.push_back(newCol);
for (int j = 0; j < cols; j++) {
v.at(i).push_back(val);
}
}
}
}
}
When I print the vector it is populated solely of zeros, even though the read values that are printed to standard output are what I expect (the values from the file).
Your solution would push all the numbers 'cols' times into each row, that is you end up with row * (cols * n) matrix. Look at your loops correctly.
I assume you meant to read each number only once. Then change your loop to something like following (add error checking as necessary)
for (int i = 0; i < rows; i++)
{
std::vector<int> newRow;
for (int j = 0; j < cols; j++)
{
int val;
read >> val;
newRow.push_back(val);
}
v.push_back(newRow);
}
If you want to read one value at a time, you may want to consider a loop like this:
unsigned int column = 0;
std::vector<std::vector<int> > matrix;
std::vector<int> data_row;
while (read >> value)
{
data_row.push_back(value);
++column;
if (column > MAXIMUM_COLUMNS)
{
matrix.push_back(row_data);
data_row.clear();
column = 0;
}
}
The above code builds a row of data, one column at a time. When enough columns are read, the row is then appended to the matrix.

C++ how to modify a 2D vector of objects size in a function initialized in the constructor?

Since I'm Italian, the function names are in Italian but really simple to understand: immagine=image, inserisci=insert, altezza=height, larghezza=width,mosaico =mosaic, righe=rows, colonne=columns.
So this program has 2 classes: an image with its attributes and a mosaic, which contains n images and this is represented through a 2D vector of obj Image (Immagine). The 2D vector has to be initialized in the constructor with r rows and c columns and using the inserisci (insert/add) function will then grow its dimension. Then if the element passed in the insert function has more rows/columns the insert function has to add the needed rows and columns in order to insert the element.
The problem is that even though I used pointers/references, every time I try to insert an element with a size that is bigger than the one initialized in the constructor, it gives me an error, meaning that the 2D vector that I modify in the insert function is not really edited... (look at the main when I insert: m2.inserisci(i4, 4, 4, &m2.immagini) since 4 rows > inital size of rows and same for columns gives me a runnning error..) Hope it is clear. This is my code:
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;
class Immagine{
private:
string nome;
public:
int altezza;
int larghezza;
Immagine(string,int,int);
string toString();
};
Immagine::Immagine(string n, int a, int l){
nome = n;
altezza = a;
larghezza= l;
}
string Immagine::toString(){
return nome;
}
class Mosaico{
public:
Mosaico(int, int,Immagine,vector< vector<Immagine> >*);
int getRighe();
int getColonne();
string getImmagine(int,int);
bool exist(int, int);
Immagine getIm(int,int);
void inserisci(Immagine,int,int,vector< vector<Immagine> >*);
vector< vector<Immagine> > immagini;
vector< vector<Immagine> >* aPointer= &immagini;
};
Mosaico::Mosaico(int r, int c,Immagine imm, vector< vector<Immagine> >* immag ){
(*immag).resize(r);
for(int i=0; i<(*immag).size(); i++)
for(int j=0; j<c; j++)
(*immag)[i].insert((*immag)[i].begin()+j,imm);
}
bool Mosaico::exist(int r, int c){
for(int i = 0; i < getRighe(); i++){
for(int j=0; j<getColonne(); j++){
if(i==r && j==c && immagini[r][c].toString()!= " "){
return true;
}
}
}
return false;
}
int Mosaico::getRighe(){
return immagini.size();
}
int Mosaico::getColonne(){
return immagini[1].size();
}
string Mosaico::getImmagine(int r, int c){
if(exist(r,c))
return immagini[r][c].toString();
}
Immagine Mosaico::getIm(int r, int c){
return immagini[r][c];
}
void Mosaico::inserisci(Immagine imm,int r, int c, vector< vector<Immagine> >* immag){
if(r<(*immag).size() && c<(*immag)[0].size()){
(*immag)[r][c]=imm;
}
else if(r>=(*immag).size() && c>=(*immag)[0].size()){
(*immag).resize(r);
for(int i=0; i<r; i++){
for(int j=(*immag)[0].size(); j<c; j++){
(*immag)[i].insert((*immag)[i].begin()+j, imm);
}
}
(*immag)[r][c]=imm;
}
else if(r>=(*immag).size() && c<(*immag)[0].size()){
(*immag).resize(r);
(*immag)[r][c]=imm;
}
else if(r<(*immag).size() && c>=(*immag)[0].size()){
for(int i=0; i<(*immag).size(); i++){
for(int j=(*immag)[0].size(); j<c; j++){
(*immag)[i].insert((*immag)[i].begin()+j, imm);
}
}
(*immag)[r][c]=imm;
}
}
int main() {
Immagine i1 ("I01",300,200);
Immagine i2 ("I02",300,400);
Immagine i3 ("I03",400,200);
Immagine i4 ("I04",400,400);
cout << "Creo un mosaico 2x2 con quattro immagini" <<endl;
Mosaico m2(2,2,i1,&m2.immagini) ;
cout<<m2.getRighe()<<endl;
cout<<m2.getColonne()<<endl;
for (int i=0; i < m2.getRighe(); i++) {
for (int j=0; j < m2.getColonne(); j++){
//if(m1.exist(i,j))
cout<<m2.getImmagine(i,j);
}
cout<<endl;
}
m2.inserisci(i1, 0, 0, &m2.immagini);
m2.inserisci(i2, 0, 1, &m2.immagini);
m2.inserisci(i3, 1, 0, &m2.immagini);
m2.inserisci(i4, 4, 4, &m2.immagini); //HERE IS WHERE I GET THE ERROR
cout <<"Stampa mosaico: "<<endl;
for (int i=0; i < m2.getRighe(); i++) {
for (int j=0; j < m2.getColonne(); j++){
cout<<m2.getImmagine(i,j);
}
cout<<endl;
}
}
By the way, this was a Java exercise and I tried to do it in C++. Thanks in advance!
Before I'll get to the details of the issues, let me first state that there are a lot of things in the code I'd do differently. Most prominently, I'd probably use a flat vector<Image> for storage instead of a vector<vector<..>>. But such things are better suited for CodeReview in my opinion (once the code is working).
The biggest problems in the OP's code are within the implementation of the inserisci function:
void Mosaico::inserisci(Immagine imm,int r, int c,
vector< vector<Immagine> >* immag) {
if(r < (*immag).size() && c < (*immag)[0].size()){
(*immag)[r][c]=imm;
}
This part is fine, if we assume that (*immag)[i].size() is the same for all i in [0, (*immag).size()). Let us call this assumption A. The [x, y) notation stands for a half-open-on-right interval (x is within that interval, y is not). Note that you can replace (*e).m with e->m, which I'll do in the following.
The assumption A is a class invariant: after every member function (except for the destructor), this class invariant must hold. Continuing with the inserisci function:
else if(r>=(*immag).size() && c>=(*immag)[0].size()){
(*immag).resize(r);
The *immag vector now has r elements. This is insufficient if you want to access the rth element, since indexing starts with 0. You need to have at least r+1 elements. Replace the above resize with:
int newRowCount = r+1;
(*immag).resize(newRowCount);
Continuing with the OP's function:
for(int i=0; i<r; i++){
This has the same off-by-one bug: replace r with newRowCount, or simply immag->size().
for(int i=0; i<immag->size(); i++){
Continuing with the OP's function:
for(int j=(*immag)[0].size(); j<c; j++){
(*immag)[i].insert((*immag)[i].begin()+j, imm);
}
}
With the above resize, we have added newRowCount - immag->size() new elements to the immag vector. Those new elements are vectors of the size 0. To be able to access the cth element of such a vector, we need to add at least c+1 elements to it.
The value of (*immag)[0].size() however changes after the first iteration of the outer loop such that (*immag)[0].size() == c for the remaining (*immag)[i] elements where i is in [1, newRowCount). This code won't add any new columns to those rows. A simple fix is:
int newColumnCount = c+1;
for(int j=(*immag)[i].size(); j < newColumnCount; j++){
(*immag)[i].insert((*immag)[i].begin()+j, imm);
}
}
(*immag)[r][c]=imm;
}
A note related to code review: You can very easily resize the inner elements as well, using the resize-overload which takes an additional argument:
(*immag)[i].resize(newColumnCount, imm);
Continuing with the OP:
else if(r>=(*immag).size() && c<(*immag)[0].size()){
(*immag).resize(r);
This suffers from the same off-by-one bug again. You need to have at least r+1 elements to access the rth element in the following
(*immag)[r][c]=imm;
}
And in the following piece of code, the same issues appear as in the second branch (that is, (*immag)[0].size() instead of referring to the current element's size, and j < c instead of j < newColumnCount).
else if(r<(*immag).size() && c>=(*immag)[0].size()){
for(int i=0; i<(*immag).size(); i++){
for(int j=(*immag)[0].size(); j<c; j++){
(*immag)[i].insert((*immag)[i].begin()+j, imm);
}
}
(*immag)[r][c]=imm;
}
}

edit a range of elements inside a 2d array?

well ive been trying to edit the element of an array so lets assume that we have a 2d array
so
a 2d array 9 x 9;
for(... ... ... ++)
{
for(.. ... ...++){}
}
lets say that the code will use another set of for loops to display the 2d array its a simple array nothing fancy
00000000
00000000
00000000...
so if i wanted to to display an E from elements[1][0] to [2][3] how would i do that?
00000000
eeeeeeee
eeee0000
00000000
what i had in mind was something like while(x < y)
{ array[x++][y];}
but this idea doesnt seem to work.
would gladly take any help. thx
for(int i=0; i<9; i++) //This loops on the rows.
{
for(int j=0; j<9; j++) //This loops on the columns
{
board[i][j] = grid; // set the array to the char on grid '0'.
}
}
board[s_col][s_row] = 'Z';
while(s_col < e_col)//s_col is the start of the rows and columns
//{
//if(s_col != e_col)
{
++s_col;
board[s_col][s_row];
}
//}
//cout << board[s_col][s_row++] <<endl;
// display the array
for(int i=0; i<9; i++) //This loops on the rows.
{
for(int j=0; j<9; j++) //This loops on the columns
{
cout << board[i][j] << " ";
}
cout << endl;
}
You were on the right track with the approach:
for(... ... ... ++)
{
for(.. ... ...++){}
}
Here is some code that should help you:
#include <stdio.h>
#include <memory.h>
#define MAX_ROW 4
#define MAX_COL 8
void fillRange(char fillChar, int startRow, int startCol, int count);
char myArray[MAX_ROW][MAX_COL];
void printArray();
int main(int argc, char *argv[])
{
memset(myArray, '0', sizeof(myArray));
printf("\nBefore:\n");
printArray();
fillRange('e', 1, 0, 12);
printf("\nAfter:\n");
printArray();
}
void fillRange(char fillChar, int startRow, int startCol, int count)
{
int i, j, filledChars = 0;
for(i = startRow; i < MAX_ROW; i++)
{
for(j = startCol; j < MAX_COL; j++)
{
myArray[i][j] = fillChar;
if(++filledChars == count)
return;
}
}
}
void printArray()
{
int i, j;
for(i = 0; i < MAX_ROW; i++)
{
for(j = 0; j < MAX_COL; j++)
putchar(myArray[i][j]);
printf("\n");
}
}
If you instead wanted to end at a particular point in the array then you just need to change the condition that triggers the return.
This is one of the many reasons why the more coding you do the more you tend to avoid 2D arrays of the sort you have.
Instead you use a 1D array like this: board[i][j] == board_1D[i*num_columns+j]. That also means you can just iterate through the entire board in a single for loop.
Now you simply calculate the begin and end indices of your e range, and simply test if your counter is within that range. In other words, you have a single if statement inside your inner-most loop.
You can, of course, convert your i,j 2D indices into the equivalent 1D index and take the same approach. index_1D = i*9+j;
I'll leave the code to you.
Dealing with a sequence of adjacent values is easiest done when you have an underlying contiguous array and you don't need to deal with double indexing (see Adam's answer on that). However, in your simple case it also quite doable:
You'd initialize your row and column variables with the start row and column (in your case 0 and 1). You then walk with your column until you reached either the target column (2) and you are on the target row (3) or you reached the end of the matrix in which case you set the column to 0 and increment the row.