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) != ':')
Related
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
I know there were a couple of other questions on this from a while back, but I looked over those and still couldn't figure it out. I'm trying to take user input in the form of a string, then loop through that string converting all of the uppercase to lowercase so that I can display it all in lowercase.
Where am I going wrong?
int main()
{
cout << "Enter Text: ";
string Text;
getline(cin, Text);
for(int i=0; i<Text.length(); i++)
{
if(islower(Text[i]) == false)
{
tolower(Text[i]);
i++;
}
Text[i] = Text[i];
}
cout << "Your text is: ";
cout << Text;
cout << "\n";
}
I'm very new to C++ and I'd be lying if I said I had much of an idea even where I was going wrong. Line 11, where the for loop is says that it's trying to compare two different signs, but I don't know what that means or if that's the source of my problem. Line 15 where the tolower() is says that it's 'ignoring return value of function declared with pure attribute' but I still don't know what that means either.
Please help.
A few points:
tolower returns the lowercase character if it exists ('A' becomes
'a', 'a' is unchanged, '9' is unchanged, etc.)
The line Text[i] = Text[i]; does not do anything, you want Text[i]
= tolower(Text[i]);
There is no need to check if each character is lowercase, tolower
will handle that for you
Simplified:
#include <iostream>
using namespace std;
int main() {
cout << "Enter Text: ";
string Text;
getline(cin, Text);
for (int i = 0; i < Text.length(); i++)
Text[i] = tolower(Text[i]);
cout << "Your text is: ";
cout << Text;
cout << "\n";
}
I'd suggest using the std library algorithm function transform to simplify and to make the code easier to read for you and others.
#include <iostream> //for cout and getline
#include <algorithm> //for transform
int main()
{
cout << "Enter Text: ";
string Text;
getline(cin, Text);
//This will iterate over each character [Text.begin()-Text.end()] and then
//replace it by a call to tolower with itself as a parameter
transform(Text.begin(), Text.end(), Text.begin(), ::tolower);
cout << "Your text is: ";
cout << Text;
cout << "\n";
}
EDIT:
As Remy pointed out to correct way of implenting this is by using a proxy lambda since
the behavior of std::tolower is undefined if the argument's value is
neither representable as unsigned char nor equal to EOF.
transform(Text.begin(), Text.end(), Text.begin(),
[](unsigned char c){ return std::tolower(c); });
I'd recommend looking at the ascii tables to see the codes for upper case and lower case characters.
http://www.asciitable.com/
bool islower(char in)
{
return !(char >= 'A' && char <= 'Z'); //we do this so if its a not an alphabet character we don't get false positives
}
char tolower(char in)
{
return char-'A' + 'a'; //essentially get its distance from the start of the
//alphabet and add this distance to the lowercase (only works on uppercase)
}
Its all just about working with the ascii values to get what you want since all characters are essentially integers.
For my code, I am trying to create a class with two functions that:
Display a cstring where each word is reversed
Display an entire cstring reversed
My two test sentences are "Hi There" and "To Be", so the output is:
erehT iH
eB oT
iH erehT
oT eB
Here is my code:
#include <iostream>
#include <cstring>
using namespace std;
class cStringType {
public:
char sentenceInput[80]; //Member variable
void reverse_sentence(); //Member function
void reverse_words(); //Member function
}; //Bottom of cStringType
int main()
{
cStringType sentence1, sentence2;
//Objects declared of cStringType
cout << "Please enter a sentence!\n" << endl;
cin.get(sentence1.sentenceInput, 79, '\n');
cin.ignore(80, '\n');
cout << "\nPlease enter another sentence!\n" << endl;
cin.get(sentence2.sentenceInput, 79, '\n');
cout << "\nThe first sentence reversed: ";
sentence1.reverse_sentence();
cout << endl;
cout << "The second sentence where each word is reversed: ";
sentence2.reverse_words();
cout << endl;
cout << endl;
cout << "The first sentence where each word is reversed: ";
sentence1.reverse_words();
cout << endl;
cout << "The second sentence reversed: ";
sentence2.reverse_sentence();
cout << endl;
return 0;
}
void cStringType::reverse_sentence()
{
char reverse_sentence;
//Reverse entire sentence using loop
for (int i = 0; i < strlen(sentenceInput) / 2; i++)
{
//Reverse the sentence using the length of the
//variable in the class
reverse_sentence = sentenceInput[i];
//First get the user input
//Set your variable equal to the variable in the class
sentenceInput[i] = sentenceInput[strlen(sentenceInput) - i - 1];
//Then reverse the characters and word order
//Starts from the last character in the array
//and goes backwards to 0
sentenceInput[strlen(sentenceInput) - i - 1] = reverse_sentence;
//Set the variable equal to the result
//sentenceInput is now the reverse of the user input in main
}
cout << sentenceInput << endl;
//Output of the new sentence
}
void cStringType::reverse_words()
{
int beginning, end, j = 0;
char reverse_words;
//Reverse each word separately using loop
for (int i = 0; i <= strlen(sentenceInput); i++)
//Get the length of the sentence in the class
{
if (sentenceInput[i] == ' ' || sentenceInput[i] == '\0')
//Check for spaces or null characters
//This allows only the letters of each word to be
//reversed, not the entire sentence
{
for (beginning = j, end = i - 1;
beginning < (i + j) / 2; beginning++, end--)
//j is the beginning of the array; increases
//i is the end of the array; decreases
{
reverse_words = sentenceInput[beginning];
//Set a variable equal to the first
//word in the original user input
sentenceInput[beginning] = sentenceInput[end];
//Set the first letter of a word equal to
//the last letter of a word
sentenceInput[end] = reverse_words;
//Set the result equal to the variable
//sentenceInput is now the user input where each
//word is reversed
}
}
j = i + 1;
}
cout << sentenceInput << endl;
//Output of the new sentence
}
When I try to run the code, the output becomes something like this:
Please enter a sentence!
Hi There
Please enter another sentence!
To Be
The first sentence reversed: erehT iH
The second sentence where each word is reversed: oT eB
The first sentence where each word is reversed: There Hi
The second sentence reversed: Be To
I tried fixing it, but to no avail. The output is never correct.
Is there some way to fix this issue? Or better yet, to simplify the code? I believe the issue is with the code in the function.
The main problem with your code is that it's using the same buffer for both transformations. In other words: you are reversing the words in the same string which you've already reversed entirely. So you need to have another copy of the original string to do these independently.
Regarding simplifying your code you need to define a function that would reverse a string given a pointer and size or begin and end pointers. Then you can use this function on your entire string or on every word you find while searching for a space character:
char *begin = sentenceInput; //points to the beginning of the word
char *end = sentenceInput + strlen(sentenceInput);
for (char *it = begin; it != end; ++it)
if (*it == ' ') {
reverse(begin, it);
begin = it + 1;
}
reverse(begin, end); //reverse the last word
The reverse function can be either std::reverse, which can be used in the above code and on the entire string as follows:
std::reverse(sentenceInput, sentenceInput + strlen(sentenceInput))
or you can create a similar function like this:
void reverse(char *begin, char *end)
{
--end; //point to the last character instead of one-past-last
while (begin < end)
std::swap(*begin++, *end--);
}
I would suggest using stack for it, it is a natural way of looking at it.
so
#include <stack>
and then the function would be like that
void cStringType::reverse_words()
{
int beginning, end, j = 0;
char reverse_words;
stack<char> lastWord;
//Reverse each word separately using loop
for (int i = 0; i <= strlen(sentenceInput); i++)
//Get the length of the sentence in the class
{
if (sentenceInput[i] == ' ' || sentenceInput[i] == '\0')
//Check for spaces or null characters
//This allows only the letters of each word to be
//reversed, not the entire sentence
{
//we want to print the last word that was parsed
while(!lastWord.empty())
{
//we print in the reverse order the word by taking off the stack char by char
cout<< lastWord.top();
lastWord.pop();
}
cout<<" ";
}
//if the letter is not space or end of string then push it on the stack
else
lastWord.push(sentenceInput[i]);
j = i + 1;
}
cout << sentenceInput << endl;
//Output of the new sentence
}
This question already has answers here:
How do I iterate over the words of a string?
(84 answers)
Closed 9 years ago.
I am writing a pig latin converter that takes a string as a command line argument and converts each word in the sentence into pig latin. I am trying to break up the string into individual words by finding spaces, but the output I get with the below code... honestly makes no sense.
It works for the first word, but then doesn't convert any subsequent words. So "test this string" becomes "esttay this ay string ay."
At this point we haven't covered vectors, so the solution has to be relatively simple.
Any ideas?
#include <iostream>
#include <string>
using namespace std;
void convertSentence(string sentence);
string pigLatinWord(string input);
bool isVowel(string input);
int main(int argc, char* argv[]) {
if(argc != 2) {
cout << "USAGE: " << argv[0] << " \"[sentence]\"" << endl;
} else {
string sentence(argv[1]);
convertSentence(sentence);
}
return 0;
}
void convertSentence(string sentence) {
string word = "", remainder = sentence, pigLatin = "";
for(int i = sentence.find(" ",0); i != string::npos; i = sentence.find(" ",i)) {
word = sentence.substr(0,i);
pigLatin += pigLatinWord(word) + " ";
sentence = sentence.erase(0,i);
i++;
}
pigLatin += pigLatinWord(sentence);
cout << pigLatin << endl;
}
string pigLatinWord(string input) {
string word = "";
// If the first letter is a vowel, simply add "yay" to the end of it.
if (isVowel(input)) {
word = input + "yay";
//If the first letter is a consonant, add the first letter to the end,
//delete the first letter, then add "ay." - Credit to Tyler Sorrels
//CString/String solution post on Piazza. I had issues working with
//substrings, and this ended up being easier to read.
//But I did add a check for words that start with two consonants
//to cover all cases.
} else {
input += input.at(0);
input = input.erase(0,1);
word = input + "ay";
}
return word;
}
// Checks if the first letter of the word is a vowel.
// Returns true if yes, false if no.
bool isVowel(string input) {
return ((input[0] == 'a') || (input[0] == 'e') || (input[0] == 'i') || (input[0] == 'o') || (input[0] == 'a'));
}
Two errors:
for(int ...; ; i = sentence.find(" ",i)) { // next space find should start from 0.
//..
//..
sentence = sentence.erase(0,i);// you should delete the current space found also.
i++;
}
Change this to:
for(int ...; ; i = sentence.find(" ",0)) {
//..
//..
sentence = sentence.erase(0,i+1);
i++;
}
Output:
esttay histay tringsay
The code is confused because you are trying to skip the word you have already found and you are trying to remove the word you have already found from sentence. Do one or the other.
Can I recommend that you use the POSIX regular expression library or PCRE, which should make swapping the first and last letters of words simple.
A regex such as \b(\w)(\w+)(\w)\b could be replaced by swapping the first and last collection groups
My assignment says:
---Rewrite the program by grouping the calculations into functions. In particular, you should introduce at least the following functions:
---A function named toLowerCase that takes a single character as an input parameter and returns a character. The returned value should be identical to the input unless the input is an upper-case letter, in which case the returned value should be the lower-case equivalent to that letter.
---Another function named toLowerCase, this one taking a string as an input parameter and returning a string. The returned string should be identical to the input except that all upper-case letters have been converted to lowercase.
----A function named readText that takes a string as an output parameter (no return value) and that reads multiple lines of input from cin until either hitting end-of-input or encountering an empty line. (Note: readText should not write anything to cout.)
----A function named countCharacter that takes two parameters as input and return an integer. The first input parameter will be a string and the second a character. The returned value should be the number of time that character occurs in the string (zero if the character occurs nowhere in the string). This function should work as described for all legal characters (i.e., even though this program will only use it to count lower-case letters, it should work for lower-case letters, upper-case letters, punctuation, etc.)
As you introduce each function, replace the code in main() by calls to your new functions as appropriate.
I keep getting error: expected primary-expression before char
#include<iomanip>
#include<iostream>
#include<string>
using namespace std;
void readText(string& text);
void toLowercase(string& text);
void countcharacter(string& text, char []);
char ToLowerCase();
int main (int argc, char** argv)
{
string userinput; //Initialize string name userinput
cout << "Enter text to be analyzed, ending with an empty line or end-of-input:" << endl;
readText(userinput); //Read text from user
cout << "You've entered: \n" << userinput << '\n'; // Read input, line by line, until end of input or an empty line
toLowercase(userinput); //Output user input and if upper-case, convert to lower-case
cout << "Lower case version of what you said: \n" << userinput << '\n';
countcharacter(userinput); //Count characters in userinput
ToLowerCase();
return 0;
}
void readText(string& text)
{
string line;
getline (cin, line);
while (cin && line != "")
{
text = text + line + "\n";
getline (cin, line);
}
/*for(std::string line; getline(std::cin, line) && !'\n' ; )
input += line + '\n'; */
}
void toLowercase(string& text)
{
const int ucLcOffset = 'a' - 'A';
for (int i = 0; i < text.size(); ++i)
{
char c = text[i];
if (c >= 'A' && c <= 'Z')
text[i] = text[i] + ucLcOffset;
}
}
void countcharacter(string& text, char c)
{
// Count and report on each alphabetic character
int totalCount = 0;
for (c = 'a'; c <= 'z'; ++c)
{
// Count how many times c occurs in the text
int charCount = 0;
for (int i = 0; i < text.size(); ++i)
{
if (text[i] == c)
++charCount;
}
// report on character c
cout << c << ":" << charCount << " " << flush;
if ((c - 'a') % 10 == 9)
cout << "\n";
totalCount = totalCount + charCount;
}
// How many characters are left over?
cout << "\nother:" << text.size() - totalCount << endl;
}
char ToLowerCase()
{
char c = 'A';
char Conversion;
const int ucLcOffset = 'a' - 'A';
if (c >= 'A' && c <= 'Z')
Conversion = c + ucLcOffset;
cout << "Your conversion for character A is: " << Conversion << '\n';
}
Line 28 error. 'countcharacter(userinput); //Count characters in userinput'
The line:
#inlcude<iostream>
Should be:
#include <iostream>
Syntax highlighting is your friend.
Also... countcharacter() takes two arguments:
void countcharacter(string& text, char []);
But you only provide one:
countcharacter(userinput);
#inlcude<iostream>
You spelt include wrong.
countcharacter(userinput); //Count characters in userinput
countcharacter() takes two parameters, not one.
It seems you want to count the occurrences of each lower case character ('a'-'z'). In this case you don't need to pass a second argument to countcharacter(). Change:
void countcharacter(string& text, char []);
to
void countcharacter(string& text);
and
void countcharacter(string& text, char []);
to
void countcharacter(string& text);
You will also have to declare char c in countcharacter().
It also seems you should change char ToLowerCase() to void ToLowerCase() as you don't seem to be returning anything.
I'm not a C++ guru, but the line
void countcharacter(string& text, char []);
Appears to be missing a parameter name.
Post the exact code you fed to your compiler. You wouldn't get "error: expected primary-expression before char" for what you posted, you'd get "error: invalid preprocessing directive #inlcude".
Copy-and-paste it, don't re-type it.
EDIT: fixed errror message