Read Strings from a text file and place in 2D Array - c++

I've spent the past two hours search this and other forums for pointers & guidance on how I can read a txt file, line by line, and store them in a 2D array that I can manipulate with other functions and then later save the array back to the text file; with little luck. Hopefully some bright spark can point me in the right direction.
Currently my text file contains data, separated by spaces, that looks like this:
Number1 Number2 Number3
Colour1 Colour2 Colour3
Letter1 Letter2 Letter3
...
The "getting and setting" of the 2D Array needs to be done in a separate function, and I think the array's need to be global because they will later be manipulated by other functions (i.e. add a new row, delete a row, etc.)
I know the start to the function will need to look something like this:
void getAndSetData()
{
fstream file1;
file1.open("1.txt", ios::in);
}
And will contain a nested for loop that will in turn, set the elements in the 2D array 1 by one. However, I'm really at a loss as how to go about this.
Thank you in-advance.

Hello here is example code how I did it
ifstream in("test.txt"); // input file
string my_array[3][200];
void read_into_array()
{
if(in.is_open())
{
for(int i = 0; i < 200; ++i) // number of rows
{
for(int j = 0; j < 3; ++j) // number of columns
{
in >> my_array[i][j];
cout<<my_array[i][j]<<"\t";
}
cout<<endl;
}
}
}

Related

Struggling to store data from file in an 2D int array

I'm working on a project where I'm supposed to be reading sets of parameters from a txt file to then print multiple circles within the command prompt. Here is the format of the file:
10 10 14 15
50 20 5 15
This is just the constructor I've made for the Circle Class, but while it seems to read the file properly, something must be going wrong with my nested for loops. I ran the program with it printing what it was reading from the file during the loops and then what was stored after and it only seems to be saving the last two numbers of the first line (the array seems to hold 14 14 14 14 15 15 15 15). This is only my second semester working on C++, so I can't help but wonder if there's something obvious I'm missing, but I could use some help here trying to figure out what's wrong with my loops/array so I can fix it and move on to the printing of the circles code which I'm also struggling with and running out of time to wrap my head around.
Circle::Circle(string fileAdd) //constructor function
{
int num; //variable for holding the file data in loops
cirCount = 0; //making sure this variable doesn't have junk value
cirStats = nullptr; //making sure this variable doesn't have junk value
string line;
ifstream userFile; //creating a filestream object
userFile.open(fileAdd); //opening the file
if (userFile.is_open()) //confirming the file has properly been opened
{
while (getline(userFile, line)) //the number of circles is stored in a separate variable by this loop
{
if (line.length() != 0) //this if statement checks whether the line is blank or not, and skips it if that's the case
{
cirCount++;
}
}
userFile.clear();
userFile.seekg(0);
cirStats = new int[STATS, cirCount]; //a dynamically allocated array is created in order to store the file data
for (int i = 0; i < cirCount; i++) //these nested loops store the data in a 2 dimensional array
{
for (int j = 0; j < STATS; j++)
{
userFile >> num;
cirStats[j, i] = num;
}
}
userFile.close(); //the file is closed to prevent issues down the line
cout << cirCount << endl;
}
//if the file has not been properly loaded, then this code will run and exit the program
else
{
cout << "User file failed to load. Please reset and try again.";
exit(0);
}
for (int i = 0; i < cirCount; i++) //these nested loops are just for testing what has been saved in the array
{
for (int j = 0; j < STATS; j++)
{
cout << cirStats[j, i] << endl;
}
}
};
The solution is in #Armin_Montigny's comment. Instructions like
cirStats[j, i] = num;
should, in fact, be written this way:
cirStats[j][i] = num;
that is, without the comma operator.

Properly handling input when file has less numbers than expected

I'm attempting to read in a file with 3 floating point numbers per line. Right now, I have this implemented as:
std::ifstream inFile(inName.c_str());
if (!inFile) {
prterr("in ASCII file could not be opened!\n");
return -1;
}
std::vector<double> xData, yData, zData;
xData.resize(nPoints);
yData.resize(nPoints);
zData.resize(nPoints);
inFile.precision(std::numeric_limits<double>::digits10+1);
for (int i = 0; i < nPoints; ++i) {
inFile >> xData[i] >> yData[i] >> zData[i];
inFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
so that the program successfully runs even if the user inputs more than 3 numbers per line. However, sometimes a user tries to run the program with <3 numbers per line. When this happens, the parser will obviously store the data incorrectly.
I would like to either (a) throw an error if the file has less than 3 numbers per line, or (b) Only store the first N numbers per line in their respective vectors if only N numbers per line are present in the file. The trick is, I want to do this as quickly as possible, as my datasets can be several GBs. I can be guaranteed that my file has the exact same amount of numbers per line.
Is there a graceful and efficient way to perform (b)? I know I could implement (a) just by reading the first line as a string separately before the for loop, but that seems quite ugly. Is there a better way to do this?
I know you dd not want to read in the first line as a std::string but you need someway to find out how many white space separated columns there are and unfortunately a newline is treated like white space. If you are okay with doing that though then you can see how man columns you have with
std::ifstream inFile(inName.c_str());
std::vector<int> columns_in_file;
std::string temp;
std::getline(inFile, temp);
std::stringstream ss(temp);
int number;
while (ss >> number)
columns_in_file.push_back(number);
Then what we need to do is set up a 2d vector that will have the correct number of columns and rows.
// get number of columns. 3 max
int columns = columns_in_file.size() <= 3 ? columns_in_file.size() : 3;
std::vector<std::vector<int>> data(nPoints, std::vector<int>(columns));
// now we add the data we already read
for (int i = 0; i < columns; i++)
data[0][i] = columns_in_file[i];
Now we have a vector that is the same size as the file unless the file has more then 3 columns and has the first line of data in it. Now we have a decision to make, since you will only ever need to call
inFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
while reading if columns_in_file.size() > 3, then we don't want to call it if it is not needed. We could either have the reading code in two different functions or in two different blocks in an else if statement. The latter is what I will show but know you could refactor it into function calls. So to actually read the file we would have something like
if (columns <= 3)
{
for (int i = 0; i < nPoints; i++)
{
for(int j = 0; j < columns; j++)
{
infile >> data[i][j];
}
}
}
else
{
for (int i = 0; i < nPoints; i++)
{
for(int j = 0; j < columns; j++)
{
infile >> data[i][j];
inFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
}
You can first get the number of columns in the file while reading the first set of values,as a string, and then use the count with another loop inside the first for loop:
[EDIT] As per the comments given(and the learning continues again), instead of making the all vectors resize initially, you can resize them depending on the available columns. this will avoid unnecessary space consumption for the unused vectors.
std::vector<double> Data[3];//the x,y,z data set(Assuming the maximum number of columns can't be >3)
//you can decide which of the vectors(x,y,z) are used by looking at the column count
inFile.precision(std::numeric_limits<double>::digits10+1);
int count=0;//count the number of columns
string first_line;
double temp;
getline(inFile,first_line);
istringstream ss(first_line);
while(ss>>temp && count<3)
{
Data[count].resize(nPoints);
Data[count][0]=temp;
count++;
}
for(int i=1; i<nPoints&& inFile.peek() != EOF ; i++)
{
for(int j=0;j<count;j++)
{
inFile>>temp;
Data[j][i]=temp;
}
inFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

How do I read text into a 2D array of larger parameters than the text (2D array has more rows and columns) using object.get()?

I am attempting to read a text file of characters into a character array (char array[MAX_ROW][MAX_COL]) and the text file has less rows and columns than the character array. This leads to a problem of reading past the substance material that is within the text file. I run into this problem when I read in using the following method:
ifstream whiteboard; //ifstream object for reading from a file.
whiteboard.open(board_name.c_str());
for(int i = 0; i < MAXROW; i++){ //naive read for canvas, not considering the /n characters or the size of the image.txt
for(int j = 0; j < MAXCOL; j++){ //for this to store the print properly it must be the exact size of the image dimensions
canvas[i][j] = whiteboard.get();
if(whiteboard.get() == '/n'){
return;
}
else if(whiteboard.get() != '/n'){
canvas[i][j] = whiteboard.get();
}
}
}
whiteboard.close();
The code above is supposed to run through the 2d array only to the point where the '/n' character is. Thus, allowing me to enter an array of any size. The newline character is at the end of each line of text in a text file (in the form of an enter keystroke). The read to file stops when a newline has been read. However, I am having issues implementing this correctly. Does anyone have any hints that may help me see this more clearly? Thank you very much!
EDIT:
Input File
xxxxxxxxxxxxxx
x x
x x
x x
x x
x x
xxxxxxxxxxxxxx
I am hoping to input the box above (along with all of its ' ' characters contained within it) into corresponding values of the character array. I wish to stop the read after reading the rightmost column of x's in and after reading the final x (the bottom right). You can see that my problem comes from having an array that is larger than the size of my text box here. I understand I could fix this by equating the character array to have the same dimensions as the text box, but I wish to keep a large enough constant so that I can read in a file of a relatively large size.
I have one solution, do the following:
int n=1025, m=1024, MAX_LINES=1025, i=0, j=0;
char character, Matrix[n][m];
fstream file;
file.open("file.txt", ios::in);
while (file.get(character))// loop executes until the get() function is able to read contents or characters from the file
{
Matrix[n][m]=character; // copy the content of character to matrix[n][m], here n is used to work as lines and m as normal arrays.
m++; // finished copying to matrix[n][m] then m++ else the program will overwrite the contents to the same array.
If (m>=1024)// if string[n][m] reached the limit which is 1024.
{
Matrix[n][m]='\0'; //termimate that line
m=0;// start with a new column
if (n<MAX_LINES)// if n is less than 1024 then
n++;// write to a next line because m can support only 1024 chars.
}
Matrix[n][m]='\0';// this will terminate the whole string not just one line.
file.close();
The Matrix Arrays is filled until the file has contents, but less than 1024x1024 chars, u can increase the chars input from the file but i face problems when taking inn more than 4 kb of data into Matrix...
I hope this helps u, if helps even a bit then +1 vote to my answer pls...
You are looking for something like this:
ifstream whiteboard;
whiteboard.open(board_name);
if ( !whiteboard.is_open() )
{
// do something here...
}
char c;
int row = 0, col = 0;
while ( whiteboard.get( c ) )
{
if ( c == '\n' )
{
row++;
col = 0;
continue;
}
canvas[ row ][ col++ ] = *reinterpret_cast< unsigned char * >( &c );
}
whiteboard.close();
With this code you can fill up your matrix with the content of the file... always supposing the "array" in the file fits in the array canvas[][]
If you aren't restricted to using an array, I wanted to add an alternative solution that would allow your canvas to be dynamically sized.
using std::vector;
std::ifstream whiteboard(board_name);
vector<vector<char>> canvas;
canvas.emplace_back();
// ^ Replace with push_back(vector<char>()); if not using C++11
char c;
while (whiteboard.get(c)) {
if (c == '\n') {
canvas.emplace_back(); // See above
}
else {
canvas.back().push_back(c);
}
}
You can decide to iterate through your canvas by using either range-based for loops or by using an index (iterators work too but are ugly):
// Loop through using range-based for (C++11)
for (auto& row : canvas) {
for (auto& col : row) {
std::cout << col;
}
std::cout << std::endl;
}
// Loop through using index
for (int i = 0; i < canvas.size(); i++) {
for (int j = 0; j < canvas[i].size(); j++) {
std::cout << canvas[i][j];
}
std::cout << std::endl;
}

How can I transfer a text file to array 2D in C++?

How can i transfer a text file(.txt) to array 2D in c++ and this is my source code
fstream fin('textfile.txt', ios::in);
int matrix[n][m]; // n is the number of rows and m is the number of columns
for(int i = 0;i < n; i++){
for(int j = 0; j<m; j++){
fin>>matrix[i][j];
}
}
but how can i detemine n and m for do this,i need your help and your advice, please Join us your perspectives
This solution requires C++11+
If there is no n & m in the file, you must assume that the layout is also in 2D
One Two Three
Four Five Six
Warning:: Untested code.
std::stringstream res;
std::string wordUp;
std::vector<std::string> str;
// the matrix, vector of vector of strings.
std::vector<std::vector<std::string>> matrix;
fstream fin('textfile.txt', ios::in);
int lines = 0;
int words = 0;
// read the file line by line using `getline`
for (std::string line; std::getline(fin, line); ) {
++lines;
// use stringstream to count the number of words (m).
res.str(line); // assign line to res. might also need some reset of good().
while (res.good()) {
res >> wordUp;
str.push_back(wordUp);
++words;
}
matrix.push_back(str);
str.erase(str.begin());
}
So u mean u want to read a file and copy contents to char Matrix[][]??, you can use while loop to read characters, and split every 1024 bytes(1 kb) by lines, i mean do this:
#include <fstream.h>
int main()
{
int n=0, m=0, MAX_LINES=1025, i=0, j=0;
char character, Matrix[1024][1025];
fstream file;
file.open("file.txt", ios::in);
while (file.get(character))// loop executes until the get() function is able to read contents or characters from the file
{
Matrix[n][m]=character; // copy the content of character to matrix[n][m], here n is used to work as lines and m as normal arrays.
m++; // finished copying to matrix[n][m] then m++ else the program will overwrite the contents to the same array.
If (m>=1024)// if string[n][m] reached the limit which is 1024.
{
Matrix[n][m]='\0'; //termimate that line
m=0;// start with a new column
if (n<MAX_LINES)// if n is less than 1024 then
n++;// write to a next line because m can support only 1024 chars.
}
}
Matrix[n][m]='\0';// this will terminate the whole string not just one line.
file.close();
for (i=0; i<1025; i++)
{
for (j=0; j<=1024 || Matrix[i][j]!='\0'; j++)
cout<<Matrix[i][j];
}
return 0;
}
This code will read 1024×1024 chars, but if the txt file is less than 1024(m) characters, the while loop will be exited and Matrix[n][m]='\0'; statement is executed.
EDIT: As asked by David i have written the whole code with main() sorry bro i forget, the bug in the code was the variables n and m were intialised to 1025 and 1024 so the program skips writing to Matrix as the Matrix[1024][1025] cannot store more characters... I think this would help, ok bro...

c++ How can I read values from a .csv file and store them in a vector?

I use Code::Blocks on Windows 7 to make little .exe from .cpp files, and I am a beginner (sorry!)
Here's today's problem:
I have a .csv file containing long integers (from 0 to 2^16) separated by semicolons and listed as a series of horizontal lines.
I will make a simple example here, but in reality the file can be up to 2Go big.
Let's say my file wall.csv appears like this in a text editor such as Notepad++:
350;3240;2292;33364;3206;266;290
362;314;244;2726;24342;2362;310
392;326;248;2546;2438;228;314
378;334;274;2842;308;3232;356
Strangely enough, it appears like this in the windows notepad
350;3240;2292;33364;3206;266;290
362;314;244;2726;24342;2362;310
392;326;248;2546;2438;228;314
378;334;274;2842;308;3232;356
Anyway,
let's say that I will know and will declare in 3 float variables the amount of columns, the amount of lines, and a value from the file.
int col = 7; // amount of columns
int lines = 4; // amount of lines
float x = 0; // a variable that will contain a value from the file
I want:
to create a vector <float> myValues
do myValues.push_back(x) with each value from the 1st line of the csv
do myValues.push_back(x) with each value from the 2nd line of the csv
do myValues.push_back(x) with each value from the 3rd line ...etc.
until the file has been entirely stored in the vector myValues.
My problem:
I don't know how to successively assign to the variable x the values present in the csv file.
How should I do that?
OK this code works (rather slowly but ok!):
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
int col = 1221; // amount of columns
int lines = 914; // amount of lines
int x = 0; // a variable that will contain a value from the file
vector <int> myValues;
int main() {
ifstream ifs ("walls.tif.csv");
char dummy;
for (int i = 0; i < lines; ++i){
for (int i = 0; i < col; ++i){
ifs >> x;
myValues.push_back(x);
// So the dummy won't eat digits
if (i < (col - 1))
ifs >> dummy;
}
}
float A = 0;
float B = col*lines;
for (size_t i = 0; i < myValues.size(); ++i){
float C = 100*(A/B);
A++;
// display progress and successive x values
cout << C << "% accomplished, pix = " << myValues[i] <<endl;
}
}
Put the text data into a stringstream and use std::getline.
It takes an optional third parameter which is the "end-of-line" character, but you can use ; instead of a real end of line.
Call
while (std::getline(ss, str, ';')) {..}
and each loop puts the text in std::string.
Then you will need to convert to a number data type and push into a vector but this will get you started.
Also, why do you use floats for the number of columns and lines?
They are integer values.
Try using the C++ Standard Template Library's input operations.
Make a dummy character variable to eat up semicolons, then cin numbers into your x variable like so:
char dummy;
for (int i = 0; i < lines; ++i){
for (int i = 0; i < col; ++i){
cin >> x;
myValues.push_back(x);
// So the dummy won't eat digits
if (i < (col - 1))
cin >> dummy;
}
}
To do it this way, you can redirect your csv file to be input from the command line like so:
yourExecutable.exe < yourFile.csv
To loop through a vector that is filled with data:
for (size_t i = 0; i < myVector.size(); ++i){
cout << myVector[i];
}
Above, the size_t type is defined by the STL library and is used to suppress an error.
If you want to use the values only once, removing them from the container as they are used, you're better off using the std::queue container. This way, you look at the front element using front() and remove it using pop().