c++ read in array struct trouble - c++

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.

Related

Allocating memory for an array

I am trying to read numbers from a file and store then in an array using dynamic memory. When I try to print a member of the array, it is showing the address instead of the actual contents.
// CLASS METHOD IMPLEMENTATIONS
#include "DataHousing.h"
// CONSTRUCTORS
DataHousing::DataHousing() {
}
void DataHousing::FillArray() {
int tempIn = 0;
int count = 0;
// attempt to open the file with read permission
ifstream inputHandle("NumFile500.txt", ios::in);
// count how many numbers are in each file
if (inputHandle.is_open() == true) {
while (!inputHandle.eof()) {
inputHandle >> tempIn;
count++;
}
// allocate memory for array
int* pFileContents = new int[count];
// fill array
while (!inputHandle.eof()) {
for (int i = 0; i < count; i++) {
inputHandle >> pFileContents[i];
}
}
cout << &pFileContents[2];
}
else {
cout << "error";
}
}
This is my first time attempting anything like this and I am pretty stuck. What am i doing wrong here?
The unary & operator is to retrieve an address, so it is quite natural that it is showing the address.
To display the contents, remove the & in cout << &pFileContents[2]; and have it display the contents.
Also the counting part of your code
while (!inputHandle.eof()) {
inputHandle >> tempIn;
count++;
}
has two mistakes.
Firstly, you are incrementing count without the last reading was successful.
Secondly, you are trying to read from ifstream that is already reached to EOF.
You have to clear the EOF flag and seek to the beginning of the file like this:
In conclusion, the counting part should be:
while (inputHandle >> tempIn) {
count++;
}
inputHandle.clear();
inputHandle.seekg(0, ios_base::beg);
I see that you're trying to print the required value using:
cout << &pFileContents[2];
Since pFileContents is an array, pFileContents[2] will access the second element (value) of the same.
But since you've prepended & before the element, it is going to print the address of the second element of the array.
In order to print the value of the second element of the array, just use:
cout << pFileContents[2];
Notice the difference in the later code, we haven't used & just after cout <<

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++ read text file into an array

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();

how to exit after no input in a c++ program+

Hi guys i am new to c++, I just wrote this code to find min/max of a array of numbers.
I just want to know how can I make the no. of entries flexible(I mean the user should be able to enter as many entries as possible without specifying how many in the starting)
Here's the code, but its not working, can someone please help?
Thanks
code:
#include <iostream>
using namespace std;
int main(){
cout<<"Program to calculate max/min/second max\n";
int *A;
A=new int[5];
bool flag=false;
int x=0,i=0;
cout<<"Enter the numbers\n";
do{
cin>>x;
if(x=='\0'){
flag=true;
}
*(A+i)=x;
i++;
}
while(!flag);
for(int j=0;j<i;j++){
cout<<*(A+j)<<"\n";
}
return 0;
}
You are confused that pressing enter will just give you the null terminator. It will not. Depending on your platform it will give you a carriage return/line-feed (\r\n in Win, \n in *ix). The best way to do this is to just have them use a letter like 'q' for quit or a number like -1, and then compare on that.
Dynamic Memory Allocation is a bit of a tricky subject for a beginning programmer (in C and C++ in any case.) The easiest way is to have the user specify how many entries, but you don't want this.
Otherwise using the vector class over an array is probably a better (and easier to grapple with than directly using pointers.)
http://www.cplusplus.com/reference/stl/vector/ is a good place to start. Look at the syntax for creating the vector and the push_back() member function to accomplish your task.
Good Luck,
SegFaults McGee
You will have to use some sort of variable length datastructure and Vector is the best choice for this since you are working in C++. Therefore, instead of your fixed length array:
int *A;
A=new int[5];
use a vector like this:
std::vector<int> input;
And then to add values to this, use the following:
input.push_back(10);
There is an example on this page about using vectors.
mean the user should be able to enter as many entries as possible without specifying how many in the starting
With the above requirement and with the code you have, you can enter no more than 5 elements to an array.
do{
cin>>x;
if(x=='\0'){
flag=true;
}
*(A+i)=x;
i++;
}while(!flag);
Use std::vector instead for the requirement where it implicitly manages memory for you.
If you use
std::vector<int> a;
then the input becomes simply
while (std::cin >> x)
a.push_back(x);
Then the user can press ^D (Unix/Linux/etc) or ^Z (DOS/Win) when they've entered all the numbers, or use the program as in:
echo 1 4 22 | program
program < input_file
If you want to have an empty line denote the end of input, then with input validation:
std::string line;
while (getline(std::cin, line))
{
char c;
std::istringstream iss(line);
int x;
if (iss >> x)
{
a.push_back(x);
char c;
if (iss >> c)
{
std::cerr << "unexpected character '" << c << "' in line '" << line << "', terminating\n";
exit(EXIT_FAILURE);
}
}
else if (!iss.eof())
break; // empty line...
else
{
std::cerr << "unexpected characters in line '" << line << "', terminating\n";
exit(EXIT_FAILURE);
}
}