I'm sorry this is a repeat question, but no solutions seem to work for my code.
This is for an assignment in school on reading from a file and copying the data to an array. An exception is thrown every time I try to edit the array "arr" in main.
Here's my code:
#include <iostream>
#include <fstream>
using namespace std;
struct Student {
string name;
float gpa;
int id;
};
void PrintStudents(Student arr[], int nstudents) {
for (int i = 0; i < nstudents; i++) {
cout << "Student name: " << arr[i].name << endl;
cout << "Student GPA: " << arr[i].gpa << endl;
cout << "Student ID: " << arr[i].id << endl;
}
}
int ReadStudents(string fname, Student arr[]) {
ifstream file;
file.open(fname);
int counter = 0;
string name_local;
float gpa_local;
int id_local;
int index = 0;
while (!file.eof()) {
if (counter == 0) {
file >> name_local;
}
else if (counter == 1) {
file >> gpa_local;
}
else if (counter == 2) {
file >> id_local;
}
counter++;
if (counter == 3) {
counter = 0;
Student newStudent = { name_local, gpa_local, id_local };
arr[index] = newStudent;
index++;
}
}
file.close();
return index;
}
void fillStudentArray(Student array[], int array_size) {
Student temp = { "", 0, 0 };
for (int i = 0; i < array_size; i++) {
array[i] = temp;
}
return;
}
int main() {
Student arr[128];
fillStudentArray(arr, 128); // exception thrown here??
cout << "Array filled." << endl;
cout << "Reading students" << endl;
int nstudents = ReadStudents("csci10.hw8.students.txt", arr);
PrintStudents(arr, nstudents);
return 0;
}
Thanks for any help! I'm totally stumped.
Edit: Woah, I left for a 30 minute coffee break and came back to a ton of answers! I'll try to respond to all of them.
Edit 2: Just got a solution! I was working in VS 2019, switched to old school terminal G++ and it worked! Thanks everyone for all the answers :)
You do not check the file was successfully opened. Try this:
ifstream file( fname );
if ( !file )
return -1;
You do not need local variables for reading. Read directly in your array elements:
file >> arr[index].name
ReadStudents ignores the size of the passed array: you might get in trouble if you read more than the allocated size (read this again). You might use std::vector, if allowed. Alternatively, pass the size, too – the same way you did for fill.
The way you are trying to read from file is overly complicated. Try a more c++ approach:
Define an extraction operator for Student:
std::istream& operator>>( std::istream& is, Student& s )
{
return is >> s.name >> s.gpa >> s.id;
}
Use it like you would use it for reading an integer:
file >> arr[ index ]
Alternatively you could use:
is >> arr[ index ].name >> arr[ index ].gpa >> arr[ index ].id
You will get something like this:
int ReadStudents( string fname, Student arr[]/*how large is the array?*/ )
{
ifstream file( fname );
if ( !file )
return -1;
int index = 0;
while ( file >> arr[ index ].name >> arr[ index ].gpa >> arr[ index ].id )
index++;
return index;
}
Explanation
If the stream does not get opened successfull, you get an endless loop. You never check if the reading operations are successfull. If they are not you never reach eof but keep incrementing index and write to array indices out of bounds. Also the counter is superfluos here.
Furthermore I would suggest to use a std::vector instead of an array and use push_back(). This makes sure, you don't write out of bounds.
(Possible) solution
This loop:
while (!file.eof()) {
if (counter == 0) {
file >> name_local;
}
else if (counter == 1) {
file >> gpa_local;
}
else if (counter == 2) {
file >> id_local;
}
counter++;
if (counter == 3) {
counter = 0;
Student newStudent = { name_local, gpa_local, id_local };
arr[index] = newStudent;
index++;
}
}
should be changed (with the function definition) to:
int ReadStudents(string fname, std::vector<Student> &vec)
{
// open stream, etc.
while (file >> name_local >> gpa_local >> id_local) {
Student newStudent = { name_local, gpa_local, id_local };
vec.push_back(newStudent);
}
// cleanup
}
To explain a bit further what the while (file >> name_local >> gpa_local >> id_local) does:
Since std::ifstream::operator>> returns a reference to the stream itself, you can chain those statements together.
The last reference gets implicitly converted to bool (or void* in c++11 or earlier) as seen here. This evaluates true if the last reading operations where successfull (so name_local, gpa_local and id_local now have valid values) and the stream is ready for IO-operations (so it didn't reach eof while reading). This implies that it's also checking if the stream was opened at all.
Once those conditions are met you can create a new element and push it into the vector.
Related
I am having an issue pertaining to receiving a segmentation fault which is coming from somewhere within one of these 3 portions of my code presumably. I have tried different debuggiing tactics of adding cout's to see which point the code is getting screwed up to no avail. Any and all help will greatly be appreciated.
void agency::readAllData()
{
int index;
char inputFile[100];
char delim = '}';
car * p_car;
p_car = m_inventory;
cout << "Input file name: " << endl ;
cin >> inputFile;
ifstream input (inputFile);
if (input)
{
input >> m_name >> m_zipcode;
for (index = 0; index < 5; index++)
{
int tempYear, tempAvailable;
float tempPrice;
char tempMake[256], tempModel[256], tempSensors[256], tempOwner[256];
input >> tempYear >> tempMake >> tempModel >> tempPrice;
input.getline(tempSensors, 256, delim);
input >> tempAvailable;
if (tempAvailable = 0);
{
input >> tempOwner;
}
p_car -> readCars(tempYear, tempMake, tempModel, tempPrice, tempSensors, tempAvailable, tempOwner);
p_car++;
}
}
else
{
cerr << "Input file cannot be opened" << endl;
return;
}
return;
}
void sensor::readSensors(char tempSensors[], sensor *sensor_ptr)
{
int index1;
int index2 = 0;
int index3 = 0;
for(index1 = 0; tempSensors[index2] != '\0'; index1++)
{
if (tempSensors[index1] = 'g')
{
gpsCount++;
}
else if (tempSensors[index1] = 'l')
{
lidarCount++;
}
else if (tempSensors[index1] = 'r')
{
radarCount++;
}
else if (tempSensors[index1] = 'c')
{
cameraCount++;
}
for(index2+=index1; tempSensors[index2] != ' '; index2++)
{
sensor_ptr->m_type[index3] = tempSensors[index2];
index3++;
}
sensor_ptr++;
}
return;
}
these functions exist among seperate files but interact in the order I have pasted them.
Your code does not compile, since it's neither a minimal example nor the complete set of code.
Without analyzing it deeply, this line seems fishy:
if (tempAvailable = 0);
It shouldn't compile at all and also you are assigning 0 to tempAvailable.
Especially with segfaults using debuggers is far better than doing print debugging.
I suggest looking for tutorials on gdb. Another option is trying to compile the code with address sanitization (just google for it).
I am trying to fill an array of structs from a given file but it doesn't seem to read anything.
/******************************************************************
* READ FILE
* This function opens the given file name and saves the info
* into an array.
******************************************************************/
int readFile(const std::string dataFile, AccessRecord accessRecordArray[], int &cou\
nt)
{
std::ifstream fin(dataFile.c_str());
if (fin.fail())
return -1;
std::string file;
while (!fin.eof())
{
fin >> file;
count++;
}
std::cout << count << std::endl;
for (int i = 0; i < count; i++)
{
fin >> accessRecordArray[i].fileName;
fin >> accessRecordArray[i].userName;
fin >> accessRecordArray[i].timeStamp;
}
fin.close();
return 0;
}
All this outputs is zero equal to the variable count. Can you help me see what I am missing?
So I am fairly new to coding and c++. So...sorry if this is something very obvious to some of you:
I am having a hard time getting this code to read the input stored in txt file for a second time. It works for the first time.
void readcode(ifstream& infile, int list[], int& length, bool& lenCodeOk)
{
int count;
lenCodeOk = true;
infile >> length; //get the length of the secret code
cout << "Length1 is "<<length<<endl;
if (length > MAX_CODE_SIZE)
{
lenCodeOk = false;
return;
}
//Get the secret code.
for (count = 0; count < length; count++)
{
infile >> list[count];
}
cout<<" Code recorded is: ";
for (count = 0; count < length; count++)
{
cout<<list[count]<<" "<<endl;
}
}
So the first integer in my txt file is the length of the sequence of integers. This function does everything it is supposed to. Reads the length correctly also stores everything in an array.
However when I call the below compareCode function after calling the readcode function, it comes out with a completely random/different length2 (that changes/goes one up everytime I call) and array elements.
void compareCode(ifstream& infile, ofstream& outfile, const int list[], int length)
{
int length2;
int digit;
bool codeOk;
int count;
codeOk = true;
infile >> length2;
cout<<"Length2 is "<<length<<endl;
if(length != length)
{
cout<< "The original code and its copy are not of the same length"<<endl;
return;
}
outfile << "Code Digit Code Digit Copy"<<endl;
for (count= 0; count<length; count++)
{
infile >> digit;
outfile<<setw(5)<<list[count]<<setw(17)<<digit;
if (digit != list[count])
{
outfile << " Code digits are not the same"<<endl;
codeOk = false;
}
else
{
outfile<<endl;
}
if (codeOk)
{
outfile<<"Message transmitted OK."<<endl;
}
else
{
outfile<<"Error in transmission. "<<"Retransmit!!"<<endl;
}
}
}
It seems like I am missing an important piece of information about passing fstream variables I would really appreciate if someone pointed me towards the right direction.
int main()
{
int codeArray[MAX_CODE_SIZE];//Array to store the secret code
int codeLength;// Variable to store the length of the code
int codeLength2;
bool lengthCodeOk;//Variable to indicate if the legth of the secret code is less than or equal to 250
ifstream incode;// Declare ifstream variable
ofstream outcode;//Declare ofstream variable
char inputFile[51];//Variable to store the name of the input file
char outputFile[51]; //Variable to store the name of the output file
cout<<"Enter the input file name: "<<endl;
cin>> inputFile;//makesure it is one word because ci.>>skips white space
cout<<endl;
incode.open(inputFile);
if(!incode)
{
cout<< "Cannot open the input file."<<endl;
return 1;
}
cout<< "Enter the output file name: " ;
cin>> outputFile;//Same deal, one word so cin>> can read
cout<<endl;
outcode.open(outputFile);
readcode(incode,codeArray,codeLength,lengthCodeOk);
if (lengthCodeOk)
{
compareCode(incode,outcode,codeArray,codeLength);
}
else
{
cout<<"Length of the secret code must be <= "<<MAX_CODE_SIZE<<endl;
}
incode.close();
outcode.close();
return 0;
}
this should go like this:
istream& readcode(istream& infile, std::vector<int>& list)
{
int length;
if (infile >> length) {
list.reserve(length);
for (int count = 0; count < length; count++)
{
int x;
if (infile >> x)
{
list.push_back(x);
} else {
break;
}
}
}
return infile;
}
ifstream file("somefile.txt");
if (file.good())
{
std::vector<int> a, b;
if (readcode(file, a).good())
{
file.seekg(0);
if (readcode(file, b).good())
{
cout << (a!=b? "code reading are different" : "code reading are same") << endl;
}
else
{
cerr << "failed read again code" << endl;
}
}
else
{
cerr << "failed read code" << endl;
}
}
I have a program that does three things. Asks you how many variables you wan't, ask you to input each variable, then stores it in a vector. I have put some code that checks if your input is correct, and if it isn't, re-loops the code asking for your variable. The problem I am having is that when you type anything in around the second variable, it asks you to try again infinitely.
For instance, if I typed these values into the input:
Variable amount: 5
Please input variable 1: 8
Please input variable 2: 8
ERROR, PLEASE ENTER ONLY VALID SYMBOLS
---------------------
Please input variable 2:
It would keep outputting ERROR, PLEASE ENTER ONLY VALID SYMBOLS over and over again no matter what you typed. The code is down below, and if you have a better name for this question please let me know. (I'm not really sure what to call this)
#include <iostream>
#include <cmath>
#include <string>
#include <algorithm>
#include <vector>
#include <sstream>
using namespace std;
int inputErrorMessage()
{
cout << "\n ERROR, PLEASE ENTER ONLY VALID SYMBOLS \n";
cout << "--------------------- \n";
return 0;
}
int main()
{
// Declare the variables, vectors, etc.
int varNum = 1;
int totVar = 0;
int choice = 0;
vector<int> userNums;
double input = 0;
string checktotVar = "";
string checkInput = "";
string sym = "";
bool valid = false;
stringstream sstotVar;
stringstream ssinput;
if (choice != 6) {
while (!valid) {
valid = true;
// Ask user for how many variables they want then record it
cout << "Variable amount: ";
getline(cin, checktotVar);
sstotVar << checktotVar;
sstotVar >> totVar;
if (sstotVar.fail() || totVar <= 0) {
inputErrorMessage();
valid = false;
sstotVar.clear();
sstotVar.ignore();
}
}
valid = false;
while (!valid) {
valid = true;
// Ask the user for each variable, then record it into the array
for (int i = 0; i < totVar; ++i) {
cout << "Please input variable " << varNum << ": ";
getline(cin, checkInput);
ssinput << checkInput;
ssinput >> input;
if (ssinput.fail()) {
inputErrorMessage();
valid = false;
ssinput.clear();
ssinput.ignore();
}
if (valid == true) {
userNums.push_back(input);
varNum++;
}
}
}
}
}
ssinput >> input;
reads the one thing in ssinput right to the end of the stream while leaving the read valid. The next time around
ssinput << checkInput;
can't write into the stream because the stream hit the stream's end. That means the read also fails and
if (ssinput.fail()) {
enters the body of the if where the program clears the error
ssinput.clear();
and then promptly reads off the end of the stream with
ssinput.ignore();
causing the error all over again.
Quickest solution:
Recreate
stringstream ssinput;
on each loop iteration. So
stringstream sstotVar;
//stringstream ssinput; gone from here
and
getline(cin, checkInput);
stringstream ssinput(checkInput); // and now tighter scope recreated each loop.
ssinput >> input;
Also by keeping the stream around without emptying it out it can get very., very big.
You can also simplify your logic around
while (!valid) {
and eliminate some repeated code by moving the read validation into it's own function
int getMeANumber(const std::string & message, int min)
that loops until it gets a number and then returns that number. For example:
int getMeANumber(const std::string & message, int min)
{
while (true)
{
cout << message;
string checktotVar;
getline(cin, checktotVar);
stringstream sstotVar(checktotVar);
int totVar;
sstotVar >> totVar;
if (!sstotVar || totVar <= min)
{
inputErrorMessage();
}
else
{
return totVar;
}
}
}
Now main is this itty-bitty tiny lil' thing.
int main()
{
int choice = 0;
vector<int> userNums;
if (choice != 6)
{
int totVar = getMeANumber("Variable amount: ", 0);
for (int i = 0; i < totVar; ++i)
{
stringstream varname;
varname << "Please input variable " << i+1 << ": ";
userNums.push_back(getMeANumber(varname.str(), numeric_limits<int>::min()));
// numeric_limits<int>::min requires #include <limits>
}
}
}
Here are the issues with this code.
In this part:
if (valid == true) {
userNums.push_back(input);
varNum++;
}
you forgot to add an ssinput.clear(). This will reset the stream state (clear the error flags), otherwise you cannot use it again. That is why it stops working at the second input.
In addition, even though this works, you are pushing back a variable that you declared as double into a vector of ints. That is bound to cause issues if this was intended to store double variables, instead of truncating them and storing them as ints.
It should be:
#include <iostream>
#include <cmath>
#include <string>
#include <algorithm>
#include <vector>
#include <sstream>
using namespace std;
int inputErrorMessage()
{
cout << "\n ERROR, PLEASE ENTER ONLY VALID SYMBOLS \n";
cout << "--------------------- \n";
return 0;
}
int main()
{
// Declare the variables, vectors, etc.
int varNum = 1;
int totVar = 0;
int choice = 0;
vector<int> userNums;
double input = 0;
string checktotVar = "";
string checkInput = "";
string sym = "";
bool valid = false;
stringstream sstotVar;
stringstream ssinput;
if (choice != 6) {
while (!valid) {
valid = true;
// Ask user for how many variables they want then record it
cout << "Variable amount: ";
getline(cin, checktotVar);
sstotVar << checktotVar;
sstotVar >> totVar;
if (sstotVar.fail() || totVar <= 0) {
inputErrorMessage();
valid = false;
sstotVar.clear();
sstotVar.ignore();
}
}
valid = false;
while (!valid) {
valid = true;
// Ask the user for each variable, then record it into the array
for (int i = 0; i < totVar; ++i) {
cout << "Please input variable " << varNum << ": ";
getline(cin, checkInput);
ssinput << checkInput;
ssinput >> input;
if (ssinput.fail()) {
inputErrorMessage();
valid = false;
}
if (valid == true) {
userNums.push_back(input);
varNum++;
}
ssinput.clear();
}
}
}
}
EDIT: You need to clear the stringstream on each iteration of the loop, otherwise you're not writing to an empty stream when you grab the next input from the user, which is what's causing the .fail() method to return true after the first iteration of the loop.
I've been working for days now on a machine simulator that reads instructions from a file. Just started working with C++ and im studying on vectors and parsing.
A sample file looks like this :
label0: left
right
if <1> goto label1
write 0
goto label2
label1: right
write 1
label2: halt
my code for the tape looks like this :
int main() {
int total_lines=0;
int RWH=0;
// Create a vector of strings
std::vector<string> Instruction;
// Create a string variable to hold each line read from the file.
string InstLine;
// Read through file and push onto our vector
vector<char> TapeVector; //declare tape
char temp;
cin >> noskipws;
cout << "Enter the input (end with ~):"; //initialize tape
while (cin >> temp && temp != '~') {
TapeVector.push_back(temp);
}
cout << "INPUT:";
for (int i=0;i<TapeVector.size();++i)
{
cout << TapeVector[i];
}
cout << endl;
// Open our file
ifstream InFile("input.txt",ifstream::in);
// If we can read/write great
if (InFile.good())
{
{
while(std::getline(InFile, InstLine))
Instruction.push_back(InstLine);
++total_lines;
}
}
else
cout << "Error reading file";
and here is for the parsing which I'm having problems:
while (std::getline(infile, line))
std::istringstream iss(line);
string a, b, c, d;
if (iss >> a >> b >> c >> d) //if 4 parameters
{
if (a=="if" && b==VectorTape[RWH])
{
counter=0; // counter will reset if b
}
;
}
else if (iss >> a >> b >> ) //if 2 parameters
{
if (a=="goto" //unfinished
}
else if (iss >> a >> b) //if 2 parameters
{
if (a=="goto" //unfinished
}
else if (iss >> a) //if 1 parameter
{
}
enter code here
on line 3 if label1 is detected, how do I jump and read the line with the label label1?
#include <iostream>
#include <fstream>
#include <map>
#include <string>
#include <vector>
#include <cstdlib>
#include "label.h"
using namespace std;
int main() {
int RWH=0;
std::vector<string> Instruction;
int total_lines=0;
vector<char> TapeVector; //declare tape
char temp;
cin >> noskipws;
cout << "Enter the input (end with ~):"; //initialize tape
while (cin >> temp && temp != '~')
{
TapeVector.push_back(temp);
}
cout << "INPUT:";
for (int j=0;j<TapeVector.size();++j)
{
cout << TapeVector[j];
}
cout << endl;
// Open our file
ifstream InFile("input.txt",ifstream::in);
// If we can read/write great
if (InFile.good())
{
{
string InstLine;
// Read through file and push onto our vector
while(std::getline(InFile, InstLine))
Instruction.push_back(InstLine);
++total_lines;
}
}
else
cout << "Error reading file";
vector<string> labels;
labels = lookupLabels(Instruction);
size_t i = 0;
while (i < Instruction.size())
{
istringstream iss(Instruction[i]);
// ...
string a,b,c,d;
iss >> a >> b >> c >> d;
if (a == "if")
{
if (b == TapeVector[RWH])
{
i = labels[d];
continue;
}
else
;
}
else if (a == "goto")
{
i=labels[b];
continue;
}
else if (a == "write")
{
b = TapeVector[RWH];
}
else if (a == "right")
{
++RWH;
}
else if (a == "left")
{
--RWH;
}
else if (a == "halt")
{
goto end;
}
else
{
continue;
}
++i;
} //end while
end:
for (int k=0;k<TapeVector.size();++k)
{
cout << TapeVector[k];
}
cout << endl;
InFile.close();
system("Pause");
return 0;
}
this is what i've done so far.. but there are plenty of errors i dont seem to understand.
51 C:\Users\JHONIN\Documents\THISIS\readtest 2.cpp no match for 'operator=' in 'labels = lookupLabels(const std::vector<std::string, std::allocator<std::string> >&)()'
55 C:\Users\JHONIN\Documents\THISIS\readtest 2.cpp variable `std::istringstream iss' has initializer but incomplete type
You cannot just jump forward in input file to unknown location.
You need to read entire program, store it in memory in a datastructure, at least annotated with labels, then jump within that structure, e.g.:
typedef map<string, size_t> Labels; // map label -> position in Instructions vector;
Labels lookupLabels(const vector<string>& instr) {
Labels ret;
for (size_t i = 0; i < instr.size(); ++i) {
const string& s = instr[i];
size_t colonpos = s.find(':');
if (colonpos != string::npos)
ret[s.substr(0, colonpos)] = i;
}
return ret;
}
now you can modify you "parsing with problems" in the same way - i.e. loop over lines in instructions vector, not in file. Once you hit a goto just pick another line number in labels and proceed with it, roughly like this
labels = lookupLabels(Instruction)
size_t i = 0;
while (i < Instruction.size()) {
istringstream iss(Instruction[i]);
// ...
iss >> a;
if (a == "goto") {
string label;
iss >> label;
i = labels[label];
continue;
}
++i;
}