C++ Load Document Error. Trying to test - c++

I'm working on a project from class and it's a text analysis project. We're supposed to load a document into the program and basically read data from it. Ex: (word count, sentence count, etc.). For some reason, my first function isn't working correctly: my loadDocument function is supposed to load the document into the program.
Here is the code in main to call that function:
case 1: // Load Document
{
string inputLoc;
cout << "Please input the document name:" << endl;
cin >> docName;
myDocs[docCount].setName(docName);
myDocs[docCount].id = docCount;
cout << "Input Location: " << endl;
cin >> inputLoc;
myDocs[docCount].loadDocument(inputLoc);
docCount++;
break;
}
I have docName initialized outside of the case - before it.
Here is my loadDocument in side my Document class:
void Document::loadDocument(string name)
{
ifstream myFile(name);
int numOflines = 0;
string theLine;
char words;
while (myFile.get(words))
{
switch (words)
{
case '.':
numOflines++;
break;
case '?':
numOflines++;
break;
case '!':
numOflines++;
break;
}
}
lineCount = numOflines;
setLineCt(numOflines);
arr = new Line[lineCount];
myFile.close();
char theChar;
ifstream myFile2(name);
int key = 0;
if (myFile2.is_open())
{
for (id = 0; id < lineCount; id++)
{
while (theChar != '.' || theChar != '!' || theChar != '?')
{
myFile2 >> noskipws >> theChar;
theLine[key] = theChar;
key++;
}
myFile2 >> theChar;
arr[id].setStr(theLine);
}
}
}
I just wanted to know if my loadDocument has any evident bugs? For some reason, it's not actually loading a document into the program. For the input location, I typed in the exact file location of a text file that I want to input. For ex: C:\Users\Documents------. After I input that, my program just goes into an infinite loop.
Is my loadDocument doing what it's supposed to do? It's supposed to open a document and extract the number of sentences from it as well as number of words.
Also, am I testing it correctly by typing in that file location like that? I'm new to file input/output sorry.

Your while() loop is incorrect:
while (theChar != '.' || theChar != '!' || theChar != '?')
|| is not the right conditional operator here. If one condition is false, the two others will be true, thus leading to the infinite loop. You have to use &&:
while (theChar != '.' && theChar != '!' && theChar != '?')

Related

how do you define an exact case constant with a switch statement in c++

I'm learning C++ and I don't fully understand how case works in switch statements. I have the following code:
bool accept3() {
int tries = 1;
while (tries<4) {
std::cout<<"Do you want to proceed (y or n)?\n";
char answer = 0;
std::cin>>answer;
switch(answer) {
case 'y':
return true;
case 'n':
return false;
default:
std::cout<<"Sorry, but I don't understand that.\n";
tries ++;
}
}
std::cout << "I'll take that as a no.\n";
return false;
}
int main()
{
//accept();
//accept2();
accept3();
}
It works as expected when you input, 'y', 'n', or any other single character that does not meet the two defined cases.
When you input any string of characters that begins with n, it still takes that as the 'n' case. Why does it do this? How can I make this more exact, so that it ONLY accepts 'n' and not 'no', 'no way' or any other string beginning with 'n'.
Thank you!
This is tricky because if you input text with spaces into the terminal, like "d d d y", then you'll see the loop trigger 4 times in a row because "cin >> answer" breaks the line into separate inputs (this is called tokenization).
Here's code demonstrating how to properly parse an entire line of input as one menu command:
#include <iostream>
#include <string>
bool accept3() {
int tries = 1;
while (tries < 4) {
std::cout << "Do you want to proceed (y or n)?\n";
std::string answerStr;
std::getline(std::cin, answerStr);
char answer = '\0';
if (answerStr.size() == 1) {
answer = answerStr[0];
}
switch (answer) {
case 'y':
return true;
case 'n':
return false;
default:
std::cout << "Sorry, but I don't understand that.\n";
tries++;
}
}
std::cout << "I'll take that as a no.\n";
return false;
}
int main()
{
//accept();
//accept2();
accept3();
}
When you input any string of characters that begins with n, it still takes that as the 'n' case. Why does it do this?
Because you are asking cin to read a single char, so that is what it does. operator>>(char&) ignores leading whitespace, if any, and then reads 1 char. Any subsequent characters, if any, are left in the input buffer for later reads.
How can I make this more exact, so that it ONLY accepts 'n' and not 'no', 'no way' or any other string beginning with 'n'.
Use cin.getline() or std::getline() instead, and then compare the entire line, eg:
bool accept3() {
int tries = 1;
std::string answer;
do {
std::cout << "Do you want to proceed (y or n)?\n";
std::getline(std::cin >> std::ws, answer);
if (answer == "y")
return true;
if (answer == "n")
return false;
std::cout << "Sorry, but I don't understand that.\n";
++tries;
}
while (tries < 4);
std::cout << "I'll take that as a no.\n";
return false;
}

Delimiter matching simple program won't work

I have looked over this for hours it seems like. This program will compile, it just can't detect errors correctly. And for some reason it will work when I type in hey [) or hey {], etc. But it won't work for hey[) or hey{]. Obviously in all cases it should detect an error but for some reason the space after 'hey' makes a difference.
#include<iostream>
#include <stack>
using namespace std;
bool delimiterMatching(char *file){
stack<char> x;
int count = 0;
char ch, onTop, check;
while(ch != '\0'){
ch = file[count];
if (ch == '(' || ch == '[' || ch == '{')
x.push(ch);
else if (ch == ')' || ch == ']' || ch == '}') {
onTop == x.top();
x.pop();
if((ch==')' && onTop!='(') || (ch==']' && onTop!='[') || (ch=='}' &&
onTop!= '{'))
return false;
}
count++;
}
if (x.empty())
return true;
else
return false;
}
int main()
{
char *test = new char();
cout << "enter sentence: ";
cin >> test;
if (delimiterMatching(test))
cout << "success" << endl;
else
cout << "error" << endl;
return 1;
}
With cin >> test you don't get a whole sentence, but only a string until cin encounters whitespace. So if you type (hey ), thest would be (hey and the closing brace would only be read by the next >>, whereas (hey) would work as expected.
You have a second issue with your test allocation, which might be too short for reasonable input.
Change main() as follows:
char *test = new char[256]; // enough space. COnsider also string
cout << "enter sentence: ";
cin.getline(test, 256); // full line input.
...
You have also two nasty bugs in delimiterMatching().
First you use an uninitialized ch in your while condition. Either initialise ch to a non nul char, or use while (file[count]).
And did you notice onTop == x.top(); ? Shouldn't it be onTop = x.top();?

File input output confusion

I got conflicting advice with respect to how c++ operates with respect to reading past the eof.
The first group of people state that when the marker is reading past the eof area it reaches the eof and stops while the other group of people state it has to be in the exact position for it to be processed as reaching the eof. To make this clearer let me paste 2 blocks of code.
In this block of code, I am reading a number 1 from the file numbers.txt. They're no syntax errors and the only thing which I didn't paste over here is the code that opens the file.
while (!sample.eof())
{
char ch;
sample.get(ch);
sample.seekp(-1L, ios::cur);
sample >> initialnumber;
sample.seekp(2L, ios::cur);
cout << "OK";
}
In this program here I am reading the number 1 moving back one space making it start from the beginning processing it and then moving two spaces forward. The output for this is OK written only once.
#include < iostream>
#include < fstream>
#include< string>
using namespace std;
string conversion(int);
int conversion2(string);
int main()
{
string initialnumber;
fstream SAMPLE("numbers.txt", ios::in | ios::out);
ofstream sample2("numbers2.txt");
if (sample && sample2)
{
int number2;
string roman;
int number;
char ch;
while (!sample.eof()) {
sample.get(ch);
if (ch != '1' && ch != '2' && ch != '3' && ch != '4' && ch != '5' && ch != '6'
&& ch != '7' && ch != '8' && ch != '9') {
SAMPLE.seekg(-1L, ios::cur);
sample >> roman;
sample.seekg(2L, ios::cur);
sample2 << roman << " " << conversion2(roman) << endl;
int L = sample.tellp();
cout << L;
}
else {
sample.seekg(-1L, ios::cur);
sample >> number2;
sample2 << conversion(number2) << " " << number2 << endl;
sample.seekg(2L, ios::cur);
}
}
}
else
{
cout << "fail";
}
sample.close();
sample2.close();
}
Here it is repeating the number infinite number of times when it shouldn't be repeating it meaning it never reached the eof.
Please help me understand the logic of both programs.
Starting from C++11
Before doing anything else, seekg clears eofbit.
http://en.cppreference.com/w/cpp/io/basic_istream/seekg
Since seekg is always the last thing you call before checking .eof(), it will never be detected. The eofbit is set when a read operation hits the end of file. So, a read must be the last thing you do for it to work.

How do I allow different amounts of input in c++

Assume all variables exist (didnt bother declaring them all here)
if(input=='R') goto restart;
if(input=='X') exit(0);
if(input=='D') moveRight(edgeLength, board, score);
if(input=='S') moveDown(edgeLength,board, arrSize);
if(input=='A') moveLeft(edgeLength,board, arrSize);
if(input=='W') moveUp(edgeLength,arrSize,board);
if(input=='P')
{
cin>> number>>position;
board[position]=number;
}
This input is put into a loop, so the user is asked for input so long as this game is in play.
My goal is to allow for input such as
p 3 50
to place the number 50 at index position 3.
With my current code, I have to type 'p' press enter, then the next two numbers.
However, id like the program to detect 'p 3 50' (enter) in one go, as 'D'(enter) signifies moveRight.
I hope I'm being clear in my question.
cin >> input >> number >> position;
if(input=='R') goto restart;
else if(input=='X') exit(0);
else if(input=='D') moveRight(edgeLength, board, score);
else if(input=='S') moveDown(edgeLength,board, arrSize);
else if(input=='A') moveLeft(edgeLength,board, arrSize);
else if(input=='W') moveUp(edgeLength,arrSize,board);
else
{
//whatever statements for last condition;
}
If you want to capture all three input at once, you can get the input first, then execute the respective actions according to the received inputs.
Added: Using if or else-if depends on situation. From what I see here in your code snippet, else-if is better than if because you can only have one input type everytime. Once matching character is found, (example 'D'), it will stop reading the codes below (which should be the way as it is unnecessary to check the rest of the conditions whether input is 'S' or 'A' or 'W' anymore since you already got the input). Makes your code fun slightly faster too, by preventing unnecessary checking on the conditions.
Proof Of Concept:
//Example
void fncOne()
{
cout << "This is function one" << endl;
}
void fncTwo()
{
cout << "This is function two" << endl;
}
int main()
{
char input;
int number, position;
cin >> input >> number >> position;
if (input == 'A') fncOne();
else if (input == 'B') fncTwo();
}
Input: A 3 5
Output: This is function one
Well, first you're going to want to get user input as a string rather than individual types.
std::string input;
std::cin >> input;
then you'll want to parse that string based on how many words for key words/characters.
e.g.
std::vector<std::string> words;
std::stringstream stream(input); std::string temp;
while(stream >> temp)
words.push_back(temp);
if(words.size() == 3){
if(words[0][0] = 'p'){
int number = std::stoi(words[1]);
int position = std::stoi(words[2]);
board[position] = number;
}
else
... get input again ...
}
else if(words.size() > 1){
... get input again ...
}
else{
char c = words[0][0];
if(c == 'w')
moveUp(edgeLength,arrSize,board);
else if(c == 's')
moveDown(edgeLength,board, arrSize);
else if(c == 'a')
moveLeft(edgeLength,board, arrSize);
else if(c == 'd')
moveRight(edgeLength, board, score);
else if(c == 'x')
exit(0);
else if(c == 'r')
goto restart;
else
... get input again ...
}
Of course this is only one way if you want to type one string then press enter only once.

Reading parenthesis from fstream object. C++

I opened a .txt file with an ifstream object named input. If a new line starts with a "(" then it doesn't read it how I want it to. The expected output doesn't get printed, then it exits the loops. I want it to only jump out of the while loop when it reaches the end of the file. What am I doing wrong? My do while loop and my .txt file are below.
char c;
int i;
do
{
if(input.peek( ) == '(' || input.peek( ) == ')')
{
input >> c;
cout << c;
}else if(input.peek( ) == '+' || input.peek( ) == '-' || input.peek( ) == '*' || input.peek( ) == '/')
{
input >> c;
cout << c;
}else
{
input >> i;
cout << i;
}
}while(input && input.peek( ) != EOF);
Here is the .txt file, each on a separate line:
(3)
(3)
4
(5+7)-(5*3)
This is my output:
(3)3
So, I'm pretty certain that the problem is that input.peek() is returning a newline after ')' has been read. Then input >> i; doesn't read a number, and i remains the value it had before, so the output is 3. You could quickly try this by adding i = 42; before input >> i; - if the output becomes (3)42, then I'm right.
If I'm right, you will want to add a bit of code to handle isspace() or something similar.
May I also suggest that you do something like cpeek = input.peek();, before the first if, and then use if (cpeek == '(' || cpeek == ')')... etc.