Program is ignoring input - c++

I'm trying to write a simple brainfuck interpreter in C++. It works great so far, but it ignores the character input command (',').
The Interpreter:
#include <iostream>
#include <fstream>
#include <windows.h>
using namespace std;
#define SIZE 30000
void parse(const char* code);
int main(int argc, char* argv[])
{
ifstream file;
string line;
string buffer;
string filename;
cout << "Simple BrainFuck interpreter" << '\n';
cout << "Enter the name of the file to open: ";
cin >> filename;
cin.ignore();
file.open(filename.c_str());
if(!file.is_open())
{
cout << "ERROR opening file " << filename << '\n';
system("pause");
return -1;
}
while (getline(file, line)) buffer += line;
parse(buffer.c_str());
system("pause");
return 0;
}
void parse(const char* code)
{
char array[SIZE];
char* ptr = array;
char c;
int loop = 0;
unsigned int i = 0;
while(i++ < strlen(code))
{
switch(code[i])
{
case '>': ++ptr; break;
case '<': --ptr; break;
case '+': ++*ptr; break;
case '-': --*ptr; break;
case '.':
cout << *ptr;
break;
case ',':
cin >> *ptr;
break;
case '[':
if (*ptr == 0)
{
loop = 1;
while (loop > 0)
{
c = code[++i];
if (c == '[') loop ++;
else if (c == ']') loop --;
}
}
break;
case ']':
loop = 1;
while (loop > 0)
{
c = code[--i];
if (c == '[') loop --;
else if (c == ']') loop ++;
}
i --;
break;
}
}
cout << '\n';
}
The UtraSimple brainfuck code that breaks everything:
,.
Does anyone know what causes it to skip the input character?

I'd be looking at this for a start:
unsigned int i = 0;
while(i++ < strlen(code)) // increments i NOW !
{
switch(code[i]) // uses the incremented i.
The first character that will get processed there will be code[1], not code[0].
So the program ",." will first process . then \0 (end of string) hence there will be no input command , processed.
You can see this if you change the code as follows:
unsigned int i = 0;
while(i++ < strlen(code))
{
cout << "DEBUG [" << i << ":" << (int)code[i] << ":" << code[i] << "]\n";
switch(code[i])
and you'll see:
DEBUG [1:46:.]
DEBUG [2:0: ]
You need to hold off on incrementing i until after you're finished with it.

Related

How to add characters from a file that are not evenly spaced?

I'm taking C++ for the first time. And I'm a bit stuck on the final entry calculation.
5+6- 7 -8 + 9 + 10 - 11;
The question deliberately spaces things out of order and I don't know how to account for it. Any help on this would be amazing as I don't know what I'm missing. Thank you so much!
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
int val;
while (cin >> val)
{
string op;
while (cin >> op)
{
if (op == ";")
{
cout << val << endl;
break;
}
int num;
if (! (cin >> num)) {
cout << "a number is expected after '" << op << '\'' << endl;
return -1;
}
if (op == "+")
{
val += num;
}
else if (op == "-")
{
val -= num;
}
else {
cout <<"invalid operator '" << op << '\'' << endl;
return -1;
}
}
}
return 0;
}
You can do like following. See it working here:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
int val;
int num;
char op;
bool isNotStop(true);
cin>>val;
while (isNotStop)
{
cin.get(op);
//cout<<"Craracter is: ["<<op << "]"<<endl;
if(isspace(op)) continue;
switch(op)
{
case '+':
if (!(cin >> num))
{
cout << "a number is expected after '" << op << '\'' << endl;
return -1;
}
val += num;
break;
case '-':
if (!(cin >> num))
{
cout << "a number is expected after '" << op << '\'' << endl;
return -1;
}
val -= num;
break;
break;
case ';':
isNotStop = false;
break;
default:
{
cout <<"invalid operator '" << op << '\'' << endl;
return -1;
}
}
}
cout<<"Result: "<<val;
return 0;
}
I'm new here and this is my first attempt at answering a question. This might not be the best way to do it.
I think you should read the whole thing in a string with getline(cin, string), then go through the string with a for loop and get rid of all spaces. Then you can define a string stream from the resulting string and use it instead of cin.
It will look something like this:
string s1,s2;
getline(cin, s1);
for (int i = 0; i < s1.length(); i++) {
if (s1[i] != ' ')
s2 += s1[i];
}
stringstream ss;
ss << s2;
and from now on use ss instead of cin.
just make sure to include sstream and string headers.

Check whether a set of brackets consisting of parenthesis, square brackets, and Curly brackets are valid or not?

I have a small problem here: Our teacher asked us to write a program that checks whether parenthesis, square brackets, and Curly brackets are valid. eg: [[{{{(())}}}]] is a valid usage but ())), [[((]])) (the latter are interleaved here) are invalid.
Here is my try:
int main(){
string input;
cout << "Enter a text: "
cin >> input;
int nSquareBracketRight = count(s.begin(), s.end(), '[');
int nSquareBracketLeftt = count(s.begin(), s.end(), ']');
if(nSquareBracketRight != nSquareBracketLeft)
cout << "Invalid!" << endl;
else
cout << "Valid Usage!" << endl;
return 0;
}
It looks ok above but if the occurrences are equal but if a "Closing" one is in the smaller index then it is considered invalid eg: {}}{ Invalid.
Please help and thank you, guys!
This is the kind of situation that a stack is good for, such as std::stack, eg:
#include <iostream>
#include <string>
#include <stack>
using namespace std;
bool areBracketsValid(const string &input)
{
stack<char> stk;
for(string::size_type i = 0; i < input.size(); ++i)
{
char ch = input[i];
switch (ch)
{
case '(':
case '[':
case '{':
{
stk.push(ch);
break;
}
case ')':
case ']':
case '}':
{
if (stk.empty())
return false;
char openingCh = (ch == ')') ? '(' : (ch == ']') ? '[' : '{';
if (stk.top() != openingCh)
return false;
stk.pop();
break;
}
}
}
return stk.empty();
}
int main()
{
string input;
cout << "Enter a text: ";
cin >> input;
if (areBracketsValid(input))
cout << "Valid Usage!" << endl;
else
cout << "Invalid!" << endl;
return 0;
}
Live Demo
Using std::count is good but that is not what you need here in your program; You need something that is interested in the indexes moreover.
You can declare for each type of brackets a variable that holds the number of its occurrences
and inside a loop increment the target variable if it matches the tested character.
And right inside the loop after increment check whether the opening bracket number is smaller than the closing,
if so it is considered an invalid one eg: (()))(
As you can see above the number of opening and closing is OK but it is considered an invalid usage as the fact that a never a parenthesis begins with a closing one!
So break the loop signaling the invalid usage.
finally compare the number of opening and closing ones outside the loop, that is it because
inside a loop we can open n parenthesis so the checking is only after the loop ends to get the number of closing ones. eg:
(([[[{{{ cannot be checked inside the loop.
#include <iostream>
#include <string>
int main(){
std::string str;
std::cin >> str;
int nParR = 0, nParL = 0, nBrackR = 0,
nBrackL = 0, nCurlR = 0, nCurlL = 0;
for(auto i(0); i != str.length(); ++i){
switch(str[i]){
case '(':
nParR++;
break;
case ')':
nParL++;
break;
case '[':
nBrackR++;
break;
case ']':
nBrackL++;
break;
case '{':
nCurlR++;
break;
case '}':
nCurlL++;
break;
}
if(nParR < nParL || nBrackR < nBrackL ||
nCurlR < nCurlL){
std::cout << "Invalid usage!" << std::endl;
break;
}
}
if(nParR == nParL && nBrackR == nBrackL && nCurlR == nCurlL)
std::cout << "Valid usage!" << std::endl;
else
std::cout << "Invalid Usage!";
std::cout << std::endl;
return 0;
}
It is really easy to achieve: Let's say you have an input like this: ([{}]) it is considered correct isn't it? but ([)] is invalid.
In the correct one you can see in some point that element i is an opening bracket and element i + 1 is a closing bracket of the same family of brackets. Which is considered valid So the trick is to remove this subset brackets until the stack/vector is empty. If so then the whole input is correct otherwise is invalid.
Tip: inside a loop erase element i and element i + 1 if only and if element i is opening and element i + 1 is closing and element i and element i + 1 are of the same family eg: {}, [], ().
#include <iostream>
#include <string>
#include <vector>
int main(){
std::string str = "[({}{})]"; // valid
// std::string str = "["; // invalid
// std::string str = "[(])"; // invalid
// std::string str = "[({}{})]]"; // invalid
// std::string str = "[({}{}])"; // invalid
// std::string str = "{{}[{}]{(())}}"; // valid
// std::string str = "][(){}"; // invalid
std::vector<char> vecStr;
bool isDone = false;
for(auto i(0); i != str.length(); ++i)
vecStr.push_back(str[i]);
for(auto i(0); i != vecStr.size(); ++i)
std::cout << vecStr[i];
std::cout << std::endl;
for(auto i(0); i < str.length() / 2 && !isDone; ++i){
for(auto j(0) ; j < vecStr.size() - 1; ++j){
if(!vecStr.size()){
isDone = true;
break;
}
switch(vecStr[j]){
case '{':
if(vecStr[j + 1] == '}'){
vecStr.erase(&vecStr[j]);
vecStr.erase(&vecStr[j]);
}
break;
case '(':
if(vecStr[j + 1] == ')'){
vecStr.erase(&vecStr[j]);
vecStr.erase(&vecStr[j]);
}
break;
case '[':
if(vecStr[j + 1] == ']'){
vecStr.erase(&vecStr[j]);
vecStr.erase(&vecStr[j]);
}
break;
}
}
}
std::cout << "size: " << vecStr.size() << std::endl;
if(vecStr.size())
std::cout << "Invalid Input!" << std::endl;
else
std::cout << "valid Input!" << std::endl;
std::cout << std::endl;
return 0;
}
just switch uncommenting the input lines above and see the result. Or input it using std::cin.

convert variable string into char array c++

I found so incredibly many question posts of this sort - i'm speaking of "convert string to char array" - but none of those solutions actually work for me, trying to convert cin >> text into some char array textArray[1024] which I could then convert into a list cause I think it's easier to work with.
The Problem is: Spaces. Every time when there's a space in there, it just skips the following actions and punches me with my own error messeges.
It's for some encryptor (code down below).
If there's any easier way of doing this then let me know.
#include <iostream>
#include <string>
#include <fstream>
#include <list>
#include "encryptor.h"
using namespace std;
void encrypt()
{
string text;
char textArray[1024];
list<char> listText;
list<char>::iterator it;
int textSize;
string code;
bool fail = false;
string segment;
string fileName;
cout << "Now enter your text. (max 1024 chars)" << endl;
cin >> text;
textSize = text.size();
//string to char[]
//none of these work
strncpy(textArray, text.c_str(), sizeof(textArray));
textArray[sizeof(text) - 1] = 0;
strcpy_s(textArray, text.c_str());
for (int i = 0; i < text.length(); i++)
{
textArray[i] = text[i];
}
aText[text.length()] = '\0';
text.copy(textArray, text.length()+1);
//char[] to list
for(int i = 0; i < textSize; i++)
{
char *c = new char(textArray[i]);
listText.push_back(*c);
}
//Going through list
//for every char there's a special segment added to the string
for(it = listText.begin(); it != listText.end(); it++)
{
if(fail == true) break;
switch (*it)
{
case 'a':
case 'A':
{
segment = "XQ7";
} break;
{/*---*/} //I just let everything from b - z and 0 - 9 out for this post
case ' ':
{
segment = "Z 7";
} break;
case '.':
{
segment = "Z 8";
} break;
case ',':
{
segment = "Z 4";
} break;
default:
{
cout << "There's a special char this program doesn't understand. It is "
cout << *it << endl;
cout << "Do it again" << endl;
fail = true;
} break;
}
code = code + segment;
}
do
{
cout << "\n\nname of the file: ";
cin >> fileName;
if(fileName != "")
{
ofstream write;
write.open(fileName + ".txt");
write << code;
write.close();
} else {
cout << "Name shouldn't be empty!" << endl;
}
} while(fileName == "");
}
Your main issue is not in converting the string text to a character array but it is that you are not capturing the entire line from stdin.
The line cin >> text; will read from stdin until the first whitespace character has been met. That is why you are having issues with spaces. You are only reading characters into text up to the first whitespace character. Instead you need to use getline(). Replacing cin >> text; with getline(cin, text); will read in an entire line from stdin including any whitespace characters.
I've included a complete example to read in a line of text from stdin and convert it to a list of characters for you below. It completely skips the need to convert the string into a character array before converting it into a list.
#include <iostream>
#include <list>
#include <string>
using namespace std;
int main() {
string s;
list<char> text;
getline(cin, s);
for (string::iterator it = s.begin(); it != s.end(); ++it) {
text.push_back(*it);
}
// Verification
cout << "You entered " << text.size() << " characters\nThey were:\n";
for (list<char>::iterator it = text.begin(); it != text.end(); ++it) {
cout << *it;
}
cout << endl;
}

program crashes after when trying to load the csv file

me again. I have a problem. I tried to run this code and when I compile it, the compiler shows no errors, but after running it, the program crashes. HELP!!!
What the program should do:
It searches trough the data of deseases and desease codes of the WHO ( World Health Organisation). Two csv files are given (english and german version) and you have a choice to search in english and in german. I think that the program chrashes when it tries to load the char*-s from the csv file.
It's driving me crazy.
Here is also the link where you can find the whole project:
LINK
Code:
#include <iostream>
#include <stdlib.h>
#include <cstring>
#include <iomanip>
#include <fstream>
#include <list>
#include <algorithm>
using namespace std;
enum KEY {code, disease} key;
enum LANGUAGE {english, deutsch} language;
char* buffer;
struct lst
{
char *_code;
char *_disease;
};
streamsize _buffer = 10000;
bool isPartOf(char* word, char* sentence)
{
unsigned int i=0;
unsigned int j=0;
for(;i < strlen(sentence); i++)
{
if(sentence[i] == word[j])
{
j++;
}
}
if(strlen(word) == j)
return true;
else
return false;
}
void printList(list<lst>* LST)
{
for(list<lst>::iterator i= LST->begin(); i != LST->end(); i++)
{
cout << i->_code << '\t' << i->_disease << endl;
}
}
list<lst>* makeList(char* fileName)
{
int i,j;
fstream ICDcsv;
ICDcsv.open(fileName);
list<lst>* new_list = new list<lst>;
if(ICDcsv.is_open())
{
while(ICDcsv)
{
lst* x = new lst;
ICDcsv.getline(buffer,_buffer);
i = 0;
j = 0;
while (buffer[i] != ';')
{
x->_code[i] = buffer[i];
i++;
}
i++;
while (buffer[i] != ';')
{
x->_disease[j] = buffer[i];
i++;
j++;
}
(*new_list).push_back(*x);
}
ICDcsv.close();
}
else{cerr << "Error: file error" << endl;}
return new_list;
}
list<lst>* listSearch(list<lst> *LST,char* wrd,KEY key)
{
switch(key)
{
case code:
for(list<lst>::iterator i = LST->begin(); i != LST->end(); i++)
{
if(!isPartOf(wrd, ( *i )._code))
{
delete [] i->_code;
delete [] i->_disease;
delete &(*i);
}
} //i->
break;
case disease:
for(list<lst>::iterator i = LST->begin(); i != LST->end(); i++)
{
if(!isPartOf(wrd, ( *i )._disease))
{
delete [] i->_code;
delete [] i->_disease;
delete &(*i);
}
}
break;
}
return LST;
}
int main()
{
int choice;
int program_end=1;
char* _file;
char* Search;
cout << "World Health Institution (WHO)/Weltgesundheitsorganisation" << endl;
cout << "International Statistical Classification of Diseases and Related Healt Problems (ICD)/Internationale statistische Klassifikation der Krankheiten und verwandter Gesundheitsprobleme" << endl;
cout << "1 english" << endl;
cout << "2 deutsch" << endl;
cout << "your choice/Ihre Auswahl: ";
cin >> choice;
cin.clear();
if(choice == 1)
language = english;
else
language = deutsch;
switch (language)
{
case english:
{
_file = "care_icd10_en.csv";
break;
}
case deutsch:
{
_file = "care_icd10_de.csv";
break;
}
}
cout << "0 end/Ende" << endl;
cout << "1 search for ICD code (e.g. K52.9)/Suche nach ICD Kode (Beispiel K52.9)" << endl;
cout << "2 search for desease (e.g. Ebola)/Suche nach Krankheit (Beispiel Ebola)" << endl;
cout << "your choice/Ihre Auswahl: ";
cin >> program_end;
cin.clear();
switch(program_end)
{
case 0: break;
case 1:
key = code;
cout << "to search for ICD code/zu suchender ICD Kode: ";
break;
case 2:
key = disease;
cout << "to search for deseade/zu suchende Krankheit: ";
break;
}
if(program_end != 0)
{
cin >> Search;
list<lst>* test = makeList(_file);
list<lst>* test2 = listSearch(test,Search,key);
printList(test);
}
return 0;
}

Outputting Issue with File Conversion

This is a remake of a question I just asked a few minutes ago. Basically I want a line break to be displayed that is one less than the number of new line carriage returns. So if there are three new lines in a row, the line breaks should be two. Is there any way to do this?
while( infile.get( ch ) )
{
switch( ch )
{
case '\n':
outfile << "<br />";
break;
case '\t':
outfile << tab;
break;
case '&':
outfile << "&";
break;
case '<':
outfile << "<";
break;
case '>':
outfile << ">";
break;
case '"':
outfile << """;
break;
default:
outfile << ch;
break;
}
if( ch == '\n' )
{
inputLines++;
}
}
Sample output should look like this: https://gist.github.com/anonymous/b5a647913f83f796914c
This might work for you. Essentially it skips the first newline detected. If you have 3 newline input, you'll have 2 line breaks. Note that if you have only one newline, you'll just get a newline character (not a line break).
bool first_nl = true;
while( infile.get( ch ) )
{
switch( ch )
{
case '\n':
if ( first_nl ) {
outfile << "\n";
first_nl = false;
} else {
outfile << "<br />\n";
}
break;
case '\t':
outfile << tab;
break;
case '&':
outfile << "&";
break;
case '<':
outfile << "<";
break;
case '>':
outfile << ">";
break;
case '"':
outfile << """;
break;
default:
outfile << ch;
break;
}
if( ch == '\n' )
{
inputLines++;
} else {
first_nl = true;
}
}
Using this, you won't have to deal with any "peeking" at the next character.
To solve this problem, you will have to detect that you have "multiple of the same", which means building a statemachine of sorts.
A simple version, to cope only with what you are doing is to have a "peek-buffer";
#include <fstream>
#include <iostream>
using namespace std;
int buffer = 0;
int peek(ifstream &infile)
{
if (buffer) return buffer;
char ch;
if (!infile.get( ch ))
buffer = -1;
else
buffer = ch;
return buffer;
}
int get(ifstream &infile)
{
int ch = peek(infile);
buffer = 0;
cout << "ch = " << ch << endl;
return ch;
}
int main(int argc, char **argv)
{
ifstream infile(argv[1]);
ofstream outfile(argv[2]);
int ch;
while( (ch = get(infile)) != -1 )
{
int count = 0;
switch( ch )
{
case '\n':
while (peek(infile) == '\n')
{
count ++;
get(infile);
}
count--; // One less.
if (count <= 0) count = 1; // Assuming we want one output if there is only one.
for(int i = 0; i < count; i++)
{
outfile << "<br />";
}
break;
default:
outfile << (char)ch;
break;
}
}
}
I'm sure there are other clever ways to do this.