Reading file into two arrays - c++

I'm trying to write my own vocabulary with a test for my little brother, but I have a problem when I want to read data from file into two arrays - first with English words, and second with Polish words. File looks alike
black - czarny
red - czerwony etc.
And my function:
void VOC::readout()
{
fstream file;
VOC *arr = new VOC;
string line;
file.open("slowka.txt");
if(file.good())
{
int i=0;
while(!file.eof())
{
getline(file, line);
size_t pos = line.find(" - ");
int position = static_cast<int>(pos);
file>>arr[i].en;
file>>arr[i].pl;
++i;
}
}
}
I thought it could be a good idea to insert a line into first array until the function finds " - ", and after that insert the rest of line into second array, but I have some problems with that. Could someone help me? I know I can solve it by using std::vector but I care to do that by using arrays.

If you insist on using plain arrays, you'll first have to count the number of lines in your file and then allocate enough memory. Arrays -- unlike std::vector objects -- won't grow automatically but have a fixed size.
That being said, note that using !file.eof() is not the best way to read a stream until the end is reached. You can use the simpler
std::string line;
while (std::getline(file, line)) {
// ...
}
idiom instead, which also takes care of error conditions. See this question (and corresponding answers) for more information on that.

Related

Reading lines of txt file into array prints only the last element

First of all, I didn't code in C++ for more then 8 years, but there is a hobby project I would like to work on where I ran into this issue.
I checked a similar question: Only printing last line of txt file when reading into struct array in C
but in my case I don't have a semicolon at the end of the while cycle.
Anyway, so I have a nicknames.txt file where I store nicknames, one in each line.
Then I want to read these nicknames into an array and select one random element of it.
Example nicknames.txt:
alpha
beta
random nickname
...
Pirate Scrub
Then I read the TXT file:
int nicknameCount = 0;
char *nicknames[2000];
std::string line;
std::ifstream file("nicknames.txt");
FILE *fileID = fopen("asd.txt", "w");
while (std::getline(file, line))
{
nicknames[nicknameCount++] = line.data();
// (1)
fprintf(fileID, "%i: %s\n", nicknameCount - 1, nicknames[nicknameCount - 1]);
}
int randomNickIndex = rand() % nicknameCount;
// (2)
for (int i = 0; i < nicknameCount; i++)
fprintf(fileID, "%i: %s\n", i, nicknames[i]);
fprintf(fileID, "Result: %s\n", nicknames[randomNickIndex]);
fprintf(fileID, "Result: %i\n", randomNickIndex);
fclose(fileID);
exit(0);
What then I see at point (1) is what I expect; the nicknames. Then later at point (2) every single member of the array is "Pirate Scrub", which is the last element of the nicknames.txt.
I think it must be something obvious, but I just can't figure it out. Any ideas?
line.data() returns a pointer to the sequence of characters. It is always the same pointer. Every time you read a new line, the contents of line are overwritten. To fix this, you will need to copy the contents of line.
Change:
char *nicknames[2000];
to
char nicknames[2000][256];
and
nicknames[nicknameCount++] = line.data();
to
strcpy(nicknames[nicknameCount++], line.data());
However, using a vector to store the lines is probably better, since this is C++
Your nicknames array does not contain copies of the strings, all the nicknames are pointers to the same data owned by line.
Instead of char* nicknames[2000] i would recommend you use
std::vector<std::string> nicknames;
and then inside the loop:
nicknames.push_back(line);
This:
char *nicknames[2000];
is an array of 2000 pointers to char. Nowhere in your code you are actually storing the strings from the file. This
nicknames[nicknameCount++] = line.data();
merely stores pointers to the lines internal buffer in the array. In the next iteration this buffer is overwritten with contents of the next line.
Forget about all the C i/o. Mixing C and C++ is advanced and you don't need it here. If you want to store a dynamically sized array of strings in C++, that is a std::vector<std::string>:
std::vector<std::string> lines;
std::string line;
while (std::getline(file, line))
{
lines.push_back(line);
}
Also for writing to the output file you should use an std::ofstream.

How to read individual lines of a text file using C++

Ok, so its been a while since i messed with reading and writing file and i have just about forgot everything i learned. So, i am currently just trying to figure out how to read specific lines from a text file and output that said line into the command prompt. Here is my code that i am having issues with:
#include <iostream>
#include <fstream>
using namespace std;
int main(){
ifstream input;
int lineN=0;
string line[lineN];
input.open("input.txt");
getline(input, line[lineN]);
cout << line[lineN];
}
As it currently is, it will read the first line of the text file no problem. However, if i change the variable lineN(which stands for line number) to 1 to read the second line, it crashes the prompt. I have no idea what it is i am doing wrong. I have tried researching this problem, but everyone's answer is too vague (That or i'm just too dumb). If you could help me out that would great.
The problem is that you define here an empty array of strings and arrays are not dynamic:
int lineN=0;
string line[lineN];
When you change lineN to 1, nothing changes in the array, and you'll get out of bound !
The bettter way would be to use vectors:
vector<string> line;
Read in a temporary string:
string current_line;
getline(input, current_line);
and add it to your vector:
line.push_back(current_line);
Putting all this in a nice loop would be more useful:
string current_line;
while (getline(input, current_line)) {
line.push_back(current_line);
}
You may access any line later, by using line[i] exactly with your array, as long as i< line.size(). Or you may iterate easily throug all its content:
for (string x : line) { // means for every x in line[]
cout<< x<<endl;
}
you allocate a array of size 0 ...
you will find answer of what will happen can be found here:
C++ new int[0] -- will it allocate memory?

Loading Data From Comma Separated Text File to 2D Array?

I am trying to load data from a text file that looks like this:
161,77,88,255
0,44,33,11,111
etc. I have functions to manipulate it, and am ensured that the array is the correct size (which may still vary). Below is my attempt at implementation:
bool loadData(int **imgPix, string fileName) {
ifstream inputFile;
inputFile.open(fileName.c_str());
string tempLineRow; //The resulting line from the text file
string tempElementColumn; //The individual integer element
int numberOfCols = 0;
int numberOfRows = 0;
if (!inputFile.is_open()) {
return false;
}
imgPix = new int* [numberOfRows];
while (getline(inputFile, tempLineRow, '\n')) {
stringstream ss;
ss << tempLineRow; //Stringstream version of the line
while (getline(ss, tempElementColumn, ',' )) {
stringstream ss2;
ss2 << tempElementColumn;
ss2 >> numberOfCols;
//Prob? (**imgPix) = *(*(imgPix + numberOfRows) + numberOfCols);
numberOfCols++;
}
numberOfRows++;
}
inputFile.close();
return true;
}
I've marked the line with the double pointer assignment with a comment, because I believe it be the source of my error, although there could be others. I'm not sure how to use the while loop structure I've implemented to iteratively update the 2D array.
Can anyone offer any assistance? Would be greatly appreciated!
imgPix = new int* [numberOfRows]
Here numberOfRows = 0, so you don't allocate enough memory. You need to know dimensions of the array before you allocate the memory.
And then you should also allocate a memory for each row in the array:
imgPix[currentRow] = new int [TotalCols];
For a 2-dimensional rectangular array, it would be more efficient to create 1-dimensional array of TotalRows*TotalCols elements, and then access it using formula A(row, col) = A[row*TotalCols + col].
Your code has several issues, mostly I guess because you did not fully understand how built-in arrays work in C++. The main issue here is that those cannot easily grow dynamically, there is no "resize" operation for those arrays (but you will need one here). So I suggest kindly that you try to rewrite your code using std::vector<int> and std::vector< std::vector<int> >, make sure you use of .resize when you store a new row or column and come back and ask again when you run into problems with this new implementation.
Previous answers are valid, but if contiguous memory is not a requirement, std::deques may be a better choice in this case compared to std::vectors to avoid lots of memory reallocations.

Reading input into dynamically-sized array

What I've been trying to do, is read a line from stdin and split it, by using whitespace as seperators.
Let's say I have this as input:
2
1 2
3 4
The first line gives me the amount of lines I'd like to read, they're all lines with integers seperated by an unknown amount of whitespace (i.e. could be 1 space, but it could also be 10 spaces).
The thing I've been trying to do is reading those lines into dynamically sized arrays of integers.
This was extremely easy in Python:
foo = raw_input()
array = foo.split()
or even shorter:
foo = raw_input().split()
However, because of the circumstances, I have to learn the beauty of C++.
So I tried to create something akin to the above Python code:
#include <iostream>
using namespace std;
int lines;
int *array;
int main() {
cin >> lines;
for (int line = 0; line < lines; line++) {
// Something.
}
}
I don't seem to know a way to split the line of input. I know that std::cin reads until it reaches a whitespace. However, I can't seem to think of something to count the amount of numbers on the line...
A little nudge into the right direction would be appreciated, thanks.
so given all you wanted is a nudge, here are a couple of hints..
std::getline() - allows you to read from a stream into a std::string.
You can then construct a std::istringstream using this string which you've just read in. Then use this stream to read your ints
for example:
std::string line;
if(std::getline(std::cin, line))
{
std::istringstream str(line);
int lc;
if (str >> lc) // now you have the line count..
{
// now use the same technique above
}
}
oh and for your "dynamically sized array", you need to look at std::vector<>
In C++ you can access characters in a string with [], just as if that string were an array. I suggest you read a line from cin into a string, iterate over the string with a for loop and check each character to see whether it is whitespace. Whenever you find a non-whitespace character, store it in your array.

Fastest way to read a file line by line with an arbitrary number of characters in each

Ok, I'm trying to figure out which way would be faster to read a text file that I'm working with. The contents of the file look like this
1982 3923 3542 4343
2344 3453 2
334 423423 32432 23423
They're basically just an arbitrary number of int numbers and I need to read line by line. Would it be better to use getline or the insertion (>>) operator? I, personally, think it would be a lot easier to implement by using the insertion operator but I don't know how I would make the program so that it reads all of the int numbers in the same line until it reaches the end. I was thinking of setting it up like the following:
ifstream input;
input.open("someFile.txt");
if (input) {
char* ch;
while (ch != '\n\)
getline(input, buffer, ' ')
The only problem is that I have to do a conversion to an int, then put each int in an array. My desired end goal is to produce a two-dimensional array where each line of int's is an array of int's. Any suggestions as to the best implementation is appreciated!
I would keep it real simple:
ifstream in(...);
string line;
while (getline(in, line)) {
istringstream line_in(line);
while (line_in) {
int val = 0;
if (line_in >> val) {
// Do something with val
}
}
// eol
}
You'd have to benchmark to get a correct answer.
The speed of the two functions is implementation defined. You might get different results on different compilers.
Fastest way to do it would probably to use a custom-made finite state machine. But those are about as unreadable as you get.
Produce correct code first. Then fine tune it if you need to later.