C++ Can't print certain words from Char array - c++

Not sure how to phrase the question, but I'm making a program for an assignment, which we're not allowed to use pre-existing libraries besides input/output. We also can only use primitive data-types. I have to read a text file with words, remove all punctuation from the word, and then store those words in a 2D array of characters.
This problem seems to be that when a word starts with a non-alphabetic character, the whole word doesn't output when using cout << stack[top] but when I output each individual character with cout << stack[top][i], it produces the expected output.
'stack' is a 2D array which contains characters to make up words.
'top' is a variable to represent the length of stack
Code:
#include <iostream>
#include <fstream>
using namespace std;
// Function Prototypes
void push(char word[]);
char formatCharacter(char letter);
bool isAlphabet(char letter);
char toLowercase(char letter);
// Global Variables
const int STACK_SIZE = 50000;
const int WORD_SIZE = 30;
char stack[STACK_SIZE][WORD_SIZE];
int top = 0;
int words = 0;
int wordCount[STACK_SIZE];
int main(){
// Local Variables
char filename[20];
ifstream fin;
char word[WORD_SIZE];
// Get file input
cerr << "Please enter the name of the input file: ";
cin >> filename;
// Open file
fin.open(filename);
// Print error if file doesn't open, then quit the program.
if (!fin) {
cerr << "Error opening file " << filename << ". Program will exit." << endl;
return 0;
}
// Read the file into the stack
while (fin >> word) {
push(word);
}
// Close file
fin.close();
}
void push(char word[]){
if (top == STACK_SIZE) return;
int i = 0;
int j = 0;
do {
if (isAlphabet(word[i])){
word[i] = formatCharacter(word[i]);
stack[top][i] = word[i];
cout << stack[top][i]; // Output fine
j++;
}
i++;
} while (word[i]);
wordCount[words] = j;
//cout << stack[top] << ": " << wordCount[words] << endl; // Output incorrect
cout << endl;
top++;
words++;
return;
}
bool isAlphabet(char letter){
if ((letter < 'A' || letter > 'Z') && (letter < 'a' || letter > 'z')){
return false;
}
else{
return true;
}
}
char formatCharacter(char letter){
if ((letter < 'A' || letter > 'Z') && (letter < 'a' || letter > 'z')){
letter = '\0';
}
else{
if (letter >= 'A' && letter <= 'Z'){
letter = toLowercase(letter);
}
}
return letter;
}
char toLowercase(char letter){
letter = letter + 32;
return letter;
}
isAlphabet() just checks if it's an alphabetic character
formatCharacter() removes any punctuation by replacing the character with '\0', and also changes uppercase to lowercase.
Input:
Jabberwocky
'Twas brillig, and the slithy toves
Did gyre and gimble in the wabe:
All mimsy were the borogoves,
And the mome raths outgrabe.
Output when using cout << stack[top][i]:
jabberwocky
twas
brillig
and
the
slithy
toves
did
gyre
and
gimble
in
the
wabe
all
mimsy
were
the
borogoves
and
the
mome
raths
outgrabe
Output when using cout << stack[top]:
jabberwocky: 11
: 4
brillig: 7
and: 3
the: 3
slithy: 6
toves: 5
did: 3
gyre: 4
and: 3
gimble: 6
in: 2
the: 3
wabe: 4
all: 3
mimsy: 5
were: 4
the: 3
borogoves: 9
and: 3
the: 3
mome: 4
raths: 5
outgrabe: 8
Notice the word 'twas' is missing. I'd rather not loop through each character of each word to get the output I need. I'd appreciate any advice, thanks!

The simplest fix is to change:
stack[top][i] = word[i];
To:
stack[top][j] = word[i];
^ j not i here
This will ensure that the 'Twas ends up as twas and not \0twas.
Also, formatCharacter() should call isAlphabet() rather than repeat the condition.

Related

Converting this program from 1 function to a modular, multi-function program?

I am very new to C++ and have a program which I included below.
The program I am working on reads text from an input file and counts the number of words and number of occurrences of each letter in the text and then prints the results. My program is working fine but the problem is all code is written in the main function and I need to break it up into a couple more functions to make the program modular, but I am unsure of how to go about doing this.
I am sure this is pretty simple but I'm not sure where to start. I was thinking of implementing two void functions, one for reading / interpreting what is read from the data file and another that displays the results; and then call them both in the main function, but I'm not sure what to take as arguments for those functions.
int main()
{
// Declaring variables
char c; // char that will store letters of alphabet found in the data file
int count[26] = {0}; // array that will store the # of occurences of each letter
int words = 1; // int that will store the # of words
string s; // declaring string found in data file
// Opening input file stream
ifstream in;
in.open("word_data.txt");
// Reading text from the data file
getline(in, s);
//cout << s << endl;
// If input file fails to open, displays an error message
if (in.fail())
{
cout << "Input file did not open correctly" << endl;
}
// For loop for interpreting what is read from the data file
for (int i = 0; i < s.length(); i++) {
// Increment word count if new line or space is found
if (s[i] == ' ' || s[i] == '\n')
words++;
//If upper case letter is found, convert to lower case.
if (s[i] >= 'A' && s[i] <= 'Z')
s[i] = (tolower(s[i]));
//If the letters are found, increment the counter for each letter.
if (s[i] >= 'a' && s[i] <= 'z')
count[s[i] - 97]++;
}
// Display the words count
cout << words << " words" << endl;
// Display the count of each letter
for (int i = 0; i < 26; i++) {
if (count[i] != 0) {
c = i + 97;
cout << count[i] << " " << c << endl;
}
}
// Always close opened files
in.close();
return 0;
}
I would rewrite it like:
class FileReader {
public:
FileReader() {
// Any init logic goes here...
}
~FileReader() {
// Always close opened files.
in.close();
}
void open(std::string &filePath) {
in.open(filePath);
}
std::string readLine() {
std::string s;
getline(in, s);
return s;
}
bool hasErrors() const { // remove const if you get compile-error here.
return in.fail();
}
private:
ifstream in;
};
class LetterCounter {
public:
void process(std::string &s) {
// For loop for interpreting what is read from the data file
for (int i = 0; i < s.length(); i++) {
// Increment word count if new line or space is found
if (s[i] == ' ' || s[i] == '\n')
words++;
//If upper case letter is found, convert to lower case.
if (s[i] >= 'A' && s[i] <= 'Z')
s[i] = (tolower(s[i]));
//If the letters are found, increment the counter for each letter.
if (s[i] >= 'a' && s[i] <= 'z')
count[s[i] - 97]++;
}
}
void logResult() {
char c; // char that will store letters of alphabet found in the data file.
// Display the words count
cout << words << " words" << endl;
// Display the count of each letter
for (int i = 0; i < 26; i++) {
if (count[i] != 0) {
c = i + 97;
cout << count[i] << " " << c << endl;
}
}
}
private:
int count[26] = {0}; // array that will store the # of occurences of each letter
int words = 1; // int that will store the # of words
};
int main()
{
// Opening input file stream.
FileReader reader;
reader.open("word_data.txt");
// Reading text from the data file.
std::string s = reader.readLine();
// If input file fails to open, displays an error message
if (reader.hasErrors()) {
cout << "Input file did not open correctly" << endl;
return -1;
}
LetterCounter counter;
counter.process(s);
// Display word and letter count.
counter.logResult();
return 0;
}
Note that I did write without testing (excuse any mistake),
but this should give you a general idea how it should be.

Why is c++ treating the space bar as null ('\0')?

my professor asked us to determine the number of vowels in userString without a call to the library.
I am using '\0' in a for loop to figure out when will the string the user input will come to an end because I don't know the exact size they are going to input for the string. I am a beginner programmer so please don't give me complcated answer! thanks.
I have for(int i = 0; userString[i] != '\0'; i++)
but the program is treating the space bar as a null character too so
I get a problem in the output,
if I have a space in the commend line is treats it as a null and terminates the proram
loop at the pictue of the 2 different outputs for refrence.
As you can see in output 1
When i have "MianJalal" I get 9 in the terminal but for
output 2 When I have "Mian Jalal" (with a space), it treats the space as null and gives me 4, I am aware that '\0' is space in the special chartacer in c++ but it's also null, how can I tell the program i mean null not space?
this is my code,
#include <iostream>
using namespace std;
int main()
{
int numOfVowels = 0;
int length = 0;
char userString[50]; // The string the user will input
cout << "Enter a sentence to find out how many vowels are in the sentence" << endl;
cin >> userString;
for(int i = 0; userString[i] != '\0'; i++) // '\0' means null in a string in c++; if a user doesn't use a index in a char string
{ // the program will know it's a null in syntax '\0'
if(userString[i] == 'A' or userString [i] == 'a' or userString[i] == 'i')
{
numOfVowels++;
}
length++;
}
cout << length << endl;
return 0;
}
The problem is that the operator >> uses the space as a delimiter. So when reading userString it stops at the first space. To avoid this a method could be to use istream::getline (char* s, streamsize n ) function, that reads the entire line up to the '\n' character, or the supplied size limit.
#include <iostream>
using namespace std;
int main()
{
int numOfVowels = 0;
int length = 0;
char userString[50]; // The string the user will input
cout << "Enter a sentence to find out how many vowels are in the sentence" << endl;
cin.getline(userString, sizeof(userString));
for(int i = 0; userString[i] != '\0'; i++) // '\0' means null in a string in c++; if a user doesn't use a index in a char string
{ // the program will know it's a null in syntax '\0'
if(userString[i] == 'A' or userString [i] == 'a' or userString[i] == 'i')
{
numOfVowels++;
}
length++;
}
cout << length << endl;
return 0;
}

Determining the amount of letters in each word of a string in C++

I'm new to c++ and coding in general and I ran into a bit of an issue in one of my assignments. I'm just looking for some input and hopefully an explanation on why my code isn't working.
I'm trying to get input from a user and use a cin.get() function to count all the characters in that string. I do this because I want to determine the letters in each word of the string. Now my issues are I can't get it to print the result correctly.
My question is: Why can't I get a result when I try to determine if my variable chr is a '\n' character? chr is the variable that hold the value of the current character being read by the cin.get() function) is a '\n'.
I want to be able to update the parameters (word1, word2.....) of my function countWordsByLegth() when the current value of chr is '\n' or in other words the end of the string.
The following code, for example, won't run and it's the only way I know how to update my parameter for a string that contains no spaces (one word strings):
if (counter == 5 && chr == '\n')
{
++word5;
counter =0;
}
Here's my code for reference. The function isWhitespace() just determines if the character is one of the following '\n' , '\r' , '\t'):
while (cin.get(chr) && chr != '\n')
{
counter++;
if (isWhitespace(chr))
{
--counter;
//test = true;
}
if (counter == 5 && chr == '\n')
{
++word5;
counter =0;
}
if (counter == 4 && chr =='\n')
{
++word4;
counter =0;
}
if (counter == 3 && chr =='\n')
{
++word3;
counter =0;
}
if (counter == 2 && chr == '\n')
{
++word2;
counter =0;
}
if (counter ==1 && chr == '\n')
{
++word1;
counter =0;
}
cout << counter << endl; // Test code {delete later}
}
cout << "This is the total of word5: " << word5 << endl;
}
You could use std::string.length() to get the amount of chars in a string.
The length() function returns the number of chars in the string.
#include <iostream>
#include <string>
int main()
{
std::string s;
s = "test";
std::cout << "The string has " << s.length() << " letters!";
}
http://www.cplusplus.com/reference/string/string/ here you can read about the different functions that you can use with strings.

Read digits from an int and counting them

Alright so I've been looking though Google and on forums for hours and can't seem to understand how to solve this problem.
I need to write a program that first determines if the number entered by the user is a base 5 number (in other words, a number that only has 0s, 1s, 2s, 3s, and 4s in it). Then, I have to count how many 0s, 1s, 2s, etc are in the number and display it to the user.
I've seen people saying I should convert int to a string and then using cin.get().
I noticed that I can't use cin.get() on a string, it needs to be a char.
I can only use a while loop for this assignment, no while... do loops.
Any help is appreciated!!
Here's what I have so far, obviously with all my mistakes in it:
//----------------------------------------------
// Assignment 3
// Question 1
// File name: q1.cpp
// Written by: Shawn Rousseau (ID: 7518455)
// For COMP 218 Section EC / Winter 2015
// Concordia University, Montreal, QC
//-----------------------------------------------
// The purpose of this program is to check if the
// number entered by the user is a base of 5
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
// Declaring variables
int number;
int zeros;
int ones;
int twos;
int threes;
int fours;
bool base5;
// Get data and calculate
cin >> number;
string numberString = to_string(number);
// Determine if the number is a base 5 number
while (cin.get(numberString) == 0 || cin.get(numberString) == 1 ||
cin.get(numberString) == 2 || cin.get(numberString) == 3 ||
cin.get(numberString) == 4)
base5 = true;
// Determine the number of each digits
zeros = 0;
ones = 0;
twos = 0;
threes = 0;
fours = 0;
return 0;
}
Several things you need to beware of:
One way to get a specific character from a std::string is by []. e.g.
std::string myString{"abcdefg"};
char myChar = myString[4]; // myChar == 'e'
cin.get(aString) is not trying to get data from aString. It continues to get data from stdin and store in aString. Once you have get the data and put into the string, you can simply manipulate the string itself.
a short piece of code that will count number of vowel in a string. If you can understand it, there should be no problem doing your work. (Haven't compiled, probably some typos)
std::string inputString;
std::cin >> inputString;
// you said you need a while loop.
// although it is easier to with for loop and iterator...
int i = 0;
int noOfVowels = 0;
while (i < inputString.length()) {
if (inputString[i] == 'a'
|| inputString[i] == 'e'
|| inputString[i] == 'i'
|| inputString[i] == 'o'
|| inputString[i] == 'u' ) {
++noOfVowels;
}
++i;
}
std::cout << "number of vowels : " << noOfVowels << std::endl;
Well you can try this approach. This will solve your needs I guess.
#include <iostream>
#include <string>
#include <sstream>
#include <conio.h>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
int number=0;
int zeros=0;
int ones=0;
int twos=0;
int threes=0;
int fours=0;
bool valid=true;;
int counter = 0;
cout<<"Enter the number: ";
cin >> number;
stringstream out;
out << number; //int to string
string numberString = out.str();
cout<<"\n\nNumber after string conversion : "<<numberString;
cout<<"\nPrinting this just to show that the conversion was successful\n\n\n";
while (counter < numberString.length())
{
if (numberString[counter] == '0')
zeros++;
else if(numberString[counter] == '1')
ones++;
else if(numberString[counter] == '2')
twos++;
else if(numberString[counter] == '3')
threes++;
else if(numberString[counter] == '4')
fours++;
else
valid=false;
counter++;
}
if(valid==true)
{
cout<<"\nZeros : "<<zeros;
cout<<"\nOnes : "<<ones;
cout<<"\nTwos : "<<twos;
cout<<"\nThrees : "<<threes;
cout<<"\nFours : "<<fours;
}
else
cout<<"\n\nInvalid data...base of 5 rule violated";
_getch();
return 0;
}
If you don't want to use std::string then use characters, first loop over the input from the user until ENTER is pressed.
char ch = 0;
while ((ch = cin.get()) != '\n')
{
...
}
For each character read, check if it is a digit (std::isdigit) and if it is in the range 0..4, if not quit and give some message of not being base 5
have an array of ints to keep track of the frequency of the digits
int freq[5] = {0,0,0,0,0};
after you have checked that the character is valid subtract the ascii value from the digit and use that as index in the array, increment that:
freq[ch - '0']++;
e.g.
char ch;
int freq[5] = {0};
while ((ch = cin.get()) != '\n')
{
cout << ch;
freq[ch-'0']++;
}
for (int i = 0; i < sizeof(freq)/sizeof(freq[0]); ++i)
{
cout << static_cast<char>(48+i) << ":" << freq[i] << endl;
}
Here's a useful function that counts digits:
// D returns the number of times 'd' appears as a digit of n.
// May not work for n = INT_MIN.
int D(int n, int d) {
// Special case if we're counting zeros of 0.
if (n == 0 && d == 0) return 1;
if (n < 0) n = -n;
int r = 0;
while (n) {
if (n % 10 == d) r++;
n /= 10;
}
return r;
}
In your code you can use this naively to solve the problem without any further loops.
if (D(n, 5) + D(n, 6) + D(n, 7) + D(n, 8) + D(n, 9) != 0) {
cout << "the number doesn't consist only of the digits 0..4."
}
cout << "0s: " << D(n, 0) << "\n";
cout << "1s: " << D(n, 1) << "\n";
cout << "2s: " << D(n, 2) << "\n";
cout << "3s: " << D(n, 3) << "\n";
cout << "4s: " << D(n, 4) << "\n";
You could also (or should also) use loops here to reduce the redundancy.

Encrypting a string with a stack

I received an assignment for my C++ class last week. I think some of you will find it interesting! I managed to get most of the code down but I'm stuck and cannot figure this out for the life of me... Below are the guidelines for the encrypting process I must put into code:
The message sender inputs a four letter word, CCCC, and another four letter word,
XXXX.
The message sender then inputs the message to be encrypted.
The program scans the message one char at a time and each char is pushed in a stack until
either the scanned character is in the word CCCC or the end of the message is
encountered.
When the scanned character is one of the chars in CCCC, print that char and continue
to print and pop the chars at the top of the stack until either the stack is empty or the
char at the top of the stack is one of the chars in XXXX. When the end of the
message is encountered, print the character at the top of the stack and continue to pop
and print from the top of the stack until the stack is empty.
Here is a hint: "GOOD" "LUCK", it "SOUNDS SIMPLE TO ME", or as
your program would say: "OSDNOT EEM LPMIS SU"
So that is the actual assignment.
What I am having trouble with is the last bit:
When the end of the
message is encountered, print the character at the top of the stack and continue to pop
and print from the top of the stack until the stack is empty.
now here is the code I have so far:
#include <string>
#include <iostream>
using namespace std;
class Stack
{
private:
char Chars[50];
int top;
public:
int push(char);
char pop();
bool isEmpty();
bool isFull();
Stack()
{
top = 0;
}
};
int main()
{
Stack theStack;
char word1[4];
char word2[4];
for(int i=0; i < 4; i++){
word1[i] = ' ';
word2[i] = ' ';
}
char message[500];
cout << "Please enter a 4 letter word: ";
cin >> word1;
while(word1[4] || !word1[3])
{
cout << "Word must be 4 chars long. Try again: ";
cin >> word1;
}
cout << "Please enter another 4 letter word: ";
cin >> word2;
while(word2[4] || !word2[3])
{
cout << "Word must be 4 chars long. Try again: ";
cin >> word2;
}
cout << "Please enter the phrase to be encrypted (50 chars max): ";
cin.ignore(1000, '\n');
cin.getline(message,500);
int length = strlen(message);
int count = 0;
char finalMsg[length];
//scanner
for(int i = 0; i < length; i++)
{
if(message[i] == word1[0] ||
message[i] == word1[1] ||
message[i] == word1[2] ||
message[i] == word1[3])
{
finalMsg[count] = message[i];
count++;
if(message[i-1] != word2[0] ||
message[i-1] != word2[1] ||
message[i-1] != word2[2] ||
message[i-1] != word2[3])
{
finalMsg[count] = message[i-1];
count++;
}
}
else
{
theStack.push(message[i]);
}
}
cout << finalMsg << endl;
return 0;
}
int Stack::push(char data)
{
Chars[top] = data;
top++;
return top;
}
char Stack::pop()
{
char ret = Chars[top-1];
top--;
return ret;
}
bool Stack::isEmpty()
{
if(top <= 0)
return true;
else return false;
}
bool Stack::isFull()
{
if(top >= 50)
return true;
else return false;
}
When compiled, the final output gives me "OSDNOT" which is in the example provided by my professor, so I know I'm heading down the right track.. Any help would be great, I don't even know where to begin to examine the code.
Here is the corrected code. You didn't code the algorithm right. I have commented the changes i have made in the code.
first of all, you didn't pop out the elements of the stack when you encountered a character present in CCCC while scanning. Also at the end of scanning, you didn't empty the stack. Include cstring instead of string. As pointed out in the comments, your declaration for word1 and word2 is incorrect.
char finalMsg[200];
//scanner
for(int i = 0; i < length; i++)
{
if(message[i] == word1[0] ||
message[i] == word1[1] ||
message[i] == word1[2] ||
message[i] == word1[3])
{
finalMsg[count] = message[i];
count++;
//pop out elements from the stack till it is empty or an character of XXXX is encountered
while(!theStack.isEmpty())
{
char tmp=theStack.pop();
if(tmp==word2[0] ||
tmp==word2[1] ||
tmp==word2[2] ||
tmp==word2[3])
{
theStack.push(tmp);
break;
}
finalMsg[count++]=tmp;
}
}
else
{
theStack.push(message[i]);
}
}
//empty the stack
while(!theStack.isEmpty())
{
finalMsg[count++]=theStack.pop();
}
finalMsg[count++]=0;
cout << finalMsg << endl;
PS: Better use std::stack and std::string.