C++ read text file into an array - c++

I'm trying to read a text file containing 20 names into an array of strings, and then print each string to the screen.
string monsters[20];
ifstream inData;
inData.open("names.txt");
for (int i=0;i<monsters->size();i++){
inData >> monsters[i];
cout << monsters[i] << endl;
}inData.close();
However when I run this code the loop is executed but nothing is read into the array. Where have I gone wrong?

Your for loop terminating condition is wrong:
i < monsters->size()
This will actually call size() on the first string in your array, since that is located at the first index. (monsters is equivalent to monsters[0]) Since it's empty by default, it returns 0, and the loop will never even run.
Remember, C++ does not have a size() operator for arrays. You should instead use the constant 20 for your terminating condition.
i < 20

monsters->size() is 0 at runtime. Change that line to for (int i=0;i<20;i++).
string monsters[20];
ifstream inData;
inData.open("names.txt");
for (int i=0;i<20;i++){
inData >> monsters[i];
cout << monsters[i] << endl;
}inData.close();

Related

Importing data into array in C++

I have a school assignment that I feel should be relatively simply, but I've spent like 5 hours on this part now and can't figure out what I need to do. I'm trying to import 3 integers from each line in a file into 3 different arrays. Each line has an ID number, store number, and quantity ordered. I want to store them in 3 arrays, where the same index would address the integers taken from the same line in the text file.
Recommendations I'm getting from various other places say to use stringstream or a vector, neither of which I have used before and I assume are not needed at this point in the class. My code currently is:
bool loadArrays(const char* fileName, long idArray[], int storeArray[], int qtyArray[], int &count, int maxCells)
{
count = 0;
ifstream fileIn;
fileIn.open("data.txt");
int x = 0;
while ((fileIn.get()) && (x < maxCells))
{
fileIn >> idArray[x] >> storeArray[x] >> qtyArray[x];
count++;
x++;
std::cout << idArray[x] << endl;
}
fileIn.close();
return true;
}
It loops through fine. I'm passing the count variable by reference and printing it out after I run this function it gives me 20. However the cout << idArray[x] line above just displays 0 each time like I'm not importing data correctly?
I'm probably importing the data wrong, which is fine for now, but even so shouldn't I get at least SOMETHING in idArray[0]? The first line of data.txt is '16724 27 134' so idArray[0] should = 16724, yes? I thought the >> will import integers until it meets whitespace, so the numbers being spaced apart like above means that line should go into 3 arrays per line right?
I should point out I'm taking this course online for now to see how I like programming and my teacher effectively doesn't speak english so I'm kind of on my own learning this for now.
You're reading into position x of your array, and printing out position x + 1 (x++ between those lines), which obviously is still empty.
Try to print before incrementing x, like so:
fileIn >> idArray[x] >> storeArray[x] >> qtyArray[x];
std::cout << idArray[x] << endl;
count++;
x++;
You're calling fileIn.get() without using its return value. The get() method extracts on character from the stream and returns it, it doesn't check whether there's still a character in the stream.
You should put the actual input operation inside the loop parameters as it is a much better way of checking if the stream performed a successful read:
while ((fileIn >> idArray[x] >> storeArray[x] >> qtyArray[x]) && (x < maxCells))
Also, as pointed out in the comments, you're incrementing x before printing idArray[x], so it will skip the first index. Put x++ after the insertion.

How to read cin into a dynamic array?

I'm trying to store a string entered by the user into a dynamic array. For "normal" arrays, you simply use the get function as I've used it here and everything works fine. However it seems that this doesn't work for dynamic arrays. When compiled, the program basically just skips the whole input segment and moves on to what comes after it. It doesn't even pause to let me type anything. So how do I store cin input into a dynamic array? Note: This is for a specific assignment, so please don't tell me to use a string or a non-dynamic array; I can't.
int arraySize;
cout << "Enter a maximum length for the string: ";
cin >> arraySize;
arraySize += 1;
char *inputPtr;
inputPtr = new char[arraySize];
cout << "Enter a string to be converted: ";
cin.get(inputPtr, arraySize);
When interacting with a human it is best to do so a line at a time.
The std::cin is line buffered so people type the answer followed by return. Thus you should adapt the same behavior in your code.
std::string arraySizeString;
std::getline(std::cin, arraySizeString); // Get user input.
// Convert input to type we want.
int arraySize;
std::stringstream arraySizeStream(arraySizeString)
if (! (arraySizeStream >> arraySize))
{
// Error user did not enter a number.
// You may want to check if the user entered more than just a number
throw 1;
}
// Now read the lines into a dynamically size array (or vector).
std::vector<std::string> data(arraySize);
for(int loop = 0; loop < arraySize; ++loop)
{
std::getline(std::cin, data[loop]);
}
The problem you are having is that operator>> when used on a string only reads a "white space" seporated word from the input (it leaves the '\n' on the input stream). So if you combine operator>> with other read operations you need to remember to take this fact into consideration and compensate.
This is not a problem of dynamic array. When you enter the size of array, the new line character is stored into a buffer. When it comes to the last line (cin.get), it is taken that new line character and exit the program.
Try
cin >> inputPtr;
instead of
cin.get(inputPtr, arraySize);

How to convert vector to string and convert back to vector

----------------- EDIT -----------------------
Based on juanchopanza's comment : I edit the title
Based on jrok's comment : I'm using ofstream to write, and ifstream to read.
I'm writing 2 programs, first program do the following tasks :
Has a vector of integers
convert it into array of string
write it in a file
The code of the first program :
vector<int> v = {10, 200, 3000, 40000};
int i;
stringstream sw;
string stringword;
cout << "Original vector = ";
for (i=0;i<v.size();i++)
{
cout << v.at(i) << " " ;
}
cout << endl;
for (i=0;i<v.size();i++)
{
sw << v[i];
}
stringword = sw.str();
cout << "Vector in array of string : "<< stringword << endl;
ofstream myfile;
myfile.open ("writtentext");
myfile << stringword;
myfile.close();
The output of the first program :
Original vector : 10 200 3000 40000
Vector in string : 10200300040000
Writing to File .....
second program will do the following tasks :
read the file
convert the array of string back into original vector
----------------- EDIT -----------------------
Now the writing and reading is fine, thanks to Shark and Jrok,I am using a comma as a separator. The output of first program :
Vector in string : 10,200,3000,40000,
Then I wrote the rest of 2nd program :
string stringword;
ifstream myfile;
myfile.open ("writtentext");
getline (myfile,stringword);
cout << "Read From File = " << stringword << endl;
cout << "Convert back to vector = " ;
for (int i=0;i<stringword.length();i++)
{
if (stringword.find(','))
{
int value;
istringstream (stringword) >> value;
v.push_back(value);
stringword.erase(0, stringword.find(','));
}
}
for (int j=0;j<v.size();i++)
{
cout << v.at(i) << " " ;
}
But it can only convert and push back the first element, the rest is erased. Here is the output :
Read From File = 10,200,3000,40000,
Convert back to vector = 10
What did I do wrong? Thanks
The easiest thing would be to insert a space character as a separator when you're writing, as that's the default separator for operator>>
sw << v[i] << ' ';
Now you can read back into an int variable directly, formatted stream input will do the conversion for you automatically. Use vector's push_back method to add values to it as you go.
Yes, this question is over a year old, and probably completely irrelevant to the original asker, but Google led me here so it might lead others here too.
When posting, please post a complete minimal working example, having to add #include and main and stuff is time better spent helping. It's also important because of your very problem.
Why your second code isn't working is all in this block
for (int i=0;i<stringword.length();i++)
{
if (stringword.find(','))
{
int value;
istringstream (stringword) >> value;
v.push_back(value);
stringword.erase(0, stringword.find(','));
}
}
istringstream (stringword) >> value interprets the data up to the comma as an integer, the first value, which is then stored.
stringword.find(',') gets you the 0-indexed position of the comma. A return value of 0 means that the character is the first character in the string, it does not tell you whether there is a comma in the string. In that case, the return value would be string::npos.
stringword.erase deletes that many characters from the start of the string. In this case, it deletes 10, making stringword ,200,3000,40000. This means that in the next iteration stringword.find(',') returns 0.
if (stringword.find(',')) does not behave as wished. if(0) casts the integer to a bool, where 0 is false and everything else is true. Therefore, it never enters the if-block again, as the next iterations will keep checking against this unchanged string.
And besides all that there's this:
for (int j=0;j<v.size();i++)
{
cout << v.at(i) << " " ;
}
it uses i. That was declared in a for loop, in a different scope.
The code you gave simply doesn't compile, even with the added main and includes. Heck, v isn't even defined in the second program.
It is however not enough, as the for condition stringword.length() is recalculated every loop. In this specific instance it works, because your integers get an extra digit each time, but let's say your input file is 1,2,3,4,:
The loop executes normally three times
The fourth time, stringword is 4, stringword.length() returns 2, but i is already valued 3, so i<stringword.length() is invalid, and the loop exits.
If you want to use the string's length as a condition, but edit the string during processing, store the value before editing. Even if you don't edit the string, this means less calls to length().
If you save length beforehand, in this new scenario that would be 8. However, after 4 loops string is already empty, and it executes the for loop some more times with no effect.
Instead, as we are editing the string to become empty, check for that.
All this together makes for radically different code altogether to make this work:
while (!stringword.empty())
{
int value;
istringstream (stringword) >> value;
v.push_back(value);
stringword.erase(0, stringword.find(',')+1);
}
for (int i = 0; i < v.size(); i++)
{
cout << v.at(i) << " " ;
}
A different way to solve this would have been to not try to find from the start, but from index i onwards, leaving a string of commas. But why stick to messy stuff if you can just do this.
And that's about it.

C++ file writing/reading

I'm trying to create an array, write array to the file and than display it. It seems to be working but i get just part of the output (first 3 elements) or i get values over boundaries.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
int arr[20];
int i;
for (i = 0; i < 5; i++)
{
cout << "Enter the value to the array: " << endl;
cin >> arr[i];
}
ofstream fl("numbers.txt");
if (!fl)
{
cout << "file could not be open for writing ! " <<endl;
}
for (i = 0; i < arr[i]; i++)
{
fl<<arr[i]<<endl;
}
fl.close();
ifstream file("numbers.txt");
if(!file)
{
cout << "Error reading from file ! " << endl;
}
while (!file.eof())
{
std::string inp;
getline(file,inp);
cout << inp << endl;
}
file.close();
return 0;
}
The terminating condition in the for loop is incorrect:
for(i=0;i<arr[i];i++)
If the user enters the following 5 ints:
1 0 4 5 6
the for loop will terminate at the second int, the 0, as 1 < 0 (which is what i<arr[i] would equate to) is false. The code has the potential to access beyond the bounds of the array, for input:
10 11 12 13 14
the for loop will iterate beyond the first 5 elements and start processing unitialised values in the array arr as it has not been initialised:
int arr[20];
which could result in out of bounds access on the array if the elements in arr happen to always be greater than i.
A simple fix:
for(i=0;i<5;i++)
Other points:
always check the result of I/O operations to ensure variables contain valid values:
if (!(cin >> arr[i]))
{
// Failed to read an int.
break;
}
the for loop must store the number of ints read into the arr, so the remainder of the code only processes values provided by the user. An alternative to using an array, with a fixed size, and a variable to indicate the number of populated elements is to use a std::vector<int> that would contain only valid ints (and can be queried for its size() or iterated using iterators).
while (!file.eof()) is not correct as the end of file flag will set only once a read attempted to read beyond the end of the file. Check the result of I/O operations immediately:
while (std::getline(file, inp))
{
}
its like hmjd said
for(i=0;i<arr[i];i++)
looks wrong
it should look like this
int size;
size=sizeof(your array);
for(i=0;i<size;i++)
Try this:
//for(i=0;i<arr[i];i++)
for(i=0;i<5;i++)
[EDITED]
I would initialize the array with 0 like this: int arr[20] = {0}; In this case you can use for example:
while ((arr[i] != 0 || i < sizeof(arr))
i<array[i]
It is wrong beacuse it comapres with the content of the array ,it does not check the size of array .

c++ read in array struct trouble

i am experiencing much trouble reading in files from input into an array struct. here is the code if someone can tell me what im doing wrong i can figure it out. the loop is supposed to be reading 2 strings, and 1 int, and skipping possible blank lines. but when i run it, it reads the first set and doesnt read nothing after that.
struct Instruments
{
string model;
string maker;
int year;
};
int main()
{
int size;
Instruments data[20];
int i =0;
ifstream fin;
fin.open("input.txt");
for (i=0; i<20; i++)
{
do{
getline(fin, data[size].model);
getline (fin, data[size].maker);
fin >> data[size].year;
size++;
}
while (data[size].model.length() > 0);
}
fin.close();
for(int i=0;i<size; i++)
{
cout << data[i].model << "model"<<endl;
cout << data[i].maker << "maker" << endl;
cout << data[i].year<< " year" << endl;
}
return 0;
}
There are multiple issues here:
Your first 'for' loop is using i as the loop counter but size as the array index.
After this call:
fin >> data[size].year
it will read to the end of the number and any whitespace that follows will form part of your next read, so if you are expecting to start the next record at the next line, do a blank getline() here too.
Aside from that.
Use vectors not arrays
Have a method to read from a stream into your struct, and if that succeeds, use push_back() to add it to your vector.
That doesn't necessarily mean you have to loop until the read fails, it may be that you know in advance how many you wish to read. But you should still do it this way.
size variable is not initialized. In C++, variables are not automatically initialized.
You must add:
int size = 0;
This is just a guess. In addition to the missing initialization of size, the following:
do{
.....
}
while (data[size].model.length() > 0);
looks also quite suspect to me: as soon as data[size].model has some content (which it does after the first read, this will evaluate to true and you probably have an infinite loop.
If you craft the for loop correctly, you don't need the do-while loop.