Basically, below is my main.cpp and when I try to run it with Qt's debugger, I get the "EXC_BAD_ACCESS" error ("Could not access memory") along with an arrow next to the first line of main (where it says Puzzle puzzle;). I thought it might be a problem with my Puzzle class, but when I moved that line elsewhere, I still got the bad access error with the debugger leaving the same yellow arrow by the first line of main. What's causing this error? My program ran fine half an hour ago, and then started throwing this error and I haven't even modified the code since it last worked. Also, this is one of my first projects in C/C++, so I'm not totally familiar with garbage collection. Could it be something to do with memory leaks or bad memory allocation?
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include "piece.h"
#include "puzzle.h"
#include "state.h"
using namespace std;
//function prototypes
Puzzle initPuzzle(string*, int);
int countWords(string);
//count the number of words (separated by white space) in a string
int countWords(string s){
int words = 0;
char * temp = new char[s.size() + 1];
copy(s.begin(), s.end(), temp);
temp[s.size()] = '\0';
temp = strtok (temp, " ");
while (temp != NULL){
words++;
temp = strtok (NULL, " ");
}
delete(temp);
return words;
}
//first checks validity of input
//if error(s), display appropriate message & exit program
//otherwise, returninstance of puzzle class from input file
//params: lines = array of strings, each of which is a line from input... size = # of elems in 'lines'
Puzzle initPuzzle(string * lines, int size){
//create instance of puzzle
//if bad piece found, throw it out
//if first piece (Z) is invalid, the next piece becomes goal piece
//if there are 0 valid pieces, display error to user and exit program
Puzzle ret;
int rows, cols;
if(size < 2){
//not enough lines for valid input
cout << "Error: Input too short" << endl << "Exiting program..." << endl;
exit(0);
}
istringstream iss(lines[0]);
if((iss >> rows >> cols) && countWords(lines[0])==2){
ret.rows=rows;
ret.cols=cols;
} else {
cout << "Error: Invalid first line" << endl << "Exiting program..." << endl;
exit(0);
}
if(rows < 1 || cols < 1){
cout << "Error: Invalid dimensions" << endl << "Exiting program..." << endl;
exit(0);
}
//now check the rest of the lines (ie the pieces)
for(int i=1; i<size; i++){
Piece newPiece;
int startRow, startCol, width, height;
char direction;
istringstream iss(lines[i]);
if(countWords(lines[i])==5 && (iss >> startRow >> startCol >> width >> height >> direction)){
//row is formatted correctly, create instance of Piece
newPiece = Piece(startRow, startCol, width, height, direction); //validate this piece later... if valid, add to pieces
} else {
//invalid row... entire input is invalid
cout << "Error: Invalid row(s)" << endl << "Exiting program..." << endl;
exit(0);
}
//now validate temporary piece...
//first make sure piece doesn't fall outside of grid
if(newPiece.startRow < 1 || newPiece.startCol < 1 || newPiece.startRow-1 > (rows - newPiece.height) ||
newPiece.startCol-1 > (cols - newPiece.width)){
//newPiece goes over the edge of the puzzle grid
cout << "Piece goes beyond grid... Throwing it out" << endl;
continue;
}
if(newPiece.direction != 'b' && newPiece.direction != 'h' && newPiece.direction != 'v' && newPiece.direction !='n'){
//newPiece has invalid direction
cout << "Piece has invalid direction... Throwing it out" << endl;
continue;
}
if(ret.pieceCount!=0 && ret.pieceOverlap(newPiece)){
//current piece overlaps existing one
cout << "Piece overlaps another piece... Throwing it out" << endl;
continue;
}
//if loop iteration reaches this point, piece is valid and can be added to puzzle
cout << "Piece is good!" << endl;
ret.addPiece(newPiece);
}
if(ret.pieceCount == 0){
//all pieces were invalid
cout << "Error: Puzzle has no pieces" << endl << "Exiting program..." << endl;
exit(0);
}
//now assign id's to the pieces...
for(int i=0; i<ret.pieceCount; i++){
if(i==0){
ret.pieces[i].id = 'Z';
} else {
ret.pieces[i].id = i;
}
}
return ret;
}
int main()
{
Puzzle puzzle; //single instance of puzzle class... initialized later after input & piece verification
string inputFile; //name of input file... provided by user
string line; //single line from input file
string * inputLines = new string[9000]; //array of lines from the input file
ifstream infile;
int size = -1; //size of inputLines array, initialized to -1
cout << "Enter name of input file: ";
cin >> inputFile;
infile.open(inputFile.c_str());
if(infile){
while(infile){
size++;
getline(infile,line);
inputLines[size] = line;
}
infile.close();
} else {
cout << "Error: Input file could not be opened" << endl << "Exiting program" << endl;
exit(0);
}
puzzle = initPuzzle(inputLines, size); //now check the input for validity, and if valid, initialize puzzle
return 0;
}
One mistake (two really) is within the function countWords():
temp is created using new[] but is deallocated use delete, it must be delete[] (new -> delete and new[] -> delete[] and avoid explicit dynamic memory management whenever possible)
the value of temp is not the value it was originally assigned which it must be when delete[]ing
Explicit dynamic memory allocation can be avoided completely by using a std::istringstream instead to count the words:
std::istringstream in(s);
std::string ignored;
while (in >> ignored) words++;
Other points:
prefer std::vector to explicit dynamic memory allocation management:
std::vector<std::string> inputLines; // and use 'push_back()'.
always check result of input operations immediately to ensure success:
if (cin >> inputFile)
{
ifstream infile(inputFile);
if (infile)
{
std::string line;
while (std::getline(infile, line)) lines.push_back(line);
}
}
Related
I have a text file with the following contents:
2
S 8
push 2 push 3 push 5 push 7 pop print push 6 print
S 4
pop print push 1 print
An assignment gives:
The first line of the input file means the number of test cases. For each test case, the first character means which container adapter (Stack or Queue) that you need to use Linked lists to implement. The correct output should be:
The values in the stack : 2 3 5
The values in the stack : 2 3 5 6
The values in the stack :
The values in the stack : 1
I've written some working functions for stack and queue struct, though I am working on the input of the stack function first.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
void push(int);
int pop();
void printStack();
struct Stack {
int s[100];
int top;
Stack() { top = -1; }
};
Stack st;
void push(int n) {
if (st.top == 99) {
cout << "Stack full" << endl;
}
else {
st.s[++st.top] = n;
}
}
int pop() {
if (st.top == -1) {
cout << "Stack is empty" << endl;
}
else {
return st.s[st.top--];
}
}
void printStack() {
cout << "Elements";
for (int i = 0;i <= st.top;i++) {
cout << st.s[i] << ' ';
}
cout << endl;
}
void clearStack() {
st.top = -1;
}
The main part of the code is giving me trouble. I want to read every token of the text file while keeping the line structure; e.g. being able to parse by order of line. However, I do not know the length of each line, only the number of lines. How may I read the file correctly and finish this assignment?
int main() {
std::ifstream file("input1.txt");
std::string item_name;
int numTestCases;
vector<string> file_content{};
while (std::getline(file, item_name))
{
//cout << item_name << "\n";
char str[252];
strcpy(str, item_name.c_str());
char* pch;
//cout << "str0:" << str[0] << "\n";
file_content.push_back(str);
}
cout << "printing file content:" << endl;
for (int i = 0;i < file_content.size(); i++) {
cout << file_content[i] << endl;
}
}
Okay, you basically have two distinct problems.
Read your input file so you know what actions to perform.
Implement both Stack and Queue.
So start by breaking them up. I looked at your stack code. Your problem says to use linked lists, which isn't what you're doing. Maybe that's just because you haven't gotten that far yet.
Code like this would give you the number of test cases.
std::string numCasesStr;
if (!getline(file, numCasesStr)) {
cout << "early end of file detected\n";
return;
}
int numCases = std::stoi(numCasesStr);
At this point, you can now do this:
for (int testCase = 0; testCase < numCases; ++testCase) {
std::string typeAndCountStr;
if (!getline(file, typeAndCountStr)) {
cout << "early end of file detected\n";
return;
}
char typeC = typeAndCountStr.at(0);
if (typeC == 'S') {
...
}
else if (typeC == 'Q') {
...
}
}
The harder part is parsing the next line. You're going to get input in a similar fashion, but then you have to break it into pieces. This is called tokenizing. Basically you split it at each space. What's useful is the find method on a string.
do {
size_t lastPos = 0;
size_t pos = str.find(' ', lastPos);
string thisArg;
if (pos != string::npos) {
thisArg = str.substr(lastPos, pos);
lastPos = pos + 1;
}
else {
thisArg = str.substr(lastPos);
}
// At this point, thisArg contains one argument. You still have more
// to do, but this is one way to split your string into pieces.
} while (lastPos != string::npos);
What I do with that is stuff the individual pieces into a std::vector<std::string> and now it's a lot easier to deal with. You can traverse the vector, looking at each string, and depending upon what it is, you know if you have to grab the next item in the list (like push 8 -- you get push and then you get the 8) or just use the current item.
Overall -- break the problem down into smaller pieces. For main:
Get the number of test cases
Loop from 0..testCaseCnt
Get the type of tests (stack or queue)
Get the next input
Split it into tokens broken at each space
Traverse the tokens and Do The Right Thing (tm).
Code for main to read inputs:
int main() {
int numTestCases;
vector<string> file_content{};
fstream ifs;
ifs.open("input2.txt");
if (!ifs.is_open()) {
cout << "Failed to open file.\n";
}
else {
ifs >> numTestCases;
char type;
int numberOps;
//ifs >> type;
cout << numTestCases;
for (int j = 0;j < numTestCases;j++) {
ifs >> type;
ifs >> numberOps;
if (type == 'S') {
Stack st;
clearStack();
for (int i = 0;i < numberOps;i++) {
string operation;
ifs >> operation;
if (operation == "push") {
int pushed;
ifs >> pushed;
push(pushed);
}
if (operation == "pop") {
pop();
}
if (operation == "print") {
printStack();
}
}
}
}
ifs.close();
}
}
I'm coding a simple custom shell in UNIX and I want to retrieve a specific command string from an array of commands that I loaded in from an external file. I know that my array successfully loaded the commands as all 7 of them are printing out, so I know they are there. However, when I enter in, say, 'mypwd' as input to be retrieved from the array, I get nothing back.
What I've done is I hard coded in the string I want to be read
if(command.compare("mypwd") == 0)
and
if(command.compare(0,5,"mypwd") == 0)
the program recognizes and executes my command, but when I try to call if from where it is stored in the array,
if(command.compare(command_array[0]) == 0)
and i've also tried
if(command.substr(0, 5).compare(command_array[0]) == 0)
my else statement error gets thrown.
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <iostream>
#include <fstream>
using namespace std;
// global variables
string username;
string password;
string command_array[7];
int COUNT = 0;
void mypwd();
void build_command();
int main()
{
int i=0,opcode=0;
int pid=0, status=0, background=0;
string command, parameters[3];
build_command();
int numberOfElements = COUNT;
cout << "........................\n" << endl;
cout << "List of commands loaded.\n" << endl;
cout << "........................\n" << endl;
//Print all commands.
for(int c = 0; c < numberOfElements; c++)
{
cout << command_array[c] << endl;
}
//Enter command you want to run
cout << "\Enter command: ";
cin >> command;
//Get the command.
if(command.compare(command_array[0]) == 0)
{
cout << "You've read the " << command << " command!";
}else
{
cout << "Command not read." << endl;
}
return 0;
}
void build_command()
{
ifstream COMMANDFILE;
string GETCOMMAND;
COMMANDFILE.open("commands.txt");
if(COMMANDFILE.is_open())
{
while(getline(COMMANDFILE, GETCOMMAND))
{
command_array[COUNT] = GETCOMMAND;
COUNT++;
}
}
COMMANDFILE.close();
}
void mypwd()
{
ofstream TO_CHANGE;
TO_CHANGE.open("users.txt");
if(TO_CHANGE.is_open())
{
cout << "Enter new password:";
cin >> password;
TO_CHANGE << username << ":" << password;
TO_CHANGE.close();
}
}
The output that is currently happening is
mypwd
mycopy
myps
mydf
mysearch
myhistory
mylogout
Enter command: mypwd
"Command not read."
The only other thing I could come up to solving this problem is maybe loading them into a string of vectors and having them compared that way using the std::vector library or possibly using strtok() but at this point, I'm mostly curious as to what I'm doing wrong in my code.
The only possibility is that there's whitespace at the end of your commands. Can you change:
cout << command_array[c] << endl;
For
cout << command_array[c] << " " << command_array[c].size() << endl;
One you confirm there's extra characters, then you'll have to think about stripping the extra whitespace.
I ended up fixing my problem by changing my comparison line to
if(command == command_array[0].substr(0,5))
instead of
if(command.compare(command_array[0]) == 0)
by setting the substr at the end returned the substring of the element at index [0] and thereby stripping off the extra whitespace in the string. It's not the optimal solution, but it solves my problem.
Sorry for the somewhat beginner question, but I've been at this for a couple of days and can't figure out a solution.
I'm basically reading integers from a file, these files should have a set amount of numbers, for the purpose of this question let us say 40. I can return an error fine when the file has less than or more than 40 integers. However, if there happens to be a non-numeric character in there, I'm struggling to figure out how to return an error.
This is what I'm currently doing:
int number = 0;
int counter = 0;
while(inputstream >> number)
{
// random stuff
counter++;
}
if (counter < 40)
return error;
It is at this point I'm a bit confused where to go. My while loop will terminate when the input stream is not an int, but there are two cases when this could happen, a non-integer character is in there, or the end of file has been reached. If we're at eof, my error message is fine and there were less than 40 integers. However, we could also be at less than 40 if it encountered a non-int somewhere. I want to be able to determine the difference between the two but struggling to figure out how to do this. Any help would be appreciated. Thanks!
you can input a line inside loop and try to convert it to integer so if the conversion fails means a non-integer and immediately break the loop returning a error telling that a non-integer found.
otherwise continue read until the end of file then check whether values are less or more 40 checking whether the loop reads all the content or broke because of non-integer value:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
enum ERRORFLAG{INIT, LESS_40, MORE_40, NON_INT}; // enumerate error
int main()
{
ifstream in("data.txt");
string sLine; // input one line for each read
int value; // value that will be assigned the return value of conversion
int count = 0; // counter for integer values
ERRORFLAG erFlag = INIT; // intialize the error flag
while(getline(in, sLine)) // iterate reading one line each time
{
if( !(value = atoi(sLine.c_str()) ) ) // conversion from string to integer so if the conversion failed else body will be executed
{
erFlag = NON_INT; // setting the error flag to non-int and break
break;
}
else
count++; // otherwise continue reading incrementing count
}
if(INIT == erFlag) // check whether the loop finishes successfully or a non-int caused it to break
{
if( count < 40) // checking whether number of ints less than 40
erFlag = LESS_40; //
else
if(count > 40) // or more than 40
erFlag = MORE_40;
}
// printing the error
switch(erFlag)
{
case LESS_40:
cout << "Error: less than 40 integers << endl";
break;
case MORE_40:
cout << "Error: More than 40 integers << endl";
break;
case NON_INT:
cout << "Error: non-intger found!" << endl;
break;
default:
cout << "Undefined Error" << endl;
}
in.close();
std::cout << std::endl;
return 0;
}
#include <iostream>
using namespace std;
int main() {
int count = 0;
int x;
istream& is = cin; // works with every class that inherits this one
while (is >> x) ++count;
if (is.eof()) {} // end of file reached
else {} // a bad value has been read
cout << "Read count " << count << '\n';
}
this program works fine: first read the file checking for a non-digits and non-white space characters and if you find break immediately setting the error flag.
keep in mind that white spaces like single and tab space will not be considered as invalid because they are used in your file as separators so any character other than digit or white space will break the loop returning an error.
if no error occurred (no invalid character found) and reaching the end of file then read again the file pushing the integer values into a vector which is a good idea without needing a counter then check the size of vector if it is less or more than 40 issuing an error otherwise print the content of vector:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
#include <vector>
enum ERRORFLAG{INIT, LESS_40, MORE_40, NON_INT};
int main()
{
ifstream in("data.txt");
char c;
string sLine;
int value;
vector<int> vec;
ERRORFLAG erFlag = INIT;
while(in >> c)
{
if(!isspace(c) && !isdigit(c))
{
erFlag = NON_INT;
break;
}
}
in.clear();
in.seekg(0, ios::beg); // jumping back the the beginning of the file moving the get pointer to the beginning
while(in >> value)
vec.push_back(value);
if(NON_INT == erFlag)
cout << "non-int found!" << endl;
else
{
if(vec.size() < 40)
cout << "les than 40 integers!" << endl;
else
if(vec.size() > 40)
cout << "more than 40 integers found!" << endl;
else
for(int i(0); i < vec.size(); i++)
cout << vec[i] << ", ";
}
std::cout << std::endl;
return 0;
}
This is my code.
#include <iostream>
using namespace std;
typedef struct
{
int polski;
int wf;
int matma;
}oceny;
int funkcja_liczaca(int suma, int ile_liczb, int ktory_przedmiot, oceny &temporary);
int main()
{
int suma = 0;
int temp[3];
int ile_liczb_zostalo_wprowadzonych = 0;
oceny database;
string teksty[3] = {"polski: ", "wf: ", "matma: "};
for (int i=0; i!=3; i++)
{
cout << teksty[i] << endl;
while(temp[i]!=0)
{
cin >> temp[i];
if(cin.good()) //floating point exception here. the code don't even step into this one.
{
{
suma = temp[i] + suma;
ile_liczb_zostalo_wprowadzonych++;
if(temp[i]==0){ile_liczb_zostalo_wprowadzonych--;}
}
}else cout << "error";
};
funkcja_liczaca(suma, ile_liczb_zostalo_wprowadzonych, i, database);
suma = 0;
ile_liczb_zostalo_wprowadzonych = 0;
}
cout << "output of struct members in main() \n";
cout << database.polski << endl;
cout << database.wf << endl;
cout << database.matma << endl;
return 0;
}
int funkcja_liczaca(int suma, int ile_liczb, int ktory_przedmiot, oceny &temporary)
{
if(ktory_przedmiot==0){temporary.polski=suma/ile_liczb;cout << temporary.polski << endl;}
if(ktory_przedmiot==1){temporary.wf=suma/ile_liczb;cout << temporary.wf << endl;}
if(ktory_przedmiot==2){temporary.matma=suma/ile_liczb;cout << temporary.matma << endl;}
}
It counts arithmetic average of inputed numbers untill user input 0 which ends loop. then the arithmetic average of thoose numbers is counted in the funkcja_liczaca() and it's saved into the members of struct oceny.
everything works fine but i want to implement something like "stream" check while inputing from keyboard to prevent inputing bad variables into integer type variable.
so inputing 'g' into temp[i] is causing floating point exception. the question is why? cin.good() and cin.fail() is not working.
When you want to deal with errors in the input stream, it's better to read the input line by line as a string and then attempt to extract your data from the string. If extraction of the data from the string is successful, proceed to process the data. Otherwise, attempt to read the next line of text. Here's the core logic for that.
while ( true )
{
cout << teksty[i] << endl;
std::string line;
if ( !getline(cin, line) )
{
// Problem reading a line of text.
// Exit.
exit(EXIT_FAILURE);
}
// Construct a istringstream object to extract the data.
std::istringstream istr(line);
if ( istr >> temp[i] )
{
// Extracting the number was successful.
// Add any additional checks as necessary.
// Break out of the while loop.
break.
}
// Bad input. Continue to the next iteration of the loop
// and read the next line of text.
}
This is part of a greater code for reading an input file word-for-word, then printing the words in reverse order. It uses a string array called words[] to store, word-by-word, the char strings from an input file earlier in the program:
//print to screen
for (int i = MAXSIZE; i >= 0; i--)
{
cout << words[i] << " ";
}
Test input file contents:
This is my test file. I hope this works.
Output is just "works. " repeating on and on.
Why is the i-- apparently never happening?
EDIT: Everything from my code. I'm on a bit of a time crunch here, to say the least. MAXSIZE=1024 part of lab prompt. Can't use vectors or reverse; seen that all over, but it's off limits for this lab. New to programming, so if you could refrain from being condescending, that'd be great. Just trying to get this to work. The reading input.txt and print to screen bit works fine. Output portion is utter fail and I don't know why. Can someone just tell me why instead of insulting me, thanks?
//Kristen Korz
//CIS 22A
//This program reads an input file and writes the words in reverse order to an output file.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
//create and link input...
ifstream inputFile;
inputFile.open("input.txt");
//...and output files
ofstream outputFile;
outputFile.open("output.txt");
//error message for file open fail
if (inputFile.fail())
cout << "Error opening the file.\n";
//constant for max size
const int MAXSIZE = 1024;
//string array and temporary-use string
string words[MAXSIZE];
string str; //note: variables will be used for output loops too
//read words from input file
for (int i = 0; (inputFile >> str) && (i < MAXSIZE); ++i)
{
words[i] = str;
//for showing in terminal if read correctly
cout << words[i] << " ";
}
inputFile.close();
cout << endl;
//something wrong with for loop resulting in i apparently not updating
for (int i = MAXSIZE; (outputFile << str) && (i >= 0); --i)
{
words[i] = str;
//for showing in terminal if written correctly
cout << words[i] << " ";
}
outputFile.close();
cout << endl;
system("pause");
return 0;
}
For output with i also printed, my cout statements in the for-loops say:
cout << words[i] << " " << i << " ";
Giving terminal output:
This 0 is 1 my 2 test 3 file. 4 I 5 hope 6 this 7 works. 8
works. 1023 works. 1022 works. 1021 (lots of repeats of works. followed by decrementing numbers) works. 3 works. 2 works. 1 works. 0
Your output loop does:
words[i] = str;
for every iteration. str still holds the value of the last string you input, so this sets every member of words to be the same string. Since your last input string was "works", this explains why you output "works" every time.
It should work better if you just remove that line. Also, start from MAXSIZE - 1. The valid indices of the array are 0 through MAXSIZE-1. Your out-of-bounds access causes undefined behaviour, although apparently in this instance it had no effect.
However if your input only has 8 words as you suggest, then outputting 1024 words will give you a lot of blank space. Consider starting the output from where i got up to, instead of MAXSIZE - 1.
At the part marked as not working (the second for loop), str is being read from but it is never changed to anything else in that loop, so it repeats the last word. i is being updated, the problem is that str is not being updated.
The other issue is that you are trying to access an element past the end of the array, as WhozCraig and Velthune discussed in their answers. You need to properly figure out what you want to do with words in your second for loop. This is key. Also, you need to store where the array you read in ends.
Viewing WhozCraig's link, if you have:
const int MAXSIZE = 1024;
string words[MAXSIZE];
for (int i = MAXSIZE; i >= 0; i--) {
cout << words[i] << " ";
}
You have a string that from 0..1023.
Accessing words[1024] is potentially dangerous.
For iterate correctly your string do:
for (int i = MAXSIZE - 1; i >= 0; --i) {
cout << words[i] << " ";
}
By the way, when you fill words, add a control:
for (int i = 0; (inputFile >> str) && (i < MAXSIZE); ++i)) {
if(str.size() <= MAXSIZE) {
words[i] = str;
}
}
update
Be sure that your string in file:
"This is my test file. I hope this works. "
doesn't end with a space. To be sure, test adding "EOF" to your string:
"This is my test file. I hope this works.EOF"
Other, do your loop in this way:
int i = 0;
while(inputFile.good() && i < MAXSIZE) {
std::string word << inputFile;
if(!word.empty())
words[i] = str;
//for showing in terminal if read correctly
cout << words[i] << " ";
}
The problem why you get a lot of "works" here is:
After this piece of codes:
//read words from input file
for (int i = 0; (inputFile >> str) && (i < MAXSIZE); ++i)
{
words[i] = str;
//for showing in terminal if read correctly
cout << words[i] << " ";
}
inputFile.close();
cout << endl;
//str = "works";
The values of variable str is works.
After that, you set every elements in words by str. So every elements in the words now are the same value works.
for (int i = MAXSIZE; (outputFile << str) && (i >= 0); --i)
{
words[i] = str;//=="works"
//for showing in terminal if written correctly
cout << words[i] << " ";
}
outputFile.close();
cout << endl;