C++ code compiles, but gives wrong output....initialize function is wrong? - c++

I understand that declarations are missing, the code compiles fine however, the output does not output correctly... instead of a letter, I am getting ¿ instead. I believe the problem is in the initialize function, I just cannot seem to figure out what it is....
void printResult(ofstream& outFile, letterType letterList[], int listSize)
{
int i;
int sum = 0;
double Percentage = 0;
cout << "PRINT" << endl;
for (i = 0; i < 52; i++)
sum += letterList[i].count;
outFile << fixed << showpoint << setprecision(2) << endl;
outFile << "Letter Count Percentage of Occurrence" << endl;
for (i = 0; i < 52; i++)
{
outFile << " " << letterList[i].letter << " "
<< setw(5) << letterList[i].count;
if (sum > 0)
Percentage = static_cast<double>(letterList[i].count) /
static_cast<double>(sum) * 100;
/*
Calculates the number of Occurrence by dividing by the total number of
Letters in the document.
*/
outFile << setw(15) << Percentage << "%" << endl;
}
outFile << endl;
}
void openFile(ifstream& inFile, ofstream& outFile)
{
string inFileName;
string outFileName;
cout << "Enter the path and name of the input file (with extension): ";
getline(cin, inFileName);
inFile.open(inFileName);
cout << endl;
cout << "Your input file is " << inFileName << endl;
cout << endl;
cout << "Enter the path and name of the output file (with extension): ";
getline(cin, outFileName);
outFile.open(outFileName);
cout << endl;
cout << "The name of your output file is " << outFileName << endl;
cout << endl;
}
void initialize(letterType letterList[])
{
//Loop to initialize the array of structs; set count to zero
for(int i = 0; i < 26; i++)
{
//This segment sets the uppercase letters
letterList[i].letter = static_cast<char>('A' + i);
letterList[i].count = 0;
//This segment sets the lowercase letters
letterList[i + 26].letter = static_cast<char>('a' + i);
letterList[i + 26].count = 0;
}
}
void count(ifstream& inFile, letterType letterList[], int& totalBig, int& totalSmall)
{
cout << "COUNT WORKING" << endl;
char ch;
//read first character
inFile >> ch;
//Keep reading until end of file is reached
while( !inFile.eof() )
{
//If uppercase letter or lowercase letter is found, update data
if('A' <= ch && ch <= 'Z')
{
letterList[static_cast<int>(ch) - 65].count++;
}
else if('a' <= ch && ch <= 'z')
{
letterList[static_cast<int>(ch) - 97].count++;
}
//read the next character
inFile >> ch;
} //end while
} //end function
===============
driver code
int main()
{
struct letterType letterList[52]; //stores the 52 char we are going to track stats on
int totalBig = 0; //variable to store the total number of uppercase
int totalSmall = 0; //variable to store the total number of lowercase
ifstream inFile;
//defines the file pointer for the text document
ofstream outFile;
//the file pointer for the output file
cout << "MAIN WORKING" << endl;
openFile(inFile, outFile);
//allow the user to specify a file for reading and outputting the stats
/*if (!inFile || !outFile)
{
cout << "***ERROR*** /n No such file found" << endl;
return 1;
}
else
return 1;
*///Check if the files are valid
initialize(&letterList[52]);
//initalizes the letter A-Z, and a-z */
count(inFile, &letterList[52], totalBig, totalSmall);
// counts the letters
printResult(outFile, letterList, 52);
//writes out the stats
//Close files
inFile.close();
outFile.close();
return 0;
}
=====================
Entire Count function
void count(ifstream& inFile, letterType letterList[], int& totalBig, int& totalSmall)
{
cout << "COUNT WORKING" << endl;
char ch;
//read first character
inFile >> ch;
//Keep reading until end of file is reached
while( !inFile.eof() )
{
//If uppercase letter or lowercase letter is found, update data
if('A' >= ch && ch <= 'Z')
{
letterList[ch - 'A'].count++;
}
else if('a' >= ch && ch <= 'z')
{
letterList[(ch - 'a') + 26].count++;
}
//read the next character
inFile >> ch;
} //end while
} //end function

The count logic is confusingly written and that is masking one bug (where it folds the case):
if('A' <= ch && ch <= 'Z')
{
letterList[static_cast<int>(ch) - 65].count++;
}
else if('a' <= ch && ch <= 'z')
{
letterList[static_cast<int>(ch) - 97].count++; // <--- a bug here
}
This reacts to 'a' by incrementing the count for the first element, which looks like it is intended to be the count for 'A'. This is easily fixed by offsetting lowercase, also rewriting it so it is clearer what is being done:
if ('A' <= ch && ch <= 'Z')
{
letterList[static_cast<int>(ch - 'A')].count++; // count uppercase
}
else if ('a' <= ch && ch <= 'z')
{
letterList[static_cast<int>(ch - 'a') + 26].count++; // count lowercase
}
As for the main bug, initialize() is not called anywhere.
Initialize is being called incorrectly as initialize(&letterList[52]); This attempts to initialize entries 52, 53, ... 103. I am surprised it doesn't segfault.
It should be called as
initialize(letterList);

Your functions are doing just right.
In your driver code you are calling these functions with wrong argumnets
Check these lines they should be like this
initialize(&letterList[0]);
//initalizes the letter A-Z, and a-z */
count(inFile, &letterList[0], totalBig, totalSmall);
While passing letterList array to the functions you should pass the pointer to first element in the array. you should pass &letterList[0] or simply letterList

Related

Pig latin conversion using Cstrings

The program takes in a word given by the user and translates that to pig latin. I've gotten everything to work almost perfectly, but have run into two bugs. The first of which is when translating words that begin with consonants say "count", the output is "ounttcay" instead of "ountcay". The second bug is that when for three letter words like "egg" or "not" the output is "egg_\377ay" or "ottn\377ay". Is there a simple way to remove that duplicate character and get rid of those numbers?
Note - Unfortunately it has to be done using a Cstring
#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std;
int convertToPigLatin(char arr[50]);
bool isVowel(char ch);
int main() {
char userInput[50];
char answer = ' ';
do {
cout << "Enter a word to convert it to pig latin" << endl;
cin.getline(userInput, 50); //get user input
cout << "Your entered word is " << userInput << endl;
convertToPigLatin(userInput); //translate user's input into piglatin
cout << "Would you like to convert another word?" << endl;
cin >> answer;
cin.ignore(); //clear past user input
cin.clear();
} while (answer == 'Y' || answer == 'y');
return 0;
}
bool isVowel (char ch) {
switch (tolower(ch)) { //if the first character of the given input is a vowel
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
return true;
default:
return false;
}
}
int convertToPigLatin(char arr[50]) {
char newArr[50];
// string conjunctions[6] = {"and","but","for","nor","yet","the"}; //list of conjunctions not to be converted
size_t arrLength = strlen(arr); //holds length of input
for (int i = 0; i < arrLength; i++) { //make sure all characters in input are lower case for easier processing
newArr[i] = tolower(arr[i]);
}
char lastChar = newArr[0]; //save the first character in case it needs to be appended
if (atoi(arr) || arr[0] == '\0') { //if the input contains a number or begins with a null character print an error
cout << "Cannot translate inputs that contain numbers" << endl;
return -1;
} else if (arrLength <= 2) { // if the input is 2 or less characters
cout << newArr << endl; //print the input as is
cout << "Boring! Try somthing more than 2 characters long" << endl;
return 0;
} else if ((strstr(newArr, "and") && arrLength == 3) || (arrLength == 3 && strstr(newArr, "but")) || (arrLength == 3 && strstr(newArr, "for")) || (arrLength == 3 && strstr(newArr, "nor")) || (arrLength == 3 && strstr(newArr, "yet")) || (arrLength == 3 && strstr(newArr, "the"))) { //if the input is more than 2 characters long
cout << newArr << endl; //print the input as is
cout << "No conjucntions try again!" << endl;
return 0;
} else { //if the given input is three characters and is not a conjunction, being translation
if (isVowel(arr[0])) { //check if input's first character is a vowel
cout << "Your word in piglatin is "<< strcat(newArr, "ay") << endl; //print that string with 'ay' at the end (i.e. egg'ay')
return 0;
} else { //else if the given input starts with a consonant
for (int r = 1; r < arrLength; r++) {
newArr[r-1] = newArr[r];
newArr[arrLength] = lastChar;
}
cout << "Your word in piglatin is " << strcat(newArr, "ay") << endl;
return 0;
}
}
return 0;
}
You're not terminating newArr, and the last index of the input string is arrLength - 1.
int convertToPigLatin(char arr[50]) {
// Make sure newArr is properly terminated.
char newArr[50] = {0};
// [...]
} else { //else if the given input starts with a consonant
for (int r = 1; r < arrLength; r++) {
newArr[r-1] = newArr[r];
}
// Do this outside the loop.
newArr[arrLength-1] = lastChar;
// No need for strcat here.
cout << "Your word in piglatin is " << newArr << "ay" << endl;
}
}
return 0;
}
You need to add the '\0' at the end of newArr because strlen does not count it so you are not copying it. strcat replaces '\0' witn 'ay\0' but you have no '\0'.
for (int r = 1; r < arrLength; r++) {
newArr[r-1] = newArr[r];
newArr[arrLength] = lastChar;
}
newArr[arrLength+1] = '\0';
cout << "Your word in piglatin is " << strcat(newArr, "ay") << endl;

Issue with processing an Array in C++

I am trying to create an Array which would let the user input up to 80 characters and then when the program halts, for the program to return the amount of times each vowel shows up in the Array. I successfully got it to work last week, but the coding got lost and I had to do it from scratch.
Edit: The problem I am having is that based on the current structure, all the counters still return 0 at the end.
I remember that I used the following coding, but I am having issues with the counters actually working. I think I had the segment for the counters in a loop of its own, but I can't remember it.
I also want the program to halt if the user presses ENTER, but I have no idea how that works.
Any help would be appreciated.
#include <iostream>
#include <iostream>
using namespace std;
int main()
{
int x = 0;
char thisArray[80];
int aCounter = 0, eCounter = 0, iCounter = 0, oCounter = 0, uCounter = 0;
cout << "Please enter up to 80 characters and you will be told" << endl;
cout << "how many times each vowel is in the array." << endl;
do{
cout << "Please enter a character" << endl;
cin >> thisArray;
x++;
} while (x < 80);
for (x = 0; x <= thisArray[x]; x++) {
if (thisArray[x] == 'a')
aCounter = aCounter + 1;
else if (thisArray[x] == 'e')
eCounter = eCounter + 1;
else if (thisArray[x] == 'i')
iCounter = iCounter + 1;
else if (thisArray[x] == 'o')
oCounter = oCounter + 1;
else if (thisArray[x] == 'u')
uCounter = uCounter + 1;
}
cout << "Vowel count:" << endl;
cout << "Total number of A's." << aCounter << endl;
cout << "Total number of E's." << eCounter << endl;
cout << "Total number of I's." << iCounter << endl;
cout << "Total number of O's." << oCounter << endl;
cout << "Total number of U's." << uCounter << endl;
system("pause");
}
The do loop you are using is not correct. It will try to read a string 80 times, and will store only the last string. Each of those strings will contain only non-whitespace characters.
Change the do loop so that you read one character at a time, using unformatted input, and store all the characters in the array, including whitespace characters.
Stop the loop when you reach the limit of the number of characters you can hold or the newline character is encountered.
cout << "Please enter a line of text" << endl;
// Read the characters one by one.
// Don't read more than 79 characters.
// Stop if a newline or EOF is encountered.
int c;
while ( x < 79 && (c = cin.get()) != '\n' && c != EOF )
{
thisArray[x] = c;
++x;
}
// null terminate the string.
thisArray[x] = '\0';
You have a couple issues in you code. First you are not inputting into the array in your do...while loop. You need to use the index operator([]) with the array name for that:
do{
cout << "Please enter a character" << endl;
cin >> thisArray[x];
x++; ^^^ input each character into the correct index.
} while (x < 80);
Secondly your for loop has the wrong condition.
for (x = 0; x <= thisArray[x]; x++)
Should be
for (x = 0; x < 80; x++)
Notice that I changed the <= to < as an array of size 80 has the elements of [0, 79]

Can someone tell me why I am stuck in my validation loop after entering 'y' to continue?

Why am I getting stuck in my validation loop after hitting Y to continue? I have to use cin.get and can not use strings
This program collects input from a user and displays them by using a pointer with an array, I have to validate for negative numbers, letters and newline characters with the appropriate message
#include <iostream>
#include <iomanip>
using namespace std;
void validateUserInput(char *userInputCharArray, int &strLength);
int const ARRAY_SIZE = 100;
int main()
{
char *userInputCharArray = nullptr;
char yes = NULL;
int lengthOfInput;
//creating a dynamic array size 100
userInputCharArray = new char[ARRAY_SIZE];
//loop
do
{
int count = 0;
//user prompt and accept input
cout << "Please enter an integer >= 0 and press <ENTER>: " << endl;
cin.get(userInputCharArray, ARRAY_SIZE);
while(userInputCharArray[count] != ' ' && userInputCharArray[count] != '\0')
count++;
{
if(userInputCharArray[count] == ' ')
{
userInputCharArray[count] = '\0';
}
}
lengthOfInput = count;
validateUserInput(userInputCharArray, lengthOfInput);
cout << "Your number is: " << endl;
for(int i = 0; i < lengthOfInput; i++)
{
cout << userInputCharArray[i] - '0' << " ";
}
cout << endl;
cout << "Press y to continue or any other button to exit: " <<endl;
cin >> yes;
delete [] userInputCharArray;
userInputCharArray = nullptr;
userInputCharArray = new char[ARRAY_SIZE];
}while(yes == 'y' || yes == 'Y');
cout << "Thank you Good-Bye";
cout << endl;
delete [] userInputCharArray;
userInputCharArray = nullptr;
system("pause");
return 0;
}
Im getting stuck in my functions while loop
void validateUserInput(char *userInputCharArray, int &strLength)
{
int counter = 0;
while(*userInputCharArray < '0' || (*userInputCharArray >= 'A' && *userInputCharArray <= 'Z')
|| (*userInputCharArray >= 'a' && *userInputCharArray <= 'z')
|| *userInputCharArray == 0)
{
cout << "Please enter a positive integer and press <ENTER>: " <<endl;
cin.get(userInputCharArray, ARRAY_SIZE);
}
while(userInputCharArray[counter] != ' ' && userInputCharArray[counter] != '\0')
counter++;
if(userInputCharArray[counter] == ' ')
{
userInputCharArray[counter] = '\0';
}
strLength = counter;
}
According to the while loop you have here, you will keep on calling in.get so long as the first character that you read in is a digit or an alphabetic character. So, if you start your input with one of those characters, you will loop forever.
I'd suggest that you get input a line at a time and then parse what you get.
cin.get(*userInputCharArray);
Will extract one character only, therefore the terminator character '\0' will not be part of userInputCharArray.
Change it to read a line at a time and parse the input. If you're still having issues, you can flush your input buffer before each read like so:
cin.ignore(10, "\n");
cin.get(userInputCharArray, ARRAY_SIZE);

When using fstream in C++, how can I filter out control and formatting characters?

I have one of those basic assignments where you need to count the numbers of specific types of characters in an input file. There are 3 files involved, the main program (which I will include below), the hopper.txt input text to be analyzed, and the sample output.txt which demonstrates what the output should look like in the command line.
I believe I have everything set but my final numbers arnt turning out correctly. Specifically, my other and total counters are about 200 over. Now I've done some counting with other programs and am pretty sure that the sample output is correct which is why I suspect that I must be counting the hidden characters (and they must be there because the output isn't just a block of text).
I've tried casting each character to an int in order to see what its ascii value is and go off of that range but my IDE (Xcode) says that "comparison of constant with expression of type 'bool' is always true", and the check doesn't seem to catch anything.
Here are the other two files:
hopper.txt
sample output.txt
/***************************************************************
CSCI 240 Program 4 Summer 2013
Programmer:
Date Due: 7/14/14
Purpose: This program reads in the characters from a text file.
While reading them it takes cultivates relivant data about
the frequency of different ascii characters and shares its
results.
***************************************************************/
#include <iostream>
#include <iomanip>
#include <fstream>
#include <unistd.h>
#define FILENAME "/Users/username/Documents/NIU/240/Assigntment\ 4/hopper.txt"
using namespace std;
bool isVowel(char ch);
bool isConsonant(char ch);
int main()
{
ifstream inFile;
inFile.open (FILENAME, ios::in);
char ch;
int t_total = 0;
int t_vowel = 0;
int t_consonant = 0;
int t_letter = 0;
int t_leftParen = 0;
int t_rightParen = 0;
int t_singleQuote = 0;
int t_doubleQuote = 0;
int t_digit = 0;
int t_other = 0;
//See if we successfully imported the file
if (inFile.fail())
{
cout<< "\nThe file entitled: " << FILENAME << " failed to open.\n";
return 0;
}
do
{
//get next letter and print it out
inFile.get (ch);
cout << ch;
//increment total
t_total++;
//check if the character is a letter and if so if it is a vowel or consonant
if(isalpha(ch)){
t_letter++;
//we have found a letter
if(isVowel(ch)) {
t_vowel++;
//we have found a vowel
}
else if(isConsonant(ch)) {
t_consonant++;
//we have found a consonant;
}
else {
cout << "\nYou shouldnt be here...";
}
}
//check if the character is a digit
else if (isdigit(ch)) {
t_digit++;
//we have found a digit
}
//filter out formating characters
else if (!( 32 <= ((int)ch) <= 255)) {
continue;
}
//covers all other cases of askii characters
else {
switch(ch) {
case '(':
t_leftParen++;
break;
case ')':
t_rightParen++;
break;
case '\'':
t_singleQuote++;
break;
case '\"':
t_doubleQuote++;
break;
default:
t_other++;
break;
}
}
} while (inFile);
//These are really just here for the convience of not changing each value while working on formatting
int width1 = 25;
int width2 = 6;
//print out the totals found in the document
cout << "\n\nSummary\n";
cout << fixed << setw(width1) << "\nTotal characters:" << setw(width2) << right << t_total;
cout << fixed << setw(width1) << "\nVowels:" << setw(width2) << right << t_vowel;
cout << fixed << setw(width1) << "\nConsonants:" << setw(width2) << right << t_consonant;
cout << fixed << setw(width1) << "\nLetters:" << setw(width2) << right << t_letter;
cout << fixed << setw(width1) << "\nDigits:" << setw(width2) << right << t_digit;
cout << fixed << setw(width1) << "\nLeft parentheses:" << setw(width2) << right << t_leftParen;
cout << fixed << setw(width1) << "\nRight parentheses:" << setw(width2) << right << t_rightParen;
cout << fixed << setw(width1) << "\nSingle quotes:" << setw(width2) << right << t_singleQuote;
cout << fixed << setw(width1) << "\nDouble quotes:" << setw(width2) << right << t_doubleQuote;
cout << fixed << setw(width1) << "\nOther:" << setw(width2) << right << t_other;
return 0;
}
/***************************************************************
Function: isVowel
Use: Checks if the inputed character is a vowel.
Arguements: 1. ch: A askii character
Returns: true if it is a vowel, false if it is not
***************************************************************/
bool isVowel(char ch) {
//double check we have a letter
if(isalpha(ch)) {
//reduce to lower case to reduce the number of cases that must be checked
ch = tolower(ch);
if(ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') {
return true;
}
else {
return false;
}
}
return false;
}
/***************************************************************
Function: isConsonant
Use: Checks if the inputed character is a consonant.
Arguements: 1. ch: A askii character
Returns: true if it is a consonant, false if it is not
***************************************************************/
bool isConsonant(char ch) {
//So long as it is a letter, anything that is not a vowel must be a consonant
if(isalpha(ch)) {
return !isVowel(ch);
}
return false;
}
You can use std::isspace to test if a character is one of :
space (0x20, ' ')
form feed (0x0c, '\f')
line feed (0x0a, '\n')
carriage return (0x0d, '\r')
horizontal tab (0x09, '\t')
vertical tab (0x0b, '\v')
And ignore those by adding a test in your reading loop :
else if (std::isspace(ch)) {
continue; // Do not update counters
}

probably wrong if statement, not moving to next row after input

When I run my program, I have to type how many rows do I want in my output. I have a limit from 1 to 100 rows. Each row is a task with a name of the task followed by increasing number, example: Task1:, Task2, .... When I type something into input, it must convert input string /see the code below - except the code in main();/.
My problem is that when I type first input, it should go to next task/next row/ but it doesnt. I type for example 10 strings but they dont go each to next task but they stay in one task..hope you understand now.
#include<iostream>
#include<string>
#include <ctype.h>
using namespace std;
void Convert(string input){
string output = "";
string flag = "";
bool underscore = false;
bool uppercase = false;
if ( islower(input[0]) == false){
cout << "Error!" <<endl;
return;
}
for (int i=0; i < input.size(); i++){
if ( (isalpha( input[i] ) || (input[i]) == '_') == false){
cout << "Error!" <<endl;
return;
}
if (islower(input[i])){
if (underscore){
underscore = false;
output += toupper(input[i]);
}
else
output += input[i];
}
else if (isupper(input[i])){
if (flag == "C" || uppercase){
cout << "Error!"<<endl;
return;
}
flag = "Java";
output += '_';
output += tolower(input[i]);
}
else if (input[i] == '_'){
if (flag == "Java" || underscore){
cout << "Error!" <<endl;
return;
}
flag = "C";
underscore = true;
}
}
cout << output <<endl;
}
int main(){
const int max = 100;
string input;
int pocet_r;
cout << "Zadaj pocet uloh:" << endl;
cin >> pocet_r;
if(pocet_r >= 1 && pocet_r <=100)
{
for (int i = 0; i <pocet_r; i++)
{
cout << "Uloha " << i+1 << ":" << endl;
while (cin >> input)
Convert (input);
while(input.size() > max)
cout << "slovo musi mat minimalne 1 a maximalne 100 znakov" << endl;
while(input.size() > max)
cin >> input;
while (cin >> input)
Convert(input);
}
}else{
cout << "Minimalne 1 a maximalne 100 uloh" << endl;
}
system("pause");
}
Your first if in Convert will always fail on a non-underscore and return. I don't think that's what's intended. Agree with other answer on the while cin loop. The next two whiles should be if's apparently. Step thru this code with a debugger and watch it line by line and see where it fails. You've got multiple issues here, and I'm not entirely sure what the intent is.
Edit - I didn't parse the extra parenthesis correctly. The first if in convert is actually okay.