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).
Related
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.
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;
}
I am trying to get a file location from the user. I've used the same getfile function on dozens of programs with no issues. For some strange reason this one always returns a cannot open file on the 1st try but then accepts it on the 2nd try. I have tried a cin.clear(); before the getline where I get the file location but that was no help. I cant figure out why this is acting so weird. Here is my getfile function:
void maze::getfile()
{
string filename;
char X;
cout << "please enter the location of the file you wish to input: " << endl;
getline(cin, filename);
cin.ignore(100, '\n');
inData.open(filename.c_str()); //opens file
while (!inData) //while the file is accesible
{
cout << "The file could not be opened.\nPlease try again: " << endl;
//error message for input validation
getline(cin, filename);
cin.ignore(100, '\n');
inData.open(filename.c_str());
}
for(int i = 1; i < 11; i++)
{
for(int u = 1; u < 11; u++)
{
inData >> X >>ws;
if(X == '1')
X = 219;
if(X == '0')
X = ' ';
floor[i][u] = X;
}
}
floor[0][0] = 201;
floor[0][11] = 187;
floor[11][0] = 200;
floor[11][11] = 188;
for(int i=1; i < 11; i++)
{
floor[0][i] = 205;
floor[11][i] = 205;
floor[i][0] = 186;
floor[i][11] = 186;
}
inData.close();
}
The only thing that happens before this is the main menu call. I set a variable choice = to a main menu function that returns a char, in this case '1'. Any ideas why it's failing on the first file input and not the 2nd try with the same file?
I'm sure you left a newline(maybe scanf(), cin>>, gets() left in) in the stream before you call std::getline first time, so that it gives you an empty string for the filename, after that, newline is eaten, so it works fine second time.
Hey, sorry if this is asked a lot but I have no idea what the problem here is.
In the C++ code below, I'm reading from a user defined input file and generating output. I've been writing it piece by piece and putting it together, compiling, testing, etc as I go to work out the bugs. This is a learning experience for me, first self-directed program I guess...
Anyways, when I run the code, the command prompt prints ONE line and goes unresponsive. I would say it has been caught in some kind of loop, but I believe that's impossible.
I think it might have something to do with the array I'm trying to declare, I wanted to make a dynamic string array but I found out that's difficult...
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cctype>
#include <string>
using namespace std;
int wordCount(string line)
{
int fpos, fpos2;
int count = 0;
fpos = line.find_first_not_of(' ');
line.erase(0, fpos);
while(line.size() > 0)
{
fpos = line.find_first_of(' ');
if(line.at(0) == '"')
{
line.erase(0, 1);
for(int i = 0; i <line.size(); i++)
if(line.at(i) == '"' && line.at(i-1) != '\\')
{
fpos2 = i;
break;
}
line.erase(0, fpos2 + 2);
}
else
line.erase(0, fpos + 1);
count++;
}
return count;
}
int main()
{
//Current line; Input file; Output file;
string currentline, fileName, outFileName;
ifstream fin;
ofstream fout;
cout << "Enter input file name: ";
getline(cin, fileName);
cout << "Enter output file name: ";
getline(cin, outFileName);
fin.open(fileName.c_str());
if (!fin.good()) throw "I/O error";
fout.open(outFileName.c_str());
if (!fout.good()) throw "I/O error";
getline(fin, currentline);
while (!currentline.empty())
{
int pos, pos1;
pos = currentline.find("//");
string postScript = currentline.substr(pos+2,-1);
pos = currentline.find_first_of(';');
string xline = currentline.substr(0,pos+1);
cout << xline << endl;
int size = wordCount(xline);
string *words;
words = (string *) malloc (size*sizeof(string));
words = new string[size];
pos = xline.find_first_not_of(' ');
xline.erase(0, pos);
for ( int i = 0; i < size; i++ )
{
pos = xline.find_first_of(' ');
if ( xline.at(0) == '"' )
{
xline.erase(0, 1);
for(int a = 0; a < xline.size(); a++) //This for loop finds the end of a quoted statement within the line.
if ( xline.at(a) == '"' && xline.at(a-1) != '\\' )
{
pos = a;
break;
}
words[i] = xline.substr(0,pos);
xline.erase(0,pos + 2);
}
else
{
words[i] = xline.substr(0,pos);
xline.erase(0,pos + 1);
}
cout << words[i] << endl;
}
cout << xline << endl << endl;
getline(fin, currentline);
}
return 0;
}
I would suggest you commenting out bits of code until it starts to work the way you expect (Usually the problematic bit will become obvious this way.) Once you figure out what is wrong you can ask a more specific question on StackOverflow.
You should use a debugger to investigate the program behavior.
To avoid single stepping the whole program, you can set breakpoints where you expect to passs the sequence. When a breakpoint is not hit you can use single stepping from the previous point. Additionally you can look at variables content.
It never finds the end quote:
if ( xline.at(a) == '"' && xline.at(a-1) != '\\' )
{
pos = a;
break;
}
Try this instead:
if (xline.at(a) == '"')
{
pos = a;
break;
}
You only need to escape " if its contained in a string literal, e.g. "There's a \" in this literal"