incrementing a word ahead in 2d array using pointers - c++

I'm writing a program to read a piece of text and put it in the correct grammar. All punctuation marks and newlines in the text are preceded by a ':'. One of the functions of my program is adding spaces between words that are read from the text file. However, I don't want it to do that all the time. Since ':.' marking the end of a sentence is a new word and not part of the previous word, it'll add a space between the last word and the period.
"... at the zoo ."
Instead of this:
"... at the zoo."
I'm trying to write a function that looks at the next word in the array to see if it's a colon.
Here's what I tried, among other things:
int isColon(char madLib[][256], int numWords)
{
numWords++;
char* k = madLib[numWords];
if (*k == ':')
{
cout << "{*k}";
return true;
}
else
return false;
}
Here is the output: {╠}
Without incrementing the counter (numWords), it displays the first letter without any problem.
However, I need it to look to the next word.
What do I do? Any suggestions?
Here is the code that actually displays the text:
int readFile(const char fileName[])
{
ifstream fin(fileName);
//if error when opening file, it will return true
if (fin.fail())
{
return true;
}
char madLib[256][256];
int numWords = 0;
while (fin >> madLib[numWords])
{
bool isSpace = true;
bool noPrint = false;
char* k = madLib[numWords];
while (*k)
{
if (*k == ':')
{
k++;
if (*k == '!')
cout << endl,
isSpace = false;
else if (*k == '.')
cout << ".";
else if (*k == ',')
cout << ", ";
else if (*k == '<')
cout << "\"",
isSpace = false;
else if (*k == '>')
cout << "\" ";
else
displayArray(madLib, numWords),
noPrint = true;
}
else
{
if (noPrint == false)
cout << *k;
}
k++;
}
if (isSpace == true && isColon(madLib, numWords) == false)
cout << " ";
noPrint = false;
numWords++;
}
fin.close();
return 0;
}

In my humble opinion, the main problem is that you are still working in complete C-Style mode. With all errors that result out of that.
You are using pointers and C-Style arrays. Recommendation: Do not and never use raw pointers for owned memory in C++.
Recommendation: Do not use C-style arrays in C++ (or only, if you know what your are doing).
Btw: You are using the wrong syntax for passing an 2d-array (which you should not use in the first place) to your functions. The array is decaying to a pointer.
You have huge risks for out of bounds problems using your magic numbers 256.
But your specific problem is resulting from a wrong design. You read a word, and then, before you have read the next word, you already check this none existing word.
Look at your code. You are doing fin >> something, then operate on this something, then you are calling your subfunction to check the next word. But this has not yet been read.
So, the recommendation is: At first read all words into your array, and then, afterwards, check your array content.
I hope this helps

Related

If statements that search to see if there are certain characters in them. c++

I am trying to write two if statements that will search for a certain character within a string or verify if a character is a specific letter.
One has to verify if the information being passed is an 's' or an 'h' and if its not, set it to an 's'.
the other has to verify if a name has a comma in it. The data is passed in Last, First format and if its missing the comma, it will set it to "unknown"
Help on getting started with this?
C++
I'm going to assume that you have a string defined and initialized called str.
string str = "something here";
The first if statement will look like
char &temp = str[0]; // temp is a reference to a character within the string
if(temp == 's'){
cout << "current character is s" << endl;
}
else if(temp == 'h'){
cout << "current character is h" << endl;
temp = 's';
}
The second requires a for-loop to check every character within the string.
bool found = false;
for(char item : str){
if(item == ','){
cout << "Found a comma" << endl;
found = true;
break;
}
}
if(found == false){
str = "Unknown";
}

jumping outside loop in a specific case

I am writing a code that, for one or several lines of strings, find if the overall input has only "cool" (it's first middle and last string are the same) lines, only "uncool" lines or a mix of both.
The problem I'm having is whenever I input an even number the while loop terminates. Debugging I found that, just before jumping out n gets value 0 but I don't understand how this would make the loop end.
This is the code:
#include <iostream>
using namespace std;
int main () {
// Bool has control if we have found a cool line/non-cool line
bool cool = false;
bool uncool = false;
int n; //lenght of input
while (cin >> n) {
if (cool and uncool) break; // we have found one of each so we know it is a mixed input
else if (n%2 == 0) uncool = true; // if the lenght is even there is no middle string
else {
// we are trying to see if the middle and last string are equal to the first
string comparing_string;
cin >> comparing_string;
string rest_of_sequence;
bool this_is_cool = true;
for (int i = n-2; i >= 0; i--) { // we input the rest of strings and compare them to the first
cin >> rest_of_sequence;
if ((i == n/2 or i == 0) and rest_of_sequence != comparing_string) this_is_cool = false;
}
if (this_is_cool) cool = true;
else uncool = true;
}
}
if (cool and uncool) cout << "both types" << endl;
else if (cool and not uncool) cout << "all cool" << endl;
else if (uncool and not cool) cout << "none cool" << endl;
}
Any help is appreciated! I'm currently in first year of uni and always open to recommended books/webpages/videos to continue learning :)
The problem was that I thought the program would just ignore input that wasn't an integer in the while loop, but it doesn't.
Now the code is correct:
else if (n%2 == 0) {// if the lenght is even there is no middle string
uncool = true;
string just_passing_input;
for (int i = n; i > 0; i--) cin >> just_passing_input;
}
Thanks for the helpful feedback, I shall now continue learning.

Unable to recognize colon in String C++

This snippet of code include the string I want to display and a helper method that's sole function is to display the string, entering the text on a new line when it finds a colon. However, it is only doing that for the last colon, not the other colons
string list = ":hello:chris:";
void displayEntry(){char *colon = ":";
for (int i = 0; i<list.length(); i++) {
char *letter = &list.at(i);
if (strcmp(letter, colon) != 0) {
cout << list[i];
continue;
}
cout << "\n";
}
cout << "\n";
}
It's because strcmp is not used for comparing single characters, it compares a whole string up until it finds a NUL character.
You don't actually need char* for any of this, just use char and ==.
if (list.at(i) != ':')

Palindrome tester has logic flaws

This is just a basic palindrome tester for my C++ class, and there appears to be issues.
I already know that I have two separate flaws in here somewhere. At least one, I strongly suspect, is a logic issue. The first problem is that it runs fine the first time through, but when the loop initiates, it doesn't ask for user input to put in a new line to test as a palindrome, it simply retests the old one. The second issue is, I assume, that it is testing spaces, which I base off the fact that it's giving 'hannah' back as good, but 'never even or odd' comes back bad. This one I just don't know how to fix.
#include <iostream>
#include <string>
using namespace std;
int main()
{
bool repeater = true;
do
{
string palindroneCheck;
bool palindronity = true;
cout << "Please enter a line to test for palindromity.\n";
getline(cin, palindroneCheck);
int stringSize = palindroneCheck.size();
int cutOff = stringSize/2;
for (int palindroneLength = 0; palindroneLength < cutOff; palindroneLength++)
{
if (palindroneCheck[palindroneLength] != palindroneCheck[stringSize - palindroneLength -1])
{palindronity = false;
break;}
}
if(palindronity == true)
cout << "Congratulations! This line is a palindrone!\n\n";
else
cout << "Sorry, but this is not a palindrone.\n\n";
palindroneCheck.clear();
char repeat;
cout << "Would you like to try another line? Y/N\n";
cin >> repeat;
if (repeat == "n" || repeat == "N")
repeater = false;
} while (repeater == true);
}
OK, you are right about the spaces. Your code will demand that spaces are in the same location like every other character.
The other bug seems more subtle: it's where you ask to repeat or not.
Why? Because it asks, you enter 'n' and then 'enter'
The cin >> repeat only reads the 'n', but not the 'enter'
so the next time you do `readline(cin,PalindromCheck)' it will read an empty string.
Try to write palindromCheck just after reading it. You'll see.
The reading issue of getline is solved by comments. For the whitespaces, you can tackle it by removing all the spaces inside string palindroneCheck,
std::string::iterator new_end = std::remove(palindroneCheck.begin(), palindroneCheck.end(), ' ');
std::string palindroneCheckWithoutSpaces(palindroneCheck.begin(), new_end);
Then you use palindroneCheckWithoutSpaces to do the Palindrone test.
int stringSize = palindroneCheckWithoutSpaces.size();
int cutOff = stringSize/2;
for (int palindroneLength = 0; palindroneLength < cutOff; palindroneLength++)
{
if (palindroneCheckWithoutSpaces[palindroneLength] != palindroneCheck[stringSize - palindroneLength -1])
{palindronity = false;
break;}
}
if(palindronity == true)
cout << "Congratulations! This line is a palindrone!\n\n";
else
cout << "Sorry, but this is not a palindrone.\n\n";
(you need header algorithm to use remove)
Update:
std::remove remove an element from the input range (this is defined by begin and end here) based on the value you passed in , here is the whitespace ' '. Then it return the new end of the changed range (since you delete something, the range becomes smaller). The new range starts with begin and ends with the returned value.
So the second line you create a new string based on the new range.

What is the end of line character when reading a file in using C++ get(char& c);?

My issue is I am trying my first attempt at writing a very basic lexical analyzer for ascii text files. so far, it reads and compares to my token list properly, however I am unable to grab the final token without a space or pressing enter. I've tried using the delimiter ^Z ASCII 26 as another selection before comparing the string to my token list. This failed to work. I've also tried moving the f->eof() check to below the comparison location to see if it will snag it then check the eof flag. I've had no luck. could anyone possibly enlighten me? The code is below for the read method. m_TokenList is just a vector of type string.
void CelestialAnalyzer::ReadInTokens(ifstream *f){
vector<string> statement;
vector<string> tokens;
string token;
char c;
do{
f->get(c); // Read in each character
if(f->eof())
break;
if(c == '\n' || c == ' ' || c == '^Z' || c == '\r'){ // 26 ASCII ^Z (end of file marker)
for(unsigned int i=0; i<m_TokenList.size(); i++){
if(!token.compare(m_TokenList[i])){
tokens.push_back(token);
token.clear();
}
}
} else {
token.push_back(c); // Add it to the token array
}
} while (true);
f->close();
for(unsigned int i=0; i<tokens.size(); i++){
cout << "Found Token: " << tokens[i].c_str() << endl;
}
}
The m_TokenList is initialized as
CelestialAnalyzer::CelestialAnalyzer(){
m_TokenList.push_back("KEY"); // Prints data
m_TokenList.push_back("GETINPUT"); // Grabs user data
m_TokenList.push_back("+"); // Addition/Concation
m_TokenList.push_back("-"); // Subtraction
m_TokenList.push_back("=="); // Equator
m_TokenList.push_back("="); // Assignment
m_TokenList.push_back(";"); // End statement
m_TokenList.push_back(" "); // Blank
m_TokenList.push_back("{"); // Open Grouping
m_TokenList.push_back("}"); // Close Grouping
m_TokenList.push_back("("); // Parameter opening
m_TokenList.push_back(")"); // Parameter closing
for(unsigned int i=48; i<=57; i++){
string s; s.push_back((char)i);
m_TokenList.push_back(s); s.clear();
}
}
A test file for reading is this simple example.
1 + 2 = KEY
It will register all but 'KEY' unless there is a space or a newline after it.
Why don't you just delete:
if(f->eof())
break;
and use
if(f->eof() || c == '\n' || c == ' ' || c == '^Z' || c == '\r'){
then break afterwards? That way, when you hit EOF, you will add whatever remaining token you have.
Alternately, you could just check if the token is nonempty after you break out of the loop, and add it in that case.
What about double 'new line'? As I know, in several messenger protocol regard \r\n\r\n with the end of the message. I think it's pretty reasonable. :)